diff --git a/.gitignore b/.gitignore index 2dc13af9..9752fac9 100644 --- a/.gitignore +++ b/.gitignore
@@ -163,6 +163,8 @@ /chrome/web_ui_mojo_bindings.xml /chromecast/internal /chromeos/assistant/internal +/chromeos/profiles/chromeos.orderfile.txt +/chromeos/profiles/orderfile.local.txt /cipd_cache/ /clank /cloud_print/cloud_print_version_resources.xml
diff --git a/.gn b/.gn index a9f9422..70856f6 100644 --- a/.gn +++ b/.gn
@@ -81,7 +81,7 @@ #"//chrome/*", # Many errors: https://crbug.com/949535 - #"//chrome/android/*", # 13 errors + "//chrome/android/*", "//chrome/app/*", "//chrome/app_shim/*",
diff --git a/BUILD.gn b/BUILD.gn index 7a5ad82e..19fd588 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -148,6 +148,7 @@ "//third_party/pdfium/samples:pdfium_test", "//third_party/webrtc/rtc_tools:frame_analyzer", "//tools/perf/clear_system_cache", + "//tools/polymer:polymer_tools_python_unittests", "//ui/accessibility:accessibility_unittests", "//ui/accessibility/extensions", ] @@ -313,7 +314,6 @@ "//chrome/test:android_browsertests", "//chrome/test/vr/perf:motopho_latency_test", "//components/invalidation/impl:components_invalidation_impl_junit_tests", - "//components/journey:journey_info_fetcher", "//components/policy/android:components_policy_junit_tests", "//components/signin/core/browser/android:components_signin_junit_tests", "//content/public/android:content_junit_tests",
diff --git a/DEPS b/DEPS index c19eff0a..23203113 100644 --- a/DEPS +++ b/DEPS
@@ -47,7 +47,8 @@ # By default, we should check out everything needed to run on the main # chromium waterfalls. This var can be also be set to "small", in order # to skip things are not strictly needed to build chromium for development - # purposes. + # purposes, by adding the following line to src.git's .gclient entry: + # "custom_vars": { "checkout_configuration": "small" }, 'checkout_configuration': 'default', # By default, don't check out android. Will be overridden by gclient @@ -144,11 +145,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': 'd6cb7aecf13008c148d9043ea5364dc0784976bb', + 'skia_revision': '59192a0d66a746e472802fed50c139b880ef11c4', # 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': '6c48f74fdafe303ea4013f443fd4c2a7ab824a85', + 'v8_revision': '4035531228d69a8e3ec475ef75b51db302e70473', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -156,7 +157,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '557e3853da56b9ff72be8ad8ce3643f5cdeb1d4d', + 'angle_revision': '08b97da894b278c10e70b6888ac65e3972a13b31', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -164,7 +165,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '0208b0ca4d258aa2ac8a938725d1afaa591c1a92', + 'pdfium_revision': '6e3a40600f246bd8cff2367e3805ce53466cb349', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -207,7 +208,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': '3dd1372096afac06bb2c8c83fe2e3012429900d2', + 'catapult_revision': 'c5817614666e57a37bebfb26e1cb85884321533e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -279,11 +280,11 @@ # 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': '271817784100310e8e694a537e2c036deaac6f46', + 'dawn_revision': '9d2ccaf65c2a370c5f203e119e194a44fa039481', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'quiche_revision': '89b9af539b5877093cdf7ba22cbff9354b6bf723', + 'quiche_revision': '753002daef6045500f08066b132da7fd71ab4ca9', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -483,7 +484,7 @@ }, 'src/ios/third_party/material_components_ios/src': { - 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'd57b1482fc27dae45805189a4639d2951406e284', + 'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'e5a70e02cd24d86f9c3e1a9298c4ddca4555bd40', 'condition': 'checkout_ios', }, @@ -808,7 +809,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '3fa46deb9ba5a499fb8cf91ce1f207c093348e2e', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'bf99f644ae328a8c0e265c2a4b510f27ad41bfb9', 'condition': 'checkout_linux', }, @@ -823,7 +824,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': { - 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '80a8441a9d67a14025a9541ff1e6a0f728376040', + 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '206270625a4ac391aada9ac5f0c32a4e66e9f59c', 'condition': 'checkout_linux', }, @@ -833,7 +834,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '34cc05018d70cb48e482c6c82028725d4d3d4225', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '365720e237c2afc529446d1af0a253ab3edad3b4', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -868,7 +869,7 @@ }, 'src/third_party/ffmpeg': - Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'fff11548e7b6b95ba0fcb179eebc72ff1244b11d', + Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'e0e3133c40fbca0032a2d9400da736e4b933882f', 'src/third_party/flac': Var('chromium_git') + '/chromium/deps/flac.git' + '@' + 'af862024c8c8fa0ae07ced05e89013d881b00596', @@ -902,7 +903,7 @@ }, 'src/third_party/glslang/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '302fe97e7b02e37856961ea74f76759098b99188', + Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '42f813401bdfa640e4b87d8991e63f97fe5d5c43', 'src/third_party/google_toolbox_for_mac/src': { 'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), @@ -1095,7 +1096,7 @@ }, 'src/third_party/libvpx/source/libvpx': - Var('chromium_git') + '/webm/libvpx.git' + '@' + 'bb407a27b2e32f89f0e9eeee2bcd0aa9d5cfea3f', + Var('chromium_git') + '/webm/libvpx.git' + '@' + '18d309c12734d2f06d54ad1716e512153a13ab9d', 'src/third_party/libwebm/source': Var('chromium_git') + '/webm/libwebm.git' + '@' + '51ca718c3adf0ddedacd7df25fe45f67dc5a9ce1', @@ -1178,7 +1179,7 @@ Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '6f26bce0b1c4e8ce0e13332f7c0083788def5fdf', 'src/third_party/openscreen/src': - Var('chromium_git') + '/openscreen' + '@' + 'eb5dbc61ce239d7b7bba9d9400553906acadcae4', + Var('chromium_git') + '/openscreen' + '@' + 'd5b3c34bb4b3a1dd65cb13be818596bc81a7855a', 'src/third_party/openxr/src': { 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'c52d3b40dd802353c1f2ceec139922b374c1373a', @@ -1206,7 +1207,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b088b60121ed0b061ff8a18f9486a1be1252656f', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '091864c00bffb363a0202fd5b7b1fc30ed04ca17', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1374,7 +1375,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '672a48d0d2b96ad6f80558247f34e70a975d1a2b', + Var('webrtc_git') + '/src.git' + '@' + '2bac7da1349c75e5cf89612ab9619a1920d5d974', 'src/third_party/xdg-utils': { 'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d', @@ -1415,7 +1416,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b48880d5ef41a2231530cddb6f70467bd5b9c7c8', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6129e06e7f87b0c16aca97e604344f3849c1bcd9', 'condition': 'checkout_src_internal', }, @@ -2762,7 +2763,13 @@ 'name': 'Fetch Android AFDO profile', 'pattern': '.', 'condition': 'checkout_android or checkout_linux', - 'action': ['vpython', 'src/chrome/android/profiles/update_afdo_profile.py'], + 'action': [ 'vpython', + 'src/tools/download_cros_provided_profile.py', + '--newest_state=src/chrome/android/profiles/newest.txt', + '--local_state=src/chrome/android/profiles/local.txt', + '--output_name=src/chrome/android/profiles/afdo.prof', + '--gs_url_base=chromeos-prebuilt/afdo-job/llvm', + ], }, { 'name': 'gvr_static_shim_android_arm_1', @@ -2899,6 +2906,18 @@ ], }, { + 'name': 'Fetch ChromeOS-specific orderfile for Chrome', + 'pattern': '.', + 'condition': 'checkout_chromeos or checkout_simplechrome', + 'action': [ 'vpython', + 'src/tools/download_cros_provided_profile.py', + '--newest_state=src/chromeos/profiles/orderfile.newest.txt', + '--local_state=src/chromeos/profiles/orderfile.local.txt', + '--output_name=src/chromeos/profiles/chromeos.orderfile.txt', + '--gs_url_base=chromeos-prebuilt/afdo-job/orderfiles/vetted', + ], + }, + { # Pull doclava binaries if building for Android. 'name': 'doclava', 'pattern': '.',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index f28aa1a..3ecef02 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -693,6 +693,10 @@ "renderer/print_render_frame_observer.h", ] + public_deps = [ + "//base", + ] + deps = [ ":generate_aw_resources", ":generate_aw_strings", @@ -701,7 +705,6 @@ "//android_webview/browser/gfx:gfx", "//android_webview/common", "//android_webview/common:common_mojom", - "//base", "//base/third_party/dynamic_annotations:dynamic_annotations", "//components/about_ui", "//components/autofill/android:provider", @@ -887,6 +890,7 @@ "java/src/org/chromium/android_webview/permission/AwPermissionRequest.java", "java/src/org/chromium/android_webview/policy/AwPolicyProvider.java", "java/src/org/chromium/android_webview/ui/util/UploadedCrashesInfoLoader.java", + "java/src/org/chromium/android_webview/ui/util/WebViewCrashLogParser.java", ] deps = [ ":android_webview_commandline_java",
diff --git a/android_webview/browser/aw_feature_list.cc b/android_webview/browser/aw_feature_list.cc index 846a497..50acf01 100644 --- a/android_webview/browser/aw_feature_list.cc +++ b/android_webview/browser/aw_feature_list.cc
@@ -57,10 +57,6 @@ const base::Feature kWebViewPageStartedOnCommit{ "WebViewPageStartedOnCommit", base::FEATURE_ENABLED_BY_DEFAULT}; -// Whether the application package name is logged in UMA. -const base::Feature kWebViewUmaLogAppPackageName{ - "WebViewUmaLogAppPackageName", base::FEATURE_ENABLED_BY_DEFAULT}; - // Enable raster in wide color gamut for apps that use webview in a wide color // gamut activity. const base::Feature kWebViewWideColorGamutSupport{
diff --git a/android_webview/browser/aw_feature_list.h b/android_webview/browser/aw_feature_list.h index 42cf080..f98fc23 100644 --- a/android_webview/browser/aw_feature_list.h +++ b/android_webview/browser/aw_feature_list.h
@@ -17,7 +17,6 @@ extern const base::Feature kWebViewBrotliSupport; extern const base::Feature kWebViewConnectionlessSafeBrowsing; extern const base::Feature kWebViewPageStartedOnCommit; -extern const base::Feature kWebViewUmaLogAppPackageName; extern const base::Feature kWebViewWideColorGamutSupport; } // namespace features
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc index 5f6739c1..7b27757a 100644 --- a/android_webview/browser/aw_metrics_service_client.cc +++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -218,9 +218,6 @@ } std::string AwMetricsServiceClient::GetAppPackageName() { - if (!base::FeatureList::IsEnabled(features::kWebViewUmaLogAppPackageName)) - return std::string(); - JNIEnv* env = base::android::AttachCurrentThread(); base::android::ScopedJavaLocalRef<jstring> j_app_name = Java_AwMetricsServiceClient_getAppPackageName(env);
diff --git a/android_webview/browser/aw_permission_manager.cc b/android_webview/browser/aw_permission_manager.cc index 3fd79eb..f1979fdc 100644 --- a/android_webview/browser/aw_permission_manager.cc +++ b/android_webview/browser/aw_permission_manager.cc
@@ -13,6 +13,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/logging.h" +#include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/permission_controller.h" #include "content/public/browser/permission_type.h" #include "content/public/browser/render_frame_host.h" @@ -179,6 +180,11 @@ } DCHECK(!IsCompleted()); results[result->second] = status; + if (type == PermissionType::MIDI_SYSEX && + status == PermissionStatus::GRANTED) { + content::ChildProcessSecurityPolicy::GetInstance() + ->GrantSendMidiSysExMessage(render_process_id); + } resolved_permissions_.insert(type); }
diff --git a/android_webview/browser/gfx/surfaces_instance.cc b/android_webview/browser/gfx/surfaces_instance.cc index 395dbcb..434c112 100644 --- a/android_webview/browser/gfx/surfaces_instance.cc +++ b/android_webview/browser/gfx/surfaces_instance.cc
@@ -374,9 +374,12 @@ } display_->Resize(viewport); display_->DrawAndSwap(); - // TODO(dlibby): Consider sending real swap timings here for webview (or - // prove why it is not needed). - display_->DidReceiveSwapBuffersAck(gfx::SwapTimings()); + // SkiaRenderer generates DidReceiveSwapBuffersAck calls. + if (!features::IsUsingSkiaRenderer()) { + // TODO(dlibby): Consider sending real swap timings here for webview (or + // prove why it is not needed). + display_->DidReceiveSwapBuffersAck(gfx::SwapTimings()); + } gl_surface_->MaybeDidPresent(gfx::PresentationFeedback( base::TimeTicks::Now(), base::TimeDelta(), 0 /* flags */)); }
diff --git a/android_webview/browser/network_service/android_stream_reader_url_loader.h b/android_webview/browser/network_service/android_stream_reader_url_loader.h index ba5bf2a3..285a921b 100644 --- a/android_webview/browser/network_service/android_stream_reader_url_loader.h +++ b/android_webview/browser/network_service/android_stream_reader_url_loader.h
@@ -17,9 +17,15 @@ class InputStream; class InputStreamReaderWrapper; -// Custom URLLoader implementation for loading network responses from stream. -// Current implementation is in particular for supporting shouldInterceptRequest -// callback in webview. +// Custom URLLoader implementation for loading responses from Android +// InputStreams. Although this works generally for implementers of the +// ResponseDelegate interface, this specifically aims to support: +// +// - shouldInterceptRequest callback +// - content:// URLs, which load content from Android ContentProviders (which +// could be in-app or come from other apps) +// - file:///android_asset/ & file:///android_res/ URLs, which load in-app +// content from the app's asset/ and res/ folders class AndroidStreamReaderURLLoader : public network::mojom::URLLoader { public: // Delegate abstraction for obtaining input streams.
diff --git a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc index 0efa517..1208e87 100644 --- a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc +++ b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
@@ -150,6 +150,7 @@ DISALLOW_COPY_AND_ASSIGN(InterceptedRequest); }; +// A ResponseDelegate for responses returned by shouldInterceptRequest. class InterceptResponseDelegate : public AndroidStreamReaderURLLoader::ResponseDelegate { public: @@ -203,6 +204,9 @@ base::WeakPtr<InterceptedRequest> request_; }; +// A ResponseDelegate based on top of AndroidProtocolHandler for special +// protocols, such as content://, file:///android_asset, and file:///android_res +// URLs. class ProtocolResponseDelegate : public AndroidStreamReaderURLLoader::ResponseDelegate { public:
diff --git a/android_webview/java/src/org/chromium/android_webview/ui/util/WebViewCrashLogParser.java b/android_webview/java/src/org/chromium/android_webview/ui/util/WebViewCrashLogParser.java new file mode 100644 index 0000000..3bac1d8e --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/ui/util/WebViewCrashLogParser.java
@@ -0,0 +1,67 @@ +// 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. +package org.chromium.android_webview.ui.util; + +import org.json.JSONException; + +import org.chromium.base.Log; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Parses WebView crash JSON log files which contain crash info keys extracted from crash minidump. + */ +public class WebViewCrashLogParser extends CrashInfoLoader { + private static final String TAG = "WebViewCrashUI"; + + private File mLogDir; + + /** + * @param logDir the directory where WebView store crash logs. + */ + public WebViewCrashLogParser(File logDir) { + mLogDir = logDir; + } + + /** + * Load crash info from WebView crash logs under WebView crash log directory. + * + * @return list of crashes info + */ + @Override + public List<CrashInfo> loadCrashesInfo() { + List<CrashInfo> infoList = new ArrayList<>(); + + if (!mLogDir.exists() || !mLogDir.isDirectory()) return infoList; + + File[] logFiles = mLogDir.listFiles(); + for (File logFile : logFiles) { + // Ignore non-json files. + if (!logFile.isFile() || !logFile.getName().endsWith(".json")) continue; + try { + CrashInfo crashInfo = CrashInfo.readFromJsonString(readEntireFile(logFile)); + // TODO(987806) remove the null check. + if (crashInfo.localId != null) infoList.add(crashInfo); + } catch (JSONException e) { + Log.e(TAG, "Error while reading JSON", e); + } catch (IOException e) { + Log.e(TAG, "Error while reading log file", e); + } + } + + return infoList; + } + + private static String readEntireFile(File file) throws IOException { + try (FileInputStream fileInputStream = new FileInputStream(file)) { + byte[] data = new byte[(int) file.length()]; + fileInputStream.read(data); + return new String(data); + } + } +}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashLogParserTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashLogParserTest.java new file mode 100644 index 0000000..08fc773 --- /dev/null +++ b/android_webview/javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashLogParserTest.java
@@ -0,0 +1,86 @@ +// 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. + +package org.chromium.android_webview.test.ui.util; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.empty; + +import android.support.test.filters.MediumTest; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; + +import org.chromium.android_webview.test.AwJUnit4ClassRunner; +import org.chromium.android_webview.ui.util.CrashInfoLoader.CrashInfo; +import org.chromium.android_webview.ui.util.WebViewCrashLogParser; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Unit tests for WebViewCrashLogParser. + */ +@RunWith(AwJUnit4ClassRunner.class) +public class WebViewCrashLogParserTest { + private static final String TEST_LOG_ENTRY = + "{\"crash-local-id\":\"123456abc\",\"crash-capture-time\":1234567890," + + "\"app-package-name\":\"test.package\",\"variations\":[\"123456\",\"7890\"]}"; + + @Rule + public TemporaryFolder mTestLogDir = new TemporaryFolder(); + + // Write the given string to a new file in the temp test folder. + private void writeLogFile(String fileName, String content) throws IOException { + File logFile = mTestLogDir.newFile(fileName); + FileWriter writer = new FileWriter(logFile); + writer.write(content); + writer.close(); + } + + @Test + @MediumTest + public void testParseMultipleFiles() throws Exception { + final String[] expectedLocalIds = new String[] {"crash1", "crash2", "crash3", "crash4"}; + for (String localId : expectedLocalIds) { + writeLogFile("crash_file_" + localId + ".json", + "{\"crash-local-id\":\"" + localId + + "\",\"app-package-name\":\"test.package\"}"); + } + + List<CrashInfo> crashInfoList = + new WebViewCrashLogParser(mTestLogDir.getRoot()).loadCrashesInfo(); + List<String> actualLocalIds = new ArrayList<>(); + for (CrashInfo crashInfo : crashInfoList) actualLocalIds.add(crashInfo.localId); + // Only asserting local Ids to make sure it's loaded correctly. + Assert.assertThat(actualLocalIds, containsInAnyOrder(expectedLocalIds)); + } + + @Test + @MediumTest + public void testParseInvalidFiles() throws Exception { + writeLogFile("crash_file_json.log", TEST_LOG_ENTRY); + writeLogFile("crash_file_json", TEST_LOG_ENTRY); + writeLogFile("crash_log", TEST_LOG_ENTRY); + writeLogFile("crash_log.txt", TEST_LOG_ENTRY); + writeLogFile("crash_log.json", "{\"invalid_json\":\"value\""); + List<CrashInfo> crashInfoList = + new WebViewCrashLogParser(mTestLogDir.getRoot()).loadCrashesInfo(); + Assert.assertThat(crashInfoList, empty()); + } + + @Test + @MediumTest + public void testParseNonExistDir() throws Exception { + List<CrashInfo> crashInfoList = + new WebViewCrashLogParser(new File("non_exsiting_dir")).loadCrashesInfo(); + Assert.assertThat(crashInfoList, empty()); + } +}
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc index 1dbb1ab..9eadcdd 100644 --- a/android_webview/lib/aw_main_delegate.cc +++ b/android_webview/lib/aw_main_delegate.cc
@@ -171,16 +171,16 @@ autofill::features::kAutofillSkipComparingInferredLabels); if (cl->HasSwitch(switches::kWebViewLogJsConsoleMessages)) { - features.EnableIfNotSet(features::kLogJsConsoleMessages); + features.EnableIfNotSet(::features::kLogJsConsoleMessages); } - features.DisableIfNotSet(features::kWebPayments); + features.DisableIfNotSet(::features::kWebPayments); // WebView does not and should not support WebAuthN. - features.DisableIfNotSet(features::kWebAuth); + features.DisableIfNotSet(::features::kWebAuth); // WebView isn't compatible with OOP-D. - features.DisableIfNotSet(features::kVizDisplayCompositor); + features.DisableIfNotSet(::features::kVizDisplayCompositor); // WebView does not support AndroidOverlay yet for video overlays. features.DisableIfNotSet(media::kUseAndroidOverlay); @@ -196,13 +196,13 @@ features.DisableIfNotSet( autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout); - features.DisableIfNotSet(features::kBackgroundFetch); + features.DisableIfNotSet(::features::kBackgroundFetch); - features.DisableIfNotSet(features::kAndroidSurfaceControl); + features.DisableIfNotSet(::features::kAndroidSurfaceControl); // TODO(https://crbug.com/963653): SmsReceiver is not yet supported on // WebView. - features.DisableIfNotSet(features::kSmsReceiver); + features.DisableIfNotSet(::features::kSmsReceiver); } android_webview::RegisterPathProvider();
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index ce5f236..f2f31b73 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -281,6 +281,7 @@ "../javatests/src/org/chromium/android_webview/test/services/VariationsSeedServerTest.java", "../javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java", "../javatests/src/org/chromium/android_webview/test/ui/util/UploadedCrashesInfoLoaderTest.java", + "../javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashLogParserTest.java", "../javatests/src/org/chromium/android_webview/test/util/AwQuotaManagerBridgeTestUtil.java", "../javatests/src/org/chromium/android_webview/test/util/AwTestTouchUtils.java", "../javatests/src/org/chromium/android_webview/test/util/CommonResources.java",
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 764da39..ee1d369c 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1935,6 +1935,7 @@ "//base", "//base/test:test_support", "//chromeos:test_support", + "//chromeos/strings:strings_grit", # TODO(https://crbug.com/644336): Make CrasAudioHandler Chrome or Ash only. "//chromeos/audio",
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc index 9eb834c..c0adf96 100644 --- a/ash/accessibility/accessibility_controller_impl.cc +++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -641,6 +641,12 @@ client_->TriggerAccessibilityAlert(alert); } +void AccessibilityControllerImpl::TriggerAccessibilityAlertWithMessage( + const std::string& message) { + if (client_) + client_->TriggerAccessibilityAlertWithMessage(message); +} + void AccessibilityControllerImpl::PlayEarcon(int32_t sound_key) { if (client_) client_->PlayEarcon(sound_key);
diff --git a/ash/accessibility/accessibility_controller_impl.h b/ash/accessibility/accessibility_controller_impl.h index 3a065c9a..6c237d1 100644 --- a/ash/accessibility/accessibility_controller_impl.h +++ b/ash/accessibility/accessibility_controller_impl.h
@@ -135,6 +135,9 @@ // Triggers an accessibility alert to give the user feedback. void TriggerAccessibilityAlert(AccessibilityAlert alert); + // Triggers an accessibility alert with the given |message|. + void TriggerAccessibilityAlertWithMessage(const std::string& message); + // Plays an earcon. Earcons are brief and distinctive sounds that indicate // that their mapped event has occurred. The |sound_key| enums can be found in // chromeos/audio/chromeos_sounds.h.
diff --git a/ash/accessibility/test_accessibility_controller_client.cc b/ash/accessibility/test_accessibility_controller_client.cc index 0c08653a..cf5fc02a 100644 --- a/ash/accessibility/test_accessibility_controller_client.cc +++ b/ash/accessibility/test_accessibility_controller_client.cc
@@ -24,6 +24,9 @@ last_a11y_alert_ = alert; } +void TestAccessibilityControllerClient::TriggerAccessibilityAlertWithMessage( + const std::string& message) {} + void TestAccessibilityControllerClient::PlayEarcon(int32_t sound_key) { sound_key_ = sound_key; }
diff --git a/ash/accessibility/test_accessibility_controller_client.h b/ash/accessibility/test_accessibility_controller_client.h index 42868d8..e1ff73f 100644 --- a/ash/accessibility/test_accessibility_controller_client.h +++ b/ash/accessibility/test_accessibility_controller_client.h
@@ -23,8 +23,10 @@ static constexpr base::TimeDelta kShutdownSoundDuration = base::TimeDelta::FromMilliseconds(1000); - // mojom::AccessibilityControllerClient: + // AccessibilityControllerClient: void TriggerAccessibilityAlert(AccessibilityAlert alert) override; + void TriggerAccessibilityAlertWithMessage( + const std::string& message) override; void PlayEarcon(int32_t sound_key) override; base::TimeDelta PlayShutdownSound() override; void HandleAccessibilityGesture(ax::mojom::Gesture gesture) override;
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 84253700..061dd7e86 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -1990,6 +1990,23 @@ <message name="IDS_ASH_LOCK_SCREEN_MEDIA_CONTROLS_ACCESSIBLE_NAME" desc="The accessible name for the lock screen media controls view."> Media Controls </message> + <message name="IDS_ASH_LOCK_SCREEN_MEDIA_CONTROLS_CLOSE" desc="The button to dismiss the media controls and pause playback."> + Close + </message> + + <!-- Virtual desks --> + <message name="IDS_ASH_VIRTUAL_DESKS_ALERT_NEW_DESK_CREATED" desc="A new desk is created in virtual desks."> + Desk <ph name="DESK_TITILE">$1<ex>1</ex></ph> created + </message> + <message name="IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_REMOVED" desc="A desk is removed in virtual desks."> + Desk <ph name="REMOVED_DESK">$1</ph> removed and merged with Desk <ph name="RECEIVE_DESK">$2</ph> + </message> + <message name="IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_ACTIVATED" desc="A desk in virtual desks is activated."> + Desk <ph name="DESK_TITILE">$1<ex>1</ex></ph> activated + </message> + <message name="IDS_ASH_VIRTUAL_DESKS_ALERT_WINDOW_MOVED_FROM_ACTIVE_DESK" desc="A window in active desk got be moved to another virtual desk."> + Window <ph name="WINDOW_TITLE">$1<ex>Files</ex></ph> moved from Desk <ph name="ACTIVE_DESK">$2</ph> to Desk <ph name="TARGET_DESK">$3</ph> + </message> </messages> </release> </grit>
diff --git a/ash/ash_strings_grd/IDS_ASH_LOCK_SCREEN_MEDIA_CONTROLS_CLOSE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_LOCK_SCREEN_MEDIA_CONTROLS_CLOSE.png.sha1 new file mode 100644 index 0000000..894e887 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_LOCK_SCREEN_MEDIA_CONTROLS_CLOSE.png.sha1
@@ -0,0 +1 @@ +5b713ae9c0b4aeeeffdd44a78f1bf1c0e7dfaa8a \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_ACTIVATED.png.sha1 b/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_ACTIVATED.png.sha1 new file mode 100644 index 0000000..1e88e90 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_ACTIVATED.png.sha1
@@ -0,0 +1 @@ +8f947c92a5b23810ff5cd966d12aed537a18aed2 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_REMOVED.png.sha1 b/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_REMOVED.png.sha1 new file mode 100644 index 0000000..dc28629 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_REMOVED.png.sha1
@@ -0,0 +1 @@ +d60dbf64ba69bf06c2e14938aca74aa7d1de9f59 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_NEW_DESK_CREATED.png.sha1 b/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_NEW_DESK_CREATED.png.sha1 new file mode 100644 index 0000000..f87907f --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_NEW_DESK_CREATED.png.sha1
@@ -0,0 +1 @@ +45b46f0e5040d9cf871a398d350e59daf2cc8bd2 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_WINDOW_MOVED_FROM_ACTIVE_DESK.png.sha1 b/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_WINDOW_MOVED_FROM_ACTIVE_DESK.png.sha1 new file mode 100644 index 0000000..f69f638 --- /dev/null +++ b/ash/ash_strings_grd/IDS_ASH_VIRTUAL_DESKS_ALERT_WINDOW_MOVED_FROM_ACTIVE_DESK.png.sha1
@@ -0,0 +1 @@ +84e439c808c3505a80cb16d9c06aecb49074992a \ No newline at end of file
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc index d35e576..246f5a78 100644 --- a/ash/login/ui/lock_contents_view.cc +++ b/ash/login/ui/lock_contents_view.cc
@@ -1210,10 +1210,10 @@ } bool LockContentsView::AreMediaControlsEnabled() const { - return Shell::Get()->media_controller()->AreLockScreenMediaKeysEnabled() && - base::FeatureList::IsEnabled(features::kLockScreenMediaControls) && - screen_type_ == LockScreen::ScreenType::kLock && - !expanded_view_->GetVisible(); + return screen_type_ == LockScreen::ScreenType::kLock && + !expanded_view_->GetVisible() && + Shell::Get()->media_controller()->AreLockScreenMediaKeysEnabled() && + base::FeatureList::IsEnabled(features::kLockScreenMediaControls); } void LockContentsView::HideMediaControlsLayout() {
diff --git a/ash/login/ui/lock_screen_media_controls_view.cc b/ash/login/ui/lock_screen_media_controls_view.cc index 4692774..61704d87 100644 --- a/ash/login/ui/lock_screen_media_controls_view.cc +++ b/ash/login/ui/lock_screen_media_controls_view.cc
@@ -11,6 +11,7 @@ #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "components/media_message_center/media_notification_util.h" +#include "components/vector_icons/vector_icons.h" #include "services/media_session/public/cpp/util.h" #include "services/media_session/public/mojom/constants.mojom.h" #include "services/media_session/public/mojom/media_session.mojom.h" @@ -24,6 +25,7 @@ #include "ui/views/controls/button/image_button_factory.h" #include "ui/views/controls/image_view.h" #include "ui/views/layout/box_layout.h" +#include "ui/views/layout/grid_layout.h" namespace ash { @@ -41,22 +43,25 @@ constexpr int kMediaControlsTotalWidthDp = 320; constexpr int kMediaControlsTotalHeightDp = 400; constexpr int kMediaControlsCornerRadius = 8; -constexpr gfx::Insets kMediaControlsInsets = gfx::Insets(25, 25, 30, 25); -constexpr int kMediaControlsChildSpacing = 30; constexpr int kMinimumIconSize = 16; constexpr int kDesiredIconSize = 20; constexpr int kIconSize = 20; +constexpr gfx::Insets kArtworkInsets = gfx::Insets(0, 25, 0, 25); constexpr int kMinimumArtworkSize = 200; constexpr int kDesiredArtworkSize = 300; constexpr int kArtworkViewWidth = 270; constexpr int kArtworkViewHeight = 200; constexpr gfx::Size kMediaButtonSize = gfx::Size(45, 45); +constexpr int kMediaButtonRowSeparator = 10; +constexpr gfx::Insets kButtonRowInsets = gfx::Insets(25, 25, 30, 25); constexpr int kPlayPauseIconSize = 32; constexpr int kChangeTrackIconSize = 16; constexpr int kSeekingIconsSize = 28; constexpr gfx::Size kMediaControlsButtonRowSize = gfx::Size(270, kMediaButtonSize.height()); -constexpr int kMediaButtonRowSeparator = 10; +constexpr int kCloseButtonOffset = 290; +constexpr gfx::Size kCloseButtonSize = gfx::Size(24, 24); +constexpr int kCloseButtonIconSize = 20; // How long to wait (in milliseconds) for a new media session to begin. constexpr base::TimeDelta kNextMediaDelay = @@ -129,6 +134,11 @@ DCHECK(callbacks.hide_media_controls); DCHECK(callbacks.show_media_controls); + set_notify_enter_exit_on_child(true); + + SetLayoutManager(std::make_unique<views::BoxLayout>( + views::BoxLayout::Orientation::kVertical)); + SetBackground(views::CreateRoundedRectBackground(kMediaControlsBackground, kMediaControlsCornerRadius)); middle_spacing_ = std::make_unique<NonAccessibleView>(); @@ -137,22 +147,45 @@ // Media controls have not been dismissed initially. Shell::Get()->media_controller()->SetMediaControlsDismissed(false); - SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kVertical, kMediaControlsInsets, - kMediaControlsChildSpacing)); + // |close_button_row| contains the close button to dismiss the controls. + auto close_button_row = std::make_unique<NonAccessibleView>(); + views::GridLayout* close_button_layout = + close_button_row->SetLayoutManager(std::make_unique<views::GridLayout>()); + views::ColumnSet* columns = close_button_layout->AddColumnSet(0); + columns->AddPaddingColumn(0, kCloseButtonOffset); + columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0, + views::GridLayout::USE_PREF, 0, 0); + close_button_layout->StartRowWithPadding( + 0, 0, 0, 5 /* padding between close button and top of view */); + + auto close_button = CreateVectorImageButton(this); + SetImageFromVectorIcon(close_button.get(), vector_icons::kCloseRoundedIcon, + kCloseButtonIconSize, gfx::kGoogleGrey700); + close_button->SetPreferredSize(kCloseButtonSize); + close_button->SetFocusBehavior(View::FocusBehavior::ALWAYS); + base::string16 close_button_label( + l10n_util::GetStringUTF16(IDS_ASH_LOCK_SCREEN_MEDIA_CONTROLS_CLOSE)); + close_button->SetAccessibleName(close_button_label); + close_button_ = close_button_layout->AddView(std::move(close_button)); + close_button_->SetVisible(false); + AddChildView(std::move(close_button_row)); + + // |header_row_| contains the app icon and source title of the current media + // session. header_row_ = AddChildView(std::make_unique<MediaControlsHeaderView>()); auto session_artwork = std::make_unique<views::ImageView>(); session_artwork->SetPreferredSize( gfx::Size(kArtworkViewWidth, kArtworkViewHeight)); + session_artwork->SetBorder(views::CreateEmptyBorder(kArtworkInsets)); session_artwork_ = AddChildView(std::move(session_artwork)); // |button_row_| contains the buttons for controlling playback. auto button_row = std::make_unique<NonAccessibleView>(); auto* button_row_layout = button_row->SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), + views::BoxLayout::Orientation::kHorizontal, kButtonRowInsets, kMediaButtonRowSeparator)); button_row_layout->set_cross_axis_alignment( views::BoxLayout::CrossAxisAlignment::kCenter); @@ -259,6 +292,14 @@ node_data->SetName(accessible_name_); } +void LockScreenMediaControlsView::OnMouseEntered(const ui::MouseEvent& event) { + close_button_->SetVisible(true); +} + +void LockScreenMediaControlsView::OnMouseExited(const ui::MouseEvent& event) { + close_button_->SetVisible(false); +} + views::View* LockScreenMediaControlsView::GetMiddleSpacingView() { return middle_spacing_.get(); } @@ -340,15 +381,28 @@ if (hide_controls_timer_->IsRunning()) return; + // Convert the bitmap to kN32_SkColorType if necessary. + SkBitmap converted_bitmap; + if (bitmap.colorType() == kN32_SkColorType) { + converted_bitmap = bitmap; + } else { + SkImageInfo info = bitmap.info().makeColorType(kN32_SkColorType); + if (converted_bitmap.tryAllocPixels(info)) { + bitmap.readPixels(info, converted_bitmap.getPixels(), + converted_bitmap.rowBytes(), 0, 0); + } + } + switch (type) { case media_session::mojom::MediaSessionImageType::kArtwork: { base::Optional<gfx::ImageSkia> session_artwork = - gfx::ImageSkia::CreateFrom1xBitmap(bitmap); + gfx::ImageSkia::CreateFrom1xBitmap(converted_bitmap); SetArtwork(session_artwork); break; } case media_session::mojom::MediaSessionImageType::kSourceIcon: { - gfx::ImageSkia session_icon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); + gfx::ImageSkia session_icon = + gfx::ImageSkia::CreateFrom1xBitmap(converted_bitmap); if (session_icon.isNull()) { session_icon = gfx::CreateVectorIcon(message_center::kProductIcon, kIconSize, gfx::kChromeIconGrey); @@ -360,6 +414,12 @@ void LockScreenMediaControlsView::ButtonPressed(views::Button* sender, const ui::Event& event) { + if (sender == close_button_) { + media_controller_ptr_->Stop(); + hide_media_controls_.Run(); + return; + } + if (!base::Contains(enabled_actions_, media_message_center::GetActionFromButtonTag(*sender)) || !media_session_id_.has_value()) {
diff --git a/ash/login/ui/lock_screen_media_controls_view.h b/ash/login/ui/lock_screen_media_controls_view.h index b0b83bca..9301cf1 100644 --- a/ash/login/ui/lock_screen_media_controls_view.h +++ b/ash/login/ui/lock_screen_media_controls_view.h
@@ -21,6 +21,7 @@ namespace views { class ImageView; class ToggleImageButton; +class ImageButton; } // namespace views namespace ash { @@ -61,6 +62,8 @@ const char* GetClassName() const override; gfx::Size CalculatePreferredSize() const override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; + void OnMouseEntered(const ui::MouseEvent& event) override; + void OnMouseExited(const ui::MouseEvent& event) override; views::View* GetMiddleSpacingView(); @@ -74,6 +77,8 @@ override; void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override; + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} // media_session::mojom::MediaControllerImageObserver: void MediaControllerImageChanged( @@ -155,6 +160,7 @@ views::ImageView* session_artwork_ = nullptr; NonAccessibleView* button_row_ = nullptr; views::ToggleImageButton* play_pause_button_ = nullptr; + views::ImageButton* close_button_ = nullptr; // Callbacks. const MediaControlsEnabled media_controls_enabled_;
diff --git a/ash/login/ui/lock_screen_media_controls_view_unittest.cc b/ash/login/ui/lock_screen_media_controls_view_unittest.cc index 862525e..d72d68f7 100644 --- a/ash/login/ui/lock_screen_media_controls_view_unittest.cc +++ b/ash/login/ui/lock_screen_media_controls_view_unittest.cc
@@ -167,7 +167,11 @@ return media_controls_view_->session_artwork_; } - const gfx::ImageSkia& GetAppIcon() const { + views::ImageButton* close_button() const { + return media_controls_view_->close_button_; + } + + const views::ImageView* icon_view() const { return header_row()->app_icon_for_testing(); } @@ -211,7 +215,7 @@ message_center::kProductIcon, kAppIconSize, gfx::kChromeIconGrey); // Verify that the default icon is not drawn. - EXPECT_FALSE(GetAppIcon().BackedBySameObjectAs(default_icon)); + EXPECT_FALSE(icon_view()->GetImage().BackedBySameObjectAs(default_icon)); // Set artwork for new media session. SkBitmap artwork; @@ -266,13 +270,16 @@ views::FocusManager* focus_manager = media_controls_view_->GetFocusManager(); { - // Focus the first action button. - auto* button = GetButtonForAction(MediaSessionAction::kPreviousTrack); - focus_manager->SetFocusedView(button); - EXPECT_EQ(button, focus_manager->GetFocusedView()); + // Focus the first action button - the close button. + focus_manager->SetFocusedView(close_button()); + EXPECT_EQ(close_button(), focus_manager->GetFocusedView()); } SimulateTab(); + EXPECT_EQ(GetButtonForAction(MediaSessionAction::kPreviousTrack), + focus_manager->GetFocusedView()); + + SimulateTab(); EXPECT_EQ(GetButtonForAction(MediaSessionAction::kSeekBackward), focus_manager->GetFocusedView()); @@ -308,6 +315,49 @@ EXPECT_NE(tooltip, new_tooltip); } +TEST_F(LockScreenMediaControlsViewTest, CloseButtonVisibility) { + EXPECT_TRUE(media_controls_view_->IsDrawn()); + EXPECT_FALSE(close_button()->IsDrawn()); + + // Move the mouse inside |media_controls_view_|. + ui::test::EventGenerator* generator = GetEventGenerator(); + generator->MoveMouseTo( + media_controls_view_->GetBoundsInScreen().CenterPoint()); + + // Verify that the close button is shown. + EXPECT_TRUE(close_button()->IsDrawn()); + + // Move the mouse outside |media_controls_view_|. + generator->MoveMouseBy(500, 500); + + // Verify that the close button is hidden. + EXPECT_TRUE(media_controls_view_->IsDrawn()); + EXPECT_FALSE(close_button()->IsDrawn()); +} + +TEST_F(LockScreenMediaControlsViewTest, CloseButtonClick) { + EXPECT_TRUE(media_controls_view_->IsDrawn()); + + // Move the mouse inside |media_controls_view_|. + ui::test::EventGenerator* generator = GetEventGenerator(); + generator->MoveMouseTo( + media_controls_view_->GetBoundsInScreen().CenterPoint()); + + EXPECT_TRUE(close_button()->IsDrawn()); + EXPECT_EQ(0, media_controller()->stop_count()); + + // Send event to click the close button. + generator->MoveMouseTo(close_button()->GetBoundsInScreen().CenterPoint()); + generator->ClickLeftButton(); + + // Verify that the media was stopped. + media_controls_view_->FlushForTesting(); + EXPECT_EQ(1, media_controller()->stop_count()); + + // Verify that the controls were hidden. + EXPECT_FALSE(media_controls_view_->IsDrawn()); +} + TEST_F(LockScreenMediaControlsViewTest, PreviousTrackButtonClick) { EnableAction(MediaSessionAction::kPreviousTrack); @@ -385,17 +435,17 @@ message_center::kProductIcon, kAppIconSize, gfx::kChromeIconGrey); // Verify that the icon is initialized to the default. - EXPECT_TRUE(GetAppIcon().BackedBySameObjectAs(default_icon)); - EXPECT_EQ(kAppIconSize, GetAppIcon().width()); - EXPECT_EQ(kAppIconSize, GetAppIcon().height()); + EXPECT_TRUE(icon_view()->GetImage().BackedBySameObjectAs(default_icon)); + EXPECT_EQ(kAppIconSize, icon_view()->GetImage().width()); + EXPECT_EQ(kAppIconSize, icon_view()->GetImage().height()); media_controls_view_->MediaControllerImageChanged( media_session::mojom::MediaSessionImageType::kSourceIcon, SkBitmap()); // Verify that the default icon is used if no icon is provided. - EXPECT_TRUE(GetAppIcon().BackedBySameObjectAs(default_icon)); - EXPECT_EQ(kAppIconSize, GetAppIcon().width()); - EXPECT_EQ(kAppIconSize, GetAppIcon().height()); + EXPECT_TRUE(icon_view()->GetImage().BackedBySameObjectAs(default_icon)); + EXPECT_EQ(kAppIconSize, icon_view()->GetImage().width()); + EXPECT_EQ(kAppIconSize, icon_view()->GetImage().height()); SkBitmap bitmap; bitmap.allocN32Pixels(kAppIconSize, kAppIconSize); @@ -403,9 +453,9 @@ media_session::mojom::MediaSessionImageType::kSourceIcon, bitmap); // Verify that the provided icon is used. - EXPECT_FALSE(GetAppIcon().BackedBySameObjectAs(default_icon)); - EXPECT_EQ(kAppIconSize, GetAppIcon().width()); - EXPECT_EQ(kAppIconSize, GetAppIcon().height()); + EXPECT_FALSE(icon_view()->GetImage().BackedBySameObjectAs(default_icon)); + EXPECT_EQ(kAppIconSize, icon_view()->GetImage().width()); + EXPECT_EQ(kAppIconSize, icon_view()->GetImage().height()); } TEST_F(LockScreenMediaControlsViewTest, UpdateAppName) { @@ -429,6 +479,36 @@ EXPECT_EQ(kTestAppName, GetAppName()); } +TEST_F(LockScreenMediaControlsViewTest, UpdateImagesConvertColors) { + SkBitmap artwork; + SkImageInfo artwork_info = + SkImageInfo::Make(200, 200, kAlpha_8_SkColorType, kOpaque_SkAlphaType); + artwork.allocPixels(artwork_info); + + media_controls_view_->MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType::kArtwork, artwork); + + // Verify the artwork color was converted. + EXPECT_EQ(artwork_view()->GetImage().bitmap()->colorType(), kN32_SkColorType); + + // Verify the artwork is visible. + EXPECT_TRUE(artwork_view()->GetVisible()); + + SkBitmap icon; + SkImageInfo icon_info = + SkImageInfo::Make(20, 20, kAlpha_8_SkColorType, kOpaque_SkAlphaType); + artwork.allocPixels(icon_info); + + media_controls_view_->MediaControllerImageChanged( + media_session::mojom::MediaSessionImageType::kSourceIcon, icon); + + // Verify the icon color was converted. + EXPECT_EQ(icon_view()->GetImage().bitmap()->colorType(), kN32_SkColorType); + + // Verify the icon is visible. + EXPECT_TRUE(icon_view()->GetVisible()); +} + TEST_F(LockScreenMediaControlsViewTest, UpdateArtwork) { // Verify that the artwork is initially empty. EXPECT_TRUE(artwork_view()->GetImage().isNull());
diff --git a/ash/login/ui/login_expanded_public_account_view.cc b/ash/login/ui/login_expanded_public_account_view.cc index 8272fee..b5cd47d 100644 --- a/ash/login/ui/login_expanded_public_account_view.cc +++ b/ash/login/ui/login_expanded_public_account_view.cc
@@ -220,7 +220,9 @@ // Container for the device monitoring warning. class MonitoringWarningView : public NonAccessibleView { public: - MonitoringWarningView() : NonAccessibleView(kMonitoringWarningClassName) { + MonitoringWarningView() + : NonAccessibleView(kMonitoringWarningClassName), + warning_type_(WarningType::kNone) { SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), kSpacingBetweenMonitoringWarningIconAndLabelDp)); @@ -241,27 +243,46 @@ AddChildView(label_); } - enum class WarningType { kSoftWarning, kFullWarning }; + enum class WarningType { kNone, kSoftWarning, kFullWarning }; + + void UpdateForUser(const LoginUserInfo& user) { + enterprise_domain_ = user.public_account_info->enterprise_domain; + UpdateLabel(); + } void SetWarningType(WarningType warning_type) { - base::string16 label_text; - if (warning_type == WarningType::kFullWarning) { - label_text = l10n_util::GetStringUTF16( - IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING); - image_->SetVisible(true); - } else if (warning_type == WarningType::kSoftWarning) { - label_text = l10n_util::GetStringUTF16( - IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_SOFT_WARNING); - image_->SetVisible(false); - } - label_->SetText(label_text); + warning_type_ = warning_type; + UpdateLabel(); } ~MonitoringWarningView() override = default; private: + void UpdateLabel() { + // Call sequence of UpdateForUser() and SetWarningType() is not clear. + // In case SetWarningType is called first there is a need to wait for + // enterprise_domain_ is set. + if (warning_type_ == WarningType::kNone || !enterprise_domain_.has_value()) + return; + base::string16 label_text; + if (warning_type_ == WarningType::kFullWarning) { + label_text = l10n_util::GetStringFUTF16( + IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING, + base::UTF8ToUTF16(enterprise_domain_.value())); + image_->SetVisible(true); + } else { + label_text = l10n_util::GetStringFUTF16( + IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_SOFT_WARNING, + base::UTF8ToUTF16(enterprise_domain_.value())); + image_->SetVisible(false); + } + label_->SetText(label_text); + } + friend class LoginExpandedPublicAccountView::TestApi; + WarningType warning_type_; + base::Optional<std::string> enterprise_domain_; views::ImageView* image_; views::Label* label_; @@ -458,6 +479,7 @@ void UpdateForUser(const LoginUserInfo& user) { DCHECK_EQ(user.basic_user_info.type, user_manager::USER_TYPE_PUBLIC_ACCOUNT); + monitoring_warning_view_->UpdateForUser(user); current_user_ = user; if (!language_changed_by_user_) selected_language_item_.value = user.public_account_info->default_locale; @@ -666,6 +688,15 @@ return view_->right_pane_->monitoring_warning_view_->image_; } +views::Label* +LoginExpandedPublicAccountView::TestApi::monitoring_warning_label() { + return view_->right_pane_->monitoring_warning_view_->label_; +} + +void LoginExpandedPublicAccountView::TestApi::ResetUserForTest() { + view_->right_pane_->monitoring_warning_view_->enterprise_domain_.reset(); +} + LoginExpandedPublicAccountView::LoginExpandedPublicAccountView( const OnPublicSessionViewDismissed& on_dismissed) : NonAccessibleView(kLoginExpandedPublicAccountViewClassName),
diff --git a/ash/login/ui/login_expanded_public_account_view.h b/ash/login/ui/login_expanded_public_account_view.h index dfa6cb4..a44a6f87 100644 --- a/ash/login/ui/login_expanded_public_account_view.h +++ b/ash/login/ui/login_expanded_public_account_view.h
@@ -12,6 +12,7 @@ #include "ash/login/ui/non_accessible_view.h" #include "ui/events/event_handler.h" #include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" #include "ui/views/controls/styled_label.h" #include "ui/views/view.h" @@ -45,6 +46,8 @@ LoginMenuView::Item selected_language_item(); LoginMenuView::Item selected_keyboard_item(); views::ImageView* monitoring_warning_icon(); + views::Label* monitoring_warning_label(); + void ResetUserForTest(); private: LoginExpandedPublicAccountView* const view_;
diff --git a/ash/login/ui/login_expanded_public_account_view_unittest.cc b/ash/login/ui/login_expanded_public_account_view_unittest.cc index 1cde40d3..8a504b64 100644 --- a/ash/login/ui/login_expanded_public_account_view_unittest.cc +++ b/ash/login/ui/login_expanded_public_account_view_unittest.cc
@@ -11,8 +11,11 @@ #include "ash/login/ui/public_account_warning_dialog.h" #include "ash/login/ui/views_utils.h" #include "ash/public/cpp/login_types.h" +#include "ash/strings/grit/ash_strings.h" #include "base/bind_helpers.h" +#include "chromeos/strings/grit/chromeos_strings.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/events/test/event_generator.h" #include "ui/views/layout/box_layout.h" #include "ui/views/widget/widget.h" @@ -293,6 +296,31 @@ EXPECT_EQ(test_api.selected_keyboard_item().value, kKeyboardIdForItem1); } +TEST_P(LoginExpandedPublicAccountViewTest, ChangeWarningLabel) { + LoginExpandedPublicAccountView::TestApi test_api(public_account_); + views::Label* label = test_api.monitoring_warning_label(); + test_api.ResetUserForTest(); + const base::string16 default_warning = l10n_util::GetStringUTF16( + IDS_ASH_LOGIN_PUBLIC_ACCOUNT_MONITORING_WARNING); + EXPECT_EQ(label->GetText(), default_warning); + + public_account_->SetShowFullManagementDisclosure(false); + EXPECT_EQ(label->GetText(), default_warning); + const std::string domain = + user_.public_account_info->enterprise_domain.value(); + public_account_->UpdateForUser(user_); + const base::string16 soft_warning = l10n_util::GetStringFUTF16( + IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_SOFT_WARNING, + base::UTF8ToUTF16(domain)); + EXPECT_EQ(label->GetText(), soft_warning); + + public_account_->SetShowFullManagementDisclosure(true); + const base::string16 full_warning = l10n_util::GetStringFUTF16( + IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING, + base::UTF8ToUTF16(domain)); + EXPECT_EQ(label->GetText(), full_warning); +} + INSTANTIATE_TEST_SUITE_P(, LoginExpandedPublicAccountViewTest, ::testing::Values("mouse", "touch"));
diff --git a/ash/login/ui/media_controls_header_view.cc b/ash/login/ui/media_controls_header_view.cc index 103dd42738..b6fcda3 100644 --- a/ash/login/ui/media_controls_header_view.cc +++ b/ash/login/ui/media_controls_header_view.cc
@@ -16,6 +16,7 @@ namespace { +constexpr gfx::Insets kMediaControlsHeaderInsets = gfx::Insets(0, 25, 25, 25); constexpr int kIconSize = 20; constexpr int kHeaderTextFontSize = 14; constexpr int kMediaControlsHeaderChildSpacing = 10; @@ -26,7 +27,7 @@ MediaControlsHeaderView::MediaControlsHeaderView() { SetLayoutManager(std::make_unique<views::BoxLayout>( - views::BoxLayout::Orientation::kHorizontal, gfx::Insets(), + views::BoxLayout::Orientation::kHorizontal, kMediaControlsHeaderInsets, kMediaControlsHeaderChildSpacing)); auto app_icon_view = std::make_unique<views::ImageView>(); @@ -71,8 +72,8 @@ return app_name_view_->GetText(); } -const gfx::ImageSkia& MediaControlsHeaderView::app_icon_for_testing() const { - return app_icon_view_->GetImage(); +const views::ImageView* MediaControlsHeaderView::app_icon_for_testing() const { + return app_icon_view_; } } // namespace ash \ No newline at end of file
diff --git a/ash/login/ui/media_controls_header_view.h b/ash/login/ui/media_controls_header_view.h index 3d6154b..d3ef5dc1 100644 --- a/ash/login/ui/media_controls_header_view.h +++ b/ash/login/ui/media_controls_header_view.h
@@ -27,7 +27,7 @@ void GetAccessibleNodeData(ui::AXNodeData* node_data) override; const base::string16& app_name_for_testing() const; - const gfx::ImageSkia& app_icon_for_testing() const; + const views::ImageView* app_icon_for_testing() const; private: views::ImageView* app_icon_view_;
diff --git a/ash/media/media_controller_impl.cc b/ash/media/media_controller_impl.cc index 0b6315e..789a4ad 100644 --- a/ash/media/media_controller_impl.cc +++ b/ash/media/media_controller_impl.cc
@@ -53,6 +53,8 @@ bool MediaControllerImpl::AreLockScreenMediaKeysEnabled() const { PrefService* prefs = Shell::Get()->session_controller()->GetPrimaryUserPrefService(); + DCHECK(prefs); + return base::FeatureList::IsEnabled(features::kLockScreenMediaKeys) && prefs->GetBoolean(prefs::kLockScreenMediaKeysEnabled) && !media_controls_dismissed_;
diff --git a/ash/media/media_controller_impl.h b/ash/media/media_controller_impl.h index 4e0e1a4..a611d77 100644 --- a/ash/media/media_controller_impl.h +++ b/ash/media/media_controller_impl.h
@@ -81,6 +81,8 @@ override; void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override {} + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} private: friend class MediaControllerTest;
diff --git a/ash/public/cpp/accessibility_controller_client.h b/ash/public/cpp/accessibility_controller_client.h index c9cc1448..58a07d76 100644 --- a/ash/public/cpp/accessibility_controller_client.h +++ b/ash/public/cpp/accessibility_controller_client.h
@@ -28,6 +28,10 @@ // Triggers an accessibility alert to give the user feedback. virtual void TriggerAccessibilityAlert(AccessibilityAlert alert) = 0; + // Triggers an accessibility alert with the given |message|. + virtual void TriggerAccessibilityAlertWithMessage( + const std::string& message) = 0; + // Plays an earcon. Earcons are brief and distinctive sounds that indicate // that their mapped event has occurred. The |sound_key| enums can be found in // chromeos/audio/chromeos_sounds.h. This method exists because the browser
diff --git a/ash/system/accessibility/autoclick_menu_bubble_controller.cc b/ash/system/accessibility/autoclick_menu_bubble_controller.cc index 835abe9..1de741e 100644 --- a/ash/system/accessibility/autoclick_menu_bubble_controller.cc +++ b/ash/system/accessibility/autoclick_menu_bubble_controller.cc
@@ -177,6 +177,9 @@ bubble_widget_->GetLayer()->GetAnimator()); settings.SetPreemptionStrategy( ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); + settings.SetTweenType(gfx::Tween::EASE_OUT); bubble_widget_->SetBounds(resting_bounds); if (!scroll_bubble_controller_)
diff --git a/ash/system/accessibility/autoclick_menu_bubble_controller.h b/ash/system/accessibility/autoclick_menu_bubble_controller.h index 2dc3b4a..302c5086 100644 --- a/ash/system/accessibility/autoclick_menu_bubble_controller.h +++ b/ash/system/accessibility/autoclick_menu_bubble_controller.h
@@ -20,6 +20,10 @@ : public TrayBubbleView::Delegate, public LocaleChangeObserver { public: + // The duration of the position change animation for the menu and scroll + // bubbles in milliseconds. + static const int kAnimationDurationMs = 150; + AutoclickMenuBubbleController(); ~AutoclickMenuBubbleController() override;
diff --git a/ash/system/accessibility/autoclick_scroll_view.cc b/ash/system/accessibility/autoclick_scroll_view.cc index 042ec38..0f3b3fc 100644 --- a/ash/system/accessibility/autoclick_scroll_view.cc +++ b/ash/system/accessibility/autoclick_scroll_view.cc
@@ -8,6 +8,7 @@ #include "ash/resources/vector_icons/vector_icons.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" +#include "ash/system/accessibility/autoclick_menu_bubble_controller.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/unified/custom_shape_button.h" #include "ash/system/unified/top_shortcut_button.h" @@ -334,6 +335,9 @@ GetWidget()->GetLayer()->GetAnimator()); settings.SetPreemptionStrategy( ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( + AutoclickMenuBubbleController::kAnimationDurationMs)); + settings.SetTweenType(gfx::Tween::EASE_OUT); // SetAnchorRect will resize, so set the arrow without reizing to avoid a // double animation. SetArrowWithoutResizing(arrow);
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h index cd1b92c..fba3711 100644 --- a/ash/system/tray/tray_constants.h +++ b/ash/system/tray/tray_constants.h
@@ -207,7 +207,8 @@ constexpr int kUnifiedFeaturePodCollapsedHorizontalPadding = 24; constexpr int kUnifiedFeaturePodArrowSpacing = 4; constexpr int kUnifiedFeaturePodItemsInRow = 3; -constexpr int kUnifiedFeaturePodItemsRows = 3; +constexpr int kUnifiedFeaturePodMaxRows = 3; +constexpr int kUnifiedFeaturePodMinRows = 1; constexpr int kUnifiedFeaturePodMaxItemsInCollapsed = 5; constexpr int kUnifiedFeaturePodsPageSpacing = 48; constexpr int kUnifiedNotificationSeparatorThickness = 1;
diff --git a/ash/system/unified/feature_pods_container_view.cc b/ash/system/unified/feature_pods_container_view.cc index 4b52c1a..c36c936eea 100644 --- a/ash/system/unified/feature_pods_container_view.cc +++ b/ash/system/unified/feature_pods_container_view.cc
@@ -18,7 +18,8 @@ bool initially_expanded) : controller_(controller), pagination_model_(controller->model()->pagination_model()), - expanded_amount_(initially_expanded ? 1.0 : 0.0) { + expanded_amount_(initially_expanded ? 1.0 : 0.0), + feature_pod_rows_(kUnifiedFeaturePodMaxRows) { pagination_model_->AddObserver(this); } @@ -46,13 +47,12 @@ button->SetExpandedAmount(1.0 - expanded_amount, true /* fade_icon_button */); } else if (visible_index > kUnifiedFeaturePodMaxItemsInCollapsed) { - int row = (visible_index / kUnifiedFeaturePodItemsInRow) % - kUnifiedFeaturePodItemsRows; + int row = + (visible_index / kUnifiedFeaturePodItemsInRow) % feature_pod_rows_; double button_expanded_amount = expanded_amount - ? std::min(1.0, - expanded_amount + - (0.25 * (kUnifiedFeaturePodItemsRows - row - 1))) + ? std::min(1.0, expanded_amount + + (0.25 * (feature_pod_rows_ - row - 1))) : expanded_amount; button->SetExpandedAmount(button_expanded_amount, true /* fade_icon_button */); @@ -75,7 +75,7 @@ kUnifiedFeaturePodItemsInRow; if (features::IsSystemTrayFeaturePodsPaginationEnabled()) - number_of_lines = std::min(number_of_lines, kUnifiedFeaturePodItemsRows); + number_of_lines = std::min(number_of_lines, feature_pod_rows_); return kUnifiedFeaturePodBottomPadding + (kUnifiedFeaturePodVerticalPadding + kUnifiedFeaturePodSize.height()) * @@ -208,6 +208,26 @@ y * expanded_amount_ + collapsed_y * (1.0 - expanded_amount_)); } +void FeaturePodsContainerView::SetMaxHeight(int max_height) { + int feature_pod_rows = + (max_height - kUnifiedFeaturePodBottomPadding - + kUnifiedFeaturePodTopPadding) / + (kUnifiedFeaturePodSize.height() + kUnifiedFeaturePodVerticalPadding); + + std::cout << (max_height - kUnifiedFeaturePodBottomPadding - + kUnifiedFeaturePodTopPadding) / + (kUnifiedFeaturePodSize.height() + + kUnifiedFeaturePodVerticalPadding) + << std::endl; + feature_pod_rows = std::min(feature_pod_rows, kUnifiedFeaturePodMaxRows); + feature_pod_rows = std::max(feature_pod_rows, kUnifiedFeaturePodMinRows); + + if (feature_pod_rows_ != feature_pod_rows) { + feature_pod_rows_ = feature_pod_rows; + UpdateTotalPages(); + } +} + void FeaturePodsContainerView::UpdateCollapsedSidePadding() { const int visible_count = std::min(GetVisibleCount(), kUnifiedFeaturePodMaxItemsInCollapsed); @@ -301,7 +321,7 @@ int FeaturePodsContainerView::GetTilesPerPage() const { if (features::IsSystemTrayFeaturePodsPaginationEnabled()) - return kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodItemsRows; + return kUnifiedFeaturePodItemsInRow * feature_pod_rows_; else return children().size(); }
diff --git a/ash/system/unified/feature_pods_container_view.h b/ash/system/unified/feature_pods_container_view.h index e41589a..36b7a5c5 100644 --- a/ash/system/unified/feature_pods_container_view.h +++ b/ash/system/unified/feature_pods_container_view.h
@@ -37,6 +37,10 @@ // horizontally placed. void SetExpandedAmount(double expanded_amount); + // Set the number of rows of feature pods based on the max height the + // container can have. + void SetMaxHeight(int max_height); + // Get height of the view when |expanded_amount| is set to 1.0. int GetExpandedHeight() const; @@ -55,7 +59,6 @@ void OnGestureEvent(ui::GestureEvent* event) override; void OnScrollEvent(ui::ScrollEvent* event) override; bool OnMouseWheel(const ui::MouseWheelEvent& event) override; - const char* GetClassName() const override; private: @@ -97,6 +100,10 @@ // The last |expanded_amount| passed to SetExpandedAmount(). double expanded_amount_; + // Number of rows of feature pods to display. Updated based on the available + // max height for FeaturePodsContainer. + int feature_pod_rows_ = 0; + // Horizontal side padding in dip for collapsed state. int collapsed_side_padding_ = 0;
diff --git a/ash/system/unified/feature_pods_container_view_unittest.cc b/ash/system/unified/feature_pods_container_view_unittest.cc index 0d387c0b..df0319b4 100644 --- a/ash/system/unified/feature_pods_container_view_unittest.cc +++ b/ash/system/unified/feature_pods_container_view_unittest.cc
@@ -197,7 +197,7 @@ const int kNumberOfPages = 8; EnablePagination(); - AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodItemsRows * + AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodMaxRows * kNumberOfPages); // Adding buttons to fill kNumberOfPages should cause the the same number of @@ -213,7 +213,7 @@ const int kNumberOfPages = 8; EnablePagination(); - AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodItemsRows * + AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodMaxRows * kNumberOfPages); // Position of a button should slide to the left during a page @@ -248,11 +248,46 @@ EXPECT_EQ(final_bounds, buttons_[0]->bounds()); } +TEST_F(FeaturePodsContainerViewTest, PaginationDynamicRows) { + const int kNumberOfFeaturePods = kUnifiedFeaturePodItemsInRow * 3; + const int padding = + kUnifiedFeaturePodTopPadding + kUnifiedFeaturePodBottomPadding; + + EnablePagination(); + AddButtons(kNumberOfFeaturePods); + + // Expect 1 row of feature pods even if there is 0 height. + container()->SetMaxHeight(0); + int expected_number_of_pages = + kNumberOfFeaturePods / kUnifiedFeaturePodItemsInRow; + if (kNumberOfFeaturePods % kUnifiedFeaturePodItemsInRow) + expected_number_of_pages += 1; + EXPECT_EQ(expected_number_of_pages, pagination_model()->total_pages()); + + // Expect 2 rows of feature pods when there is enough height to display them. + container()->SetMaxHeight(padding + + (2 * (kUnifiedFeaturePodSize.height() + + kUnifiedFeaturePodVerticalPadding))); + expected_number_of_pages = + kNumberOfFeaturePods / (2 * kUnifiedFeaturePodItemsInRow); + if (kNumberOfFeaturePods % (2 * kUnifiedFeaturePodItemsInRow)) + expected_number_of_pages += 1; + EXPECT_EQ(expected_number_of_pages, pagination_model()->total_pages()); + + // Expect 3 rows of feature pods at max even when the max height is very + // large. + container()->SetMaxHeight(100 * (kUnifiedFeaturePodSize.height())); + expected_number_of_pages = + kNumberOfFeaturePods / (3 * kUnifiedFeaturePodItemsInRow); + if (kNumberOfFeaturePods % (3 * kUnifiedFeaturePodItemsInRow)) + expected_number_of_pages += 1; + EXPECT_EQ(expected_number_of_pages, pagination_model()->total_pages()); +} TEST_F(FeaturePodsContainerViewTest, PaginationGestureHandling) { const int kNumberOfPages = 8; EnablePagination(); - AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodItemsRows * + AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodMaxRows * kNumberOfPages); gfx::Point container_origin = container()->GetBoundsInScreen().origin(); @@ -320,7 +355,7 @@ const int num_fingers = 2; EnablePagination(); - AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodItemsRows * + AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodMaxRows * kNumberOfPages); EXPECT_EQ(kNumberOfPages, pagination_model()->total_pages()); @@ -371,7 +406,7 @@ const int kNumberOfPages = 8; EnablePagination(); - AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodItemsRows * + AddButtons(kUnifiedFeaturePodItemsInRow * kUnifiedFeaturePodMaxRows * kNumberOfPages); gfx::Point container_origin = container()->GetBoundsInScreen().origin();
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc index e6a48aff..8dbb582 100644 --- a/ash/system/unified/unified_system_tray_view.cc +++ b/ash/system/unified/unified_system_tray_view.cc
@@ -298,6 +298,15 @@ max_height_ = max_height; message_center_view_->SetMaxHeight(max_height_); + // FeaturePodsContainer can adjust it's height by reducing the number of rows + // it uses. It will calculate how many rows to use based on the max height + // passed here. + feature_pods_container_->SetMaxHeight( + max_height - top_shortcuts_view_->GetPreferredSize().height() - + page_indicator_view_->GetPreferredSize().height() - + sliders_container_->GetPreferredSize().height() - + system_info_view_->GetPreferredSize().height()); + // Because the message center view requires a certain height to be usable, it // will be hidden if there isn't sufficient remaining height. int system_tray_height = expanded_amount_ > 0.0
diff --git a/ash/wm/desks/desk.cc b/ash/wm/desks/desk.cc index 7f32810b..e44f2d9 100644 --- a/ash/wm/desks/desk.cc +++ b/ash/wm/desks/desk.cc
@@ -170,12 +170,16 @@ // The windows on this root are about to be destroyed. We already stopped // observing the container above, so we won't get a call to // DeskContainerObserver::OnWindowRemoved(). Therefore, we must remove those - // windows manually. This happens when the last root window is destroyed (i.e. - // there are no more roots to move those windows to). This typically happen - // when shutting down. - const auto roots = Shell::GetAllRootWindows(); - if (roots.size() == 1u && roots[0] == root) - windows_.clear(); + // windows manually. If this is part of shutdown (i.e. when the + // RootWindowController is being destroyed), then we're done with those + // windows. If this is due to a display being removed, then the + // WindowTreeHostManager will move those windows to another host/root, and + // they will be added again to the desk container on the new root. + const auto windows = windows_; + for (auto* window : windows) { + if (window->GetRootWindow() == root) + base::Erase(windows_, window); + } } void Desk::AddWindowToDesk(aura::Window* window) {
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc index e38b1d1..def8041 100644 --- a/ash/wm/desks/desks_controller.cc +++ b/ash/wm/desks/desks_controller.cc
@@ -6,8 +6,10 @@ #include <utility> +#include "ash/accessibility/accessibility_controller_impl.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/shell.h" +#include "ash/strings/grit/ash_strings.h" #include "ash/wm/desks/desk.h" #include "ash/wm/desks/desks_util.h" #include "ash/wm/desks/root_window_desk_switch_animator.h" @@ -22,6 +24,7 @@ #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "ui/aura/window_tree_host.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/compositor/compositor.h" #include "ui/wm/public/activation_client.h" @@ -146,6 +149,11 @@ UMA_HISTOGRAM_ENUMERATION(kNewDeskHistogramName, source); ReportDesksCountHistogram(); + Shell::Get() + ->accessibility_controller() + ->TriggerAccessibilityAlertWithMessage(l10n_util::GetStringFUTF8( + IDS_ASH_VIRTUAL_DESKS_ALERT_NEW_DESK_CREATED, + base::NumberToString16(desks_.size()))); for (auto& observer : observers_) observer.OnDeskAdded(desks_.back().get()); @@ -162,6 +170,9 @@ [desk](const std::unique_ptr<Desk>& d) { return d.get() == desk; }); DCHECK(iter != desks_.end()); + // Used by accessibility to indicate the desk that has been removed. + const int removed_desk_number = std::distance(desks_.begin(), iter) + 1; + // Keep the removed desk alive until the end of this function. std::unique_ptr<Desk> removed_desk = std::move(*iter); DCHECK_EQ(removed_desk.get(), desk); @@ -269,6 +280,16 @@ ReportDesksCountHistogram(); ReportNumberOfWindowsPerDeskHistogram(); + int active_desk_number = GetDeskIndex(active_desk_) + 1; + if (active_desk_number == removed_desk_number) + active_desk_number++; + Shell::Get() + ->accessibility_controller() + ->TriggerAccessibilityAlertWithMessage(l10n_util::GetStringFUTF8( + IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_REMOVED, + base::NumberToString16(removed_desk_number), + base::NumberToString16(active_desk_number))); + DCHECK_LE(available_container_ids_.size(), desks_util::kMaxNumberOfDesks); } @@ -293,6 +314,12 @@ return; } + Shell::Get() + ->accessibility_controller() + ->TriggerAccessibilityAlertWithMessage(l10n_util::GetStringFUTF8( + IDS_ASH_VIRTUAL_DESKS_ALERT_DESK_ACTIVATED, + base::NumberToString16(GetDeskIndex(desk) + 1))); + // New desks are always added at the end of the list to the right of existing // desks. Therefore, desks at lower indices are located on the left of desks // with higher indices. @@ -324,6 +351,14 @@ active_desk_->MoveWindowToDesk(window, target_desk); + Shell::Get() + ->accessibility_controller() + ->TriggerAccessibilityAlertWithMessage(l10n_util::GetStringFUTF8( + IDS_ASH_VIRTUAL_DESKS_ALERT_WINDOW_MOVED_FROM_ACTIVE_DESK, + window->GetTitle(), + base::NumberToString16(GetDeskIndex(active_desk_) + 1), + base::NumberToString16(GetDeskIndex(target_desk) + 1))); + if (in_overview) { DCHECK(overview_controller->InOverviewSession()); auto* overview_session = overview_controller->overview_session();
diff --git a/base/allocator/partition_allocator/memory_reclaimer.cc b/base/allocator/partition_allocator/memory_reclaimer.cc index 1a135c7..991576c 100644 --- a/base/allocator/partition_allocator/memory_reclaimer.cc +++ b/base/allocator/partition_allocator/memory_reclaimer.cc
@@ -15,8 +15,6 @@ namespace internal { -const Feature kNoPartitionAllocDecommit{"NoPartitionAllocDecommit", - FEATURE_DISABLED_BY_DEFAULT}; // TODO(crbug.com/942512): Remove the feature after the M77 branch. const Feature kPartitionAllocPeriodicDecommit{"PartitionAllocPeriodicDecommit", FEATURE_ENABLED_BY_DEFAULT}; @@ -26,8 +24,7 @@ namespace { bool IsDeprecatedDecommitEnabled() { - return !(FeatureList::IsEnabled(internal::kNoPartitionAllocDecommit) || - FeatureList::IsEnabled(internal::kPartitionAllocPeriodicDecommit)); + return !FeatureList::IsEnabled(internal::kPartitionAllocPeriodicDecommit); } } // namespace
diff --git a/base/allocator/partition_allocator/memory_reclaimer.h b/base/allocator/partition_allocator/memory_reclaimer.h index 87987f58..eca30a7 100644 --- a/base/allocator/partition_allocator/memory_reclaimer.h +++ b/base/allocator/partition_allocator/memory_reclaimer.h
@@ -25,7 +25,6 @@ struct PartitionRootBase; -BASE_EXPORT extern const Feature kNoPartitionAllocDecommit; BASE_EXPORT extern const Feature kPartitionAllocPeriodicDecommit; } // namespace internal
diff --git a/base/memory/memory_pressure_monitor_chromeos.cc b/base/memory/memory_pressure_monitor_chromeos.cc index 91a2dd3..043d43ba 100644 --- a/base/memory/memory_pressure_monitor_chromeos.cc +++ b/base/memory/memory_pressure_monitor_chromeos.cc
@@ -93,7 +93,7 @@ base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::WILL_BLOCK); - pollfd pfd = {available_fd, POLLPRI | POLLERR, 0}; + pollfd pfd = {available_fd, POLLPRI | POLLERR | POLLIN, 0}; int res = HANDLE_EINTR(poll(&pfd, 1, -1)); // Wait indefinitely. PCHECK(res != -1);
diff --git a/base/system/sys_info_fuchsia.cc b/base/system/sys_info_fuchsia.cc index 8206aa52..7a6a8a7 100644 --- a/base/system/sys_info_fuchsia.cc +++ b/base/system/sys_info_fuchsia.cc
@@ -20,9 +20,8 @@ // static int64_t SysInfo::AmountOfAvailablePhysicalMemoryImpl() { - // TODO(https://crbug.com/706592): This method doesn't have an Fuchsia API to - // consume it - NOTREACHED(); + // TODO(https://crbug.com/986608): Implement this. + NOTIMPLEMENTED_LOG_ONCE(); return 0; }
diff --git a/base/test/scoped_feature_list.cc b/base/test/scoped_feature_list.cc index e23a5579..de8671c1 100644 --- a/base/test/scoped_feature_list.cc +++ b/base/test/scoped_feature_list.cc
@@ -10,7 +10,6 @@ #include "base/memory/ptr_util.h" #include "base/metrics/field_trial_param_associator.h" -#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -66,6 +65,19 @@ std::vector<StringPiece> disabled_feature_list; }; +// Features in |feature_vector| came from |merged_features| in +// OverrideFeatures() and contains linkage with field trial is case when they +// have parameters (with '<' simbol). In |feature_name| name is already cleared +// with GetFeatureName() and also could be without parameters. +bool ContainsFeature(const std::vector<StringPiece>& feature_vector, + StringPiece feature_name) { + auto iter = std::find_if(feature_vector.begin(), feature_vector.end(), + [&feature_name](const StringPiece& a) { + return GetFeatureName(a) == feature_name; + }); + return iter != feature_vector.end(); +} + // Merges previously-specified feature overrides with those passed into one of // the Init() methods. |features| should be a list of features previously // overridden to be in the |override_state|. |merged_features| should contain @@ -80,8 +92,8 @@ for (StringPiece feature : features_list) { StringPiece feature_name = GetFeatureName(feature); - if (Contains(merged_features->enabled_feature_list, feature_name) || - Contains(merged_features->disabled_feature_list, feature_name)) { + if (ContainsFeature(merged_features->enabled_feature_list, feature_name) || + ContainsFeature(merged_features->disabled_feature_list, feature_name)) { continue; } @@ -102,6 +114,8 @@ // Inverse of HexEncodeString(). std::string HexDecodeString(const std::string& input) { + if (input.empty()) + return std::string(); std::vector<uint8_t> bytes; bool result = HexStringToBytes(input, &bytes); DCHECK(result);
diff --git a/base/test/scoped_feature_list_unittest.cc b/base/test/scoped_feature_list_unittest.cc index 7e251f6..46b7cb17 100644 --- a/base/test/scoped_feature_list_unittest.cc +++ b/base/test/scoped_feature_list_unittest.cc
@@ -275,6 +275,27 @@ EXPECT_EQ(kValue, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); } +TEST_F(ScopedFeatureListTest, ParamsWithEmptyValue) { + const char kParam[] = "p"; + const char kEmptyValue[] = ""; + FieldTrialParams params = {{kParam, kEmptyValue}}; + + test::ScopedFeatureList feature_list0; + feature_list0.InitWithFeaturesAndParameters({{kTestFeature1, params}}, {}); + EXPECT_EQ(kEmptyValue, + GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + { + const char kValue1[] = "normal"; + FieldTrialParams params1 = {{kParam, kValue1}}; + test::ScopedFeatureList feature_list1; + feature_list1.InitWithFeaturesAndParameters({{kTestFeature1, params1}}, {}); + + EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); + } + EXPECT_EQ(kEmptyValue, + GetFieldTrialParamValueByFeature(kTestFeature1, kParam)); +} + TEST_F(ScopedFeatureListTest, EnableFeatureOverrideDisable) { test::ScopedFeatureList feature_list1; feature_list1.InitWithFeatures({}, {kTestFeature1}); @@ -398,5 +419,16 @@ ExpectFeatures("*TestFeature1", std::string()); } +TEST(ScopedFeatureListTestWithMemberList, ScopedFeatureListLocalOverride) { + test::ScopedFeatureList initial_feature_list; + initial_feature_list.InitAndDisableFeature(kTestFeature1); + { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitAndEnableFeatureWithParameters(kTestFeature1, + {{"mode", "nobugs"}}); + ASSERT_TRUE(FeatureList::IsEnabled(kTestFeature1)); + } +} + } // namespace test } // namespace base
diff --git a/base/win/i18n.cc b/base/win/i18n.cc index eb44c496..04f533a 100644 --- a/base/win/i18n.cc +++ b/base/win/i18n.cc
@@ -7,146 +7,40 @@ #include <windows.h> #include "base/logging.h" -#include "base/stl_util.h" +#include "base/strings/string_split.h" #include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" namespace { -// Keep this enum in sync with kLanguageFunctionNames. -enum LanguageFunction { - SYSTEM_LANGUAGES, - USER_LANGUAGES, - PROCESS_LANGUAGES, - THREAD_LANGUAGES, - NUM_FUNCTIONS -}; +typedef decltype(::GetSystemPreferredUILanguages)* GetPreferredUILanguages_Fn; -const char kSystemLanguagesFunctionName[] = "GetSystemPreferredUILanguages"; -const char kUserLanguagesFunctionName[] = "GetUserPreferredUILanguages"; -const char kProcessLanguagesFunctionName[] = "GetProcessPreferredUILanguages"; -const char kThreadLanguagesFunctionName[] = "GetThreadPreferredUILanguages"; - -// Keep this array in sync with enum LanguageFunction. -const char *const kLanguageFunctionNames[] = { - &kSystemLanguagesFunctionName[0], - &kUserLanguagesFunctionName[0], - &kProcessLanguagesFunctionName[0], - &kThreadLanguagesFunctionName[0] -}; - -static_assert(NUM_FUNCTIONS == base::size(kLanguageFunctionNames), - "LanguageFunction enum and kLanguageFunctionNames array must be " - "kept in sync"); - -// Calls one of the MUI Get*PreferredUILanguages functions, placing the result -// in |languages|. |function| identifies the function to call and |flags| is -// the function-specific flags (callers must not specify MUI_LANGUAGE_ID or -// MUI_LANGUAGE_NAME). Returns true if at least one language is placed in -// |languages|. -bool GetMUIPreferredUILanguageList(LanguageFunction function, ULONG flags, - std::vector<wchar_t>* languages) { - DCHECK(0 <= function && NUM_FUNCTIONS > function); - DCHECK_EQ(0U, (flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME))); - DCHECK(languages); - - HMODULE kernel32 = GetModuleHandle(L"kernel32.dll"); - if (NULL != kernel32) { - typedef BOOL (WINAPI* GetPreferredUILanguages_Fn)( - DWORD, PULONG, PZZWSTR, PULONG); - GetPreferredUILanguages_Fn get_preferred_ui_languages = - reinterpret_cast<GetPreferredUILanguages_Fn>( - GetProcAddress(kernel32, kLanguageFunctionNames[function])); - if (NULL != get_preferred_ui_languages) { - const ULONG call_flags = flags | MUI_LANGUAGE_NAME; - ULONG language_count = 0; - ULONG buffer_length = 0; - if (get_preferred_ui_languages(call_flags, &language_count, NULL, - &buffer_length) && - 0 != buffer_length) { - languages->resize(buffer_length); - if (get_preferred_ui_languages(call_flags, &language_count, - &(*languages)[0], &buffer_length) && - 0 != language_count) { - DCHECK(languages->size() == buffer_length); - return true; - } else { - DPCHECK(0 == language_count) - << "Failed getting preferred UI languages."; - } - } else { - DPCHECK(0 == buffer_length) - << "Failed getting size of preferred UI languages."; - } - } else { - DVLOG(2) << "MUI not available."; - } - } else { - NOTREACHED() << "kernel32.dll not found."; - } - - return false; -} - -bool GetUserDefaultUILanguage(base::string16* language, - base::string16* region) { - DCHECK(language); - - LANGID lang_id = ::GetUserDefaultUILanguage(); - if (LOCALE_CUSTOM_UI_DEFAULT != lang_id) { - const LCID locale_id = MAKELCID(lang_id, SORT_DEFAULT); - // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9 - base::char16 result_buffer[9]; - int result_length = GetLocaleInfo(locale_id, LOCALE_SISO639LANGNAME, - base::as_writable_wcstr(result_buffer), - base::size(result_buffer)); - DPCHECK(0 != result_length) << "Failed getting language id"; - if (1 < result_length) { - language->assign(&result_buffer[0], result_length - 1); - region->clear(); - if (SUBLANG_NEUTRAL != SUBLANGID(lang_id)) { - result_length = GetLocaleInfo(locale_id, LOCALE_SISO3166CTRYNAME, - base::as_writable_wcstr(result_buffer), - base::size(result_buffer)); - DPCHECK(0 != result_length) << "Failed getting region id"; - if (1 < result_length) - region->assign(&result_buffer[0], result_length - 1); - } - return true; - } - } else { - // This is entirely unexpected on pre-Vista, which is the only time we - // should try GetUserDefaultUILanguage anyway. - NOTREACHED() << "Cannot determine language for a supplemental locale."; - } - return false; -} - -bool GetPreferredUILanguageList(LanguageFunction function, +bool GetPreferredUILanguageList(GetPreferredUILanguages_Fn function, ULONG flags, std::vector<base::string16>* languages) { - std::vector<wchar_t> buffer; - base::string16 language; - base::string16 region; - - if (GetMUIPreferredUILanguageList(function, flags, &buffer)) { - std::vector<wchar_t>::const_iterator scan = buffer.begin(); - language = base::WideToUTF16(&*scan); - while (!language.empty()) { - languages->push_back(language); - scan += language.size() + 1; - language = base::WideToUTF16(&*scan); - } - } else if (GetUserDefaultUILanguage(&language, ®ion)) { - // Mimic the MUI behavior of putting the neutral version of the lang after - // the regional one (e.g., "fr-CA, fr"). - if (!region.empty()) - languages->push_back(language + base::string16(1, '-') + region); - languages->push_back(language); - } else { + DCHECK_EQ(0U, (flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME))); + const ULONG call_flags = flags | MUI_LANGUAGE_NAME; + ULONG language_count = 0; + ULONG buffer_length = 0; + if (!function(call_flags, &language_count, nullptr, &buffer_length) || + 0 == buffer_length) { + DPCHECK(0 == buffer_length) + << "Failed getting size of preferred UI languages."; return false; } + base::string16 buffer(buffer_length, '\0'); + if (!function(call_flags, &language_count, base::as_writable_wcstr(buffer), + &buffer_length) || + 0 == language_count) { + DPCHECK(0 == language_count) << "Failed getting preferred UI languages."; + return false; + } + + // Split string on NUL characters. + *languages = + base::SplitString(buffer, base::string16(1, '\0'), base::KEEP_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); + DCHECK_EQ(languages->size(), language_count); return true; } @@ -158,14 +52,15 @@ bool GetUserPreferredUILanguageList(std::vector<base::string16>* languages) { DCHECK(languages); - return GetPreferredUILanguageList(USER_LANGUAGES, 0, languages); + return GetPreferredUILanguageList(::GetUserPreferredUILanguages, 0, + languages); } bool GetThreadPreferredUILanguageList(std::vector<base::string16>* languages) { DCHECK(languages); return GetPreferredUILanguageList( - THREAD_LANGUAGES, MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK, - languages); + ::GetThreadPreferredUILanguages, + MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK, languages); } } // namespace i18n
diff --git a/base/win/i18n_unittest.cc b/base/win/i18n_unittest.cc index 0188838..b7973c3e 100644 --- a/base/win/i18n_unittest.cc +++ b/base/win/i18n_unittest.cc
@@ -4,12 +4,13 @@ // This file contains unit tests for Windows internationalization funcs. -#include "testing/gtest/include/gtest/gtest.h" - #include <stddef.h> +#include <string.h> +#include "base/strings/string_util.h" #include "base/win/i18n.h" #include "base/win/windows_version.h" +#include "testing/gtest/include/gtest/gtest.h" namespace base { namespace win { @@ -22,6 +23,8 @@ EXPECT_FALSE(languages.empty()); for (const auto& language : languages) { EXPECT_FALSE(language.empty()); + // Ensure there's no extra trailing 0 characters. + EXPECT_EQ(language.size(), wcslen(base::as_wcstr(language))); } } @@ -32,6 +35,7 @@ EXPECT_FALSE(languages.empty()); for (const auto& language : languages) { EXPECT_FALSE(language.empty()); + EXPECT_EQ(language.size(), wcslen(base::as_wcstr(language))); } }
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc index ce52ad64..1d3721944 100644 --- a/base/win/windows_version.cc +++ b/base/win/windows_version.cc
@@ -27,10 +27,6 @@ #error Windows 10.0.18362.0 SDK or higher required. #endif -namespace { -typedef BOOL(WINAPI* GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD); -} // namespace - namespace base { namespace win { @@ -79,14 +75,8 @@ ::GetVersionEx(reinterpret_cast<_OSVERSIONINFOW*>(&version_info)); DWORD os_type = 0; - if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) { - // Only present on Vista+. - GetProductInfoPtr get_product_info = - reinterpret_cast<GetProductInfoPtr>(::GetProcAddress( - ::GetModuleHandle(L"kernel32.dll"), "GetProductInfo")); - get_product_info(version_info.dwMajorVersion, version_info.dwMinorVersion, - 0, 0, &os_type); - } + ::GetProductInfo(version_info.dwMajorVersion, version_info.dwMinorVersion, + 0, 0, &os_type); return new OSInfo(version_info, GetSystemInfoStorage(), os_type); }(); @@ -252,13 +242,8 @@ // static OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) { - typedef BOOL(WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL); - IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>( - GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process")); - if (!is_wow64_process) - return WOW64_DISABLED; BOOL is_wow64 = FALSE; - if (!(*is_wow64_process)(process_handle, &is_wow64)) + if (!::IsWow64Process(process_handle, &is_wow64)) return WOW64_UNKNOWN; return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED; }
diff --git a/build/BUILD.gn b/build/BUILD.gn index 7ab955a..f4bc5e4 100644 --- a/build/BUILD.gn +++ b/build/BUILD.gn
@@ -2,8 +2,17 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/buildflag_header.gni") +import("//build/config/chrome_build.gni") + source_set("buildflag_header_h") { sources = [ "buildflag.h", ] } + +buildflag_header("branding_buildflags") { + header = "branding_buildflags.h" + + flags = [ "CHROMIUM_BRANDING=!is_chrome_branded" ] +}
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py index b5eefd0..624f734 100755 --- a/build/chromeos/test_runner.py +++ b/build/chromeos/test_runner.py
@@ -297,12 +297,6 @@ './' + os.path.relpath(self._on_device_script, self._path_to_outdir) ] else: - self._test_cmd += [ - # Since we're not in a chroot, the tast bin won't automatically handle - # ssh auth. So point it to the ssh keys in chromite. - '--private-key', - os.path.join(CHROMITE_PATH, 'ssh_keys', 'testing_rsa'), - ] # Capture tast's results in the logs dir as well. if self._logs_dir: self._test_cmd += [ @@ -643,6 +637,12 @@ if args.verbose: cros_run_test_cmd.append('--debug') + if args.logs_dir: + cros_run_test_cmd += [ + '--results-src', '/var/log/', + '--results-dest-dir', args.logs_dir, + ] + test_env = setup_env() if args.deploy_chrome: cros_run_test_cmd += [
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn index 514ab7ba..d44c925 100644 --- a/build/config/BUILD.gn +++ b/build/config/BUILD.gn
@@ -95,10 +95,7 @@ defines += [ "NO_TCMALLOC" ] } if (is_asan || is_hwasan || is_lsan || is_tsan || is_msan) { - defines += [ - "MEMORY_TOOL_REPLACES_ALLOCATOR", - "MEMORY_SANITIZER_INITIAL_SIZE", - ] + defines += [ "MEMORY_TOOL_REPLACES_ALLOCATOR" ] } if (is_asan) { defines += [ "ADDRESS_SANITIZER" ] @@ -130,9 +127,12 @@ if (is_official_build) { defines += [ "OFFICIAL_BUILD" ] } + + # TODO(thakis): Remove these in favor of build/branding_buildflags.h. if (is_chrome_branded) { defines += [ "GOOGLE_CHROME_BUILD" ] } else { + # TODO(thakis): All uses for this are gone, remove this in a follow-up. defines += [ "CHROMIUM_BUILD" ] }
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index db7ab02..23695f672 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -574,8 +574,10 @@ # On Android, write shared library output file to metadata. We will use # this information to, for instance, collect all shared libraries that # should be packaged into an APK. - if (!defined(invoker.metadata) && is_android && - _target_type == "shared_library") { + if (!defined(invoker.metadata) && is_android && (_target_type == + "shared_library" || + _target_type == + "loadable_module")) { _output_name = _target_name if (defined(invoker.output_name)) { _output_name = invoker.output_name @@ -590,7 +592,7 @@ _output_name = string_replace(_output_name, _magic_prefix, "", 1) _shlib_extension = ".so" - if (is_component_build) { + if (is_component_build && _target_type != "loadable_module") { _shlib_extension = ".cr.so" }
diff --git a/build/toolchain/toolchain.gni b/build/toolchain/toolchain.gni index 260ed0b7..648455c 100644 --- a/build/toolchain/toolchain.gni +++ b/build/toolchain/toolchain.gni
@@ -30,7 +30,7 @@ assert( is_official_build, "Linker map files should only be generated when is_official_build = true") - assert(current_os == "android" || target_os == "linux", + assert(target_os == "android" || target_os == "linux", "Linker map files should only be generated for Android and Linux") }
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc index 0612c46..23c71d9 100644 --- a/cc/layers/picture_layer_impl.cc +++ b/cc/layers/picture_layer_impl.cc
@@ -233,7 +233,11 @@ } float device_scale_factor = layer_tree_impl()->device_scale_factor(); - float max_contents_scale = MaximumTilingContentsScale(); + // If we don't have tilings, we're likely going to append a checkerboard quad + // the size of the layer. In that case, use scale 1 for more stable + // to-screen-space mapping. + float max_contents_scale = + tilings_->num_tilings() ? MaximumTilingContentsScale() : 1.f; PopulateScaledSharedQuadState(shared_quad_state, max_contents_scale, contents_opaque()); Occlusion scaled_occlusion;
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc index 4276fd2..1949b352 100644 --- a/cc/layers/picture_layer_impl_unittest.cc +++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -5588,5 +5588,35 @@ EXPECT_TRUE(pending_layer()->GetPaintWorkletRecordMap().contains(input3)); } +TEST_F(PictureLayerImplTest, NoTilingsUsesScaleOne) { + std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create(); + + gfx::Size layer_bounds(1000, 10000); + scoped_refptr<FakeRasterSource> active_raster_source = + FakeRasterSource::CreateEmpty(layer_bounds); + SetupPendingTree(active_raster_source); + ActivateTree(); + + active_layer()->SetContentsOpaque(true); + active_layer()->draw_properties().visible_layer_rect = + gfx::Rect(0, 0, 1000, 1000); + active_layer()->UpdateTiles(); + + ASSERT_FALSE(active_layer()->HighResTiling()); + + AppendQuadsData data; + active_layer()->WillDraw(DRAW_MODE_HARDWARE, nullptr); + active_layer()->AppendQuads(render_pass.get(), &data); + active_layer()->DidDraw(nullptr); + + // One checkerboard quad. + EXPECT_EQ(1u, render_pass->quad_list.size()); + + auto* shared_quad_state = render_pass->quad_list.begin()->shared_quad_state; + // We should use scale 1 here, so the layer rect should be full layer bounds + // and the transform should be identity. + EXPECT_RECT_EQ(gfx::Rect(1000, 10000), shared_quad_state->quad_layer_rect); + EXPECT_TRUE(shared_quad_state->quad_to_target_transform.IsIdentity()); +} } // namespace } // namespace cc
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc index 983c6be..f91deac 100644 --- a/cc/trees/property_tree.cc +++ b/cc/trees/property_tree.cc
@@ -833,7 +833,6 @@ // when we actually encounter a masking child. node->has_masking_child = false; if (node->blend_mode == SkBlendMode::kDstIn) { - DCHECK(parent_node->HasRenderSurface()); parent_node->has_masking_child = true; } }
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index e5b48fd..e107dd9 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -1862,14 +1862,17 @@ "jnigraphics", ] - deps = [ + public_deps = [ "//chrome/browser", + "//chrome/utility", + ] + + deps = [ "//chrome/browser/ui", "//chrome/child", "//chrome/common", "//chrome/gpu", "//chrome/renderer", - "//chrome/utility", "//components/gwp_asan/buildflags", "//components/minidump_uploader", "//components/safe_browsing/android:safe_browsing_mobile",
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 7760b121..35dd742 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -903,6 +903,7 @@ "//chrome/test/data/push_messaging/", "//chrome/test/data/translate/", "//chrome/test/media_router/resources/", + "//components/test/data/autofill/", "//components/test/data/payments/", "//content/test/data/browsing_data/", "//content/test/data/android/authenticator.html", @@ -1549,6 +1550,7 @@ ":test_support_jni_headers", "//chrome/browser", "//components/offline_pages/core/background:test_support", + "//content/test:test_support", ] } @@ -2624,6 +2626,7 @@ "java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java", "java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java", "java/src/org/chromium/chrome/browser/webapps/WebApkPostShareTargetNavigator.java", + "java/src/org/chromium/chrome/browser/webapps/WebApkUkmRecorder.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java", "java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 9174c89..675990f4 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -1117,7 +1117,6 @@ "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionViewBinder.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionViewProperties.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerText.java", - "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerTextClassic.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerTextNewLayout.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java", "java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/SuggestionHost.java", @@ -1224,30 +1223,22 @@ "java/src/org/chromium/chrome/browser/preferences/AboutChromePreferenceOSVersion.java", "java/src/org/chromium/chrome/browser/preferences/AboutChromePreferences.java", "java/src/org/chromium/chrome/browser/preferences/AccessibilityPreferences.java", - "java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java", "java/src/org/chromium/chrome/browser/preferences/ButtonPreferenceCompat.java", - "java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreference.java", "java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreferenceCompat.java", - "java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreference.java", "java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreferenceCompat.java", - "java/src/org/chromium/chrome/browser/preferences/ChromeBasePreference.java", "java/src/org/chromium/chrome/browser/preferences/ChromeBasePreferenceCompat.java", - "java/src/org/chromium/chrome/browser/preferences/ChromeImageViewPreference.java", "java/src/org/chromium/chrome/browser/preferences/ChromeImageViewPreferenceCompat.java", "java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java", - "java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreference.java", "java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreferenceCompat.java", "java/src/org/chromium/chrome/browser/preferences/ClearBrowsingDataCheckBoxPreference.java", "java/src/org/chromium/chrome/browser/preferences/ExpandablePreferenceGroup.java", "java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java", "java/src/org/chromium/chrome/browser/preferences/HomepagePreferences.java", "java/src/org/chromium/chrome/browser/preferences/HyperlinkPreference.java", - "java/src/org/chromium/chrome/browser/preferences/LearnMorePreference.java", "java/src/org/chromium/chrome/browser/preferences/LearnMorePreferenceCompat.java", "java/src/org/chromium/chrome/browser/preferences/LegalInformationPreferences.java", "java/src/org/chromium/chrome/browser/preferences/LocationSettings.java", "java/src/org/chromium/chrome/browser/preferences/MainPreferences.java", - "java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegate.java", "java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegateCompat.java", "java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java", "java/src/org/chromium/chrome/browser/preferences/NotificationsPreferences.java", @@ -1270,7 +1261,6 @@ "java/src/org/chromium/chrome/browser/preferences/sync/SyncPreferenceUtils.java", "java/src/org/chromium/chrome/browser/preferences/sync/SyncedAccountPreference.java", "java/src/org/chromium/chrome/browser/preferences/TextAndButtonPreference.java", - "java/src/org/chromium/chrome/browser/preferences/TextMessagePreference.java", "java/src/org/chromium/chrome/browser/preferences/TextMessagePreferenceCompat.java", "java/src/org/chromium/chrome/browser/preferences/TextScalePreference.java", "java/src/org/chromium/chrome/browser/preferences/autofill/AndroidPaymentAppPreference.java", @@ -1699,6 +1689,7 @@ "java/src/org/chromium/chrome/browser/webapps/WebApkServiceClient.java", "java/src/org/chromium/chrome/browser/webapps/WebApkShareTargetUtil.java", "java/src/org/chromium/chrome/browser/webapps/WebApkSplashNetworkErrorObserver.java", + "java/src/org/chromium/chrome/browser/webapps/WebApkUkmRecorder.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java", "java/src/org/chromium/chrome/browser/webapps/WebApkUpdateTask.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index c5ca794..f51954cba 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -52,6 +52,7 @@ "javatests/src/org/chromium/chrome/browser/appmenu/DataSaverAppMenuTest.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java", + "javatests/src/org/chromium/chrome/browser/autofill/AutofillUpstreamTest.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java", "javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java", "javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java", @@ -445,8 +446,9 @@ "javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java", "javatests/src/org/chromium/chrome/browser/sync/FakeProfileSyncService.java", "javatests/src/org/chromium/chrome/browser/sync/FirstRunTest.java", + "javatests/src/org/chromium/chrome/browser/sync/ManageSyncPreferencesTest.java", "javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java", - "javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java", + "javatests/src/org/chromium/chrome/browser/sync/SyncAndServicesPreferencesTest.java", "javatests/src/org/chromium/chrome/browser/sync/SyncTest.java", "javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java", "javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantChoiceList.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantChoiceList.java index 1537e25..8469d73 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantChoiceList.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantChoiceList.java
@@ -198,7 +198,11 @@ View.OnClickListener clickListener = unusedView -> setChecked( view, mAllowMultipleChoices ? !item.mCompoundButton.isChecked() : true); - radioButton.setOnClickListener(clickListener); + radioButton.setOnCheckedChangeListener((unusedView, isChecked) -> { + if (item.mOnSelectedListener != null) { + item.mOnSelectedListener.onResult(isChecked); + } + }); view.setOnClickListener(clickListener); mItems.add(item); } @@ -262,21 +266,24 @@ */ public void setChecked(View content, boolean checked) { for (Item item : mItems) { - boolean notifyListener = false; if (item.mContent == content) { item.mCompoundButton.setChecked(checked); - notifyListener = true; } else if (checked && !mAllowMultipleChoices) { item.mCompoundButton.setChecked(false); - notifyListener = true; - } - - if (notifyListener && item.mOnSelectedListener != null) { - item.mOnSelectedListener.onResult(item.mCompoundButton.isChecked()); } } } + /** Returns whether {@code content} is checked or not. */ + public boolean isChecked(View content) { + for (Item mItem : mItems) { + if (mItem.mContent == content) { + return mItem.mCompoundButton.isChecked(); + } + } + return false; + } + /** * Allows to change the label of the 'add' button. */
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestBinder.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestBinder.java index ba8f5a4b..aaae7a7 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestBinder.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestBinder.java
@@ -10,6 +10,7 @@ import org.chromium.chrome.browser.ChromeVersionInfo; import org.chromium.chrome.browser.autofill.PersonalDataManager; +import org.chromium.chrome.browser.autofill_assistant.payment.AssistantPaymentRequestTermsSection.Delegate; import org.chromium.chrome.browser.payments.AddressEditor; import org.chromium.chrome.browser.payments.AutofillPaymentApp; import org.chromium.chrome.browser.payments.AutofillPaymentInstrument; @@ -96,6 +97,7 @@ private final AssistantPaymentRequestPaymentMethodSection mPaymentMethodSection; private final AssistantPaymentRequestShippingAddressSection mShippingAddressSection; private final AssistantPaymentRequestTermsSection mTermsSection; + private final AssistantPaymentRequestTermsSection mTermsAsCheckboxSection; private final Object mDividerTag; private final Activity mActivity; private PersonalDataManager.PersonalDataManagerObserver mPersonalDataManagerObserver; @@ -105,7 +107,8 @@ AssistantPaymentRequestContactDetailsSection contactDetailsSection, AssistantPaymentRequestPaymentMethodSection paymentMethodSection, AssistantPaymentRequestShippingAddressSection shippingAddressSection, - AssistantPaymentRequestTermsSection termsSection, Object dividerTag, + AssistantPaymentRequestTermsSection termsSection, + AssistantPaymentRequestTermsSection termsAsCheckboxSection, Object dividerTag, Activity activity) { mRootView = rootView; mPaymentRequestExpanderAccordion = accordion; @@ -114,6 +117,7 @@ mPaymentMethodSection = paymentMethodSection; mShippingAddressSection = shippingAddressSection; mTermsSection = termsSection; + mTermsAsCheckboxSection = termsAsCheckboxSection; mDividerTag = dividerTag; mActivity = activity; } @@ -156,8 +160,20 @@ if (propertyKey == AssistantPaymentRequestModel.DELEGATE) { AssistantPaymentRequestDelegate delegate = model.get(AssistantPaymentRequestModel.DELEGATE); - view.mTermsSection.setListener( - delegate != null ? delegate::onTermsAndConditionsChanged : null); + + Delegate termsDelegate = delegate == null ? null : new Delegate() { + @Override + public void onStateChanged(@AssistantTermsAndConditionsState int state) { + delegate.onTermsAndConditionsChanged(state); + } + + @Override + public void onLinkClicked(int link) { + delegate.onTermsAndConditionsLinkClicked(link); + } + }; + view.mTermsSection.setDelegate(termsDelegate); + view.mTermsAsCheckboxSection.setDelegate(termsDelegate); view.mContactDetailsSection.setListener( delegate != null ? delegate::onContactInfoChanged : null); view.mPaymentMethodSection.setListener( @@ -232,9 +248,20 @@ view.mPaymentMethodSection.setVisible( (model.get(AssistantPaymentRequestModel.REQUEST_PAYMENT))); return true; - } else if (propertyKey == AssistantPaymentRequestModel.REQUEST_TERMS_AND_CONDITIONS) { - view.mTermsSection.setTermsListVisible( - model.get(AssistantPaymentRequestModel.REQUEST_TERMS_AND_CONDITIONS)); + } else if (propertyKey == AssistantPaymentRequestModel.ACCEPT_TERMS_AND_CONDITIONS_TEXT) { + view.mTermsSection.setAcceptTermsAndConditionsText( + model.get(AssistantPaymentRequestModel.ACCEPT_TERMS_AND_CONDITIONS_TEXT)); + view.mTermsAsCheckboxSection.setAcceptTermsAndConditionsText( + model.get(AssistantPaymentRequestModel.ACCEPT_TERMS_AND_CONDITIONS_TEXT)); + return true; + } else if (propertyKey == AssistantPaymentRequestModel.SHOW_TERMS_AS_CHECKBOX) { + if (model.get(AssistantPaymentRequestModel.SHOW_TERMS_AS_CHECKBOX)) { + view.mTermsSection.getView().setVisibility(View.GONE); + view.mTermsAsCheckboxSection.getView().setVisibility(View.VISIBLE); + } else { + view.mTermsSection.getView().setVisibility(View.VISIBLE); + view.mTermsAsCheckboxSection.getView().setVisibility(View.GONE); + } return true; } return false; @@ -259,6 +286,9 @@ if (webContents != null) { view.mTermsSection.setOrigin(UrlFormatter.formatUrlForSecurityDisplayOmitScheme( webContents.getLastCommittedUrl())); + view.mTermsAsCheckboxSection.setOrigin( + UrlFormatter.formatUrlForSecurityDisplayOmitScheme( + webContents.getLastCommittedUrl())); } view.startListenToPersonalDataManager(() -> { AssistantPaymentRequestBinder.this.updateAvailableProfiles(model, view); @@ -291,7 +321,9 @@ model.get(AssistantPaymentRequestModel.CONTACT_DETAILS), true); return true; } else if (propertyKey == AssistantPaymentRequestModel.TERMS_STATUS) { - view.mTermsSection.setTermsStatus(model.get(AssistantPaymentRequestModel.TERMS_STATUS)); + int termsStatus = model.get(AssistantPaymentRequestModel.TERMS_STATUS); + view.mTermsSection.setTermsStatus(termsStatus); + view.mTermsAsCheckboxSection.setTermsStatus(termsStatus); return true; } return false; @@ -339,6 +371,7 @@ view.mShippingAddressSection.setPaddings(0, view.mSectionToSectionPadding); } view.mTermsSection.setPaddings(view.mSectionToSectionPadding, 0); + view.mTermsAsCheckboxSection.setPaddings(view.mSectionToSectionPadding, 0); // Hide dividers for currently invisible sections and after the expanded section, if any. boolean prevSectionIsExpandedOrInvisible = false;
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java index 7884733..726274b 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestCoordinator.java
@@ -64,8 +64,11 @@ new AssistantPaymentRequestShippingAddressSection( mActivity, paymentRequestExpanderAccordion); createSeparator(paymentRequestExpanderAccordion); - AssistantPaymentRequestTermsSection termsSection = - new AssistantPaymentRequestTermsSection(mActivity, paymentRequestExpanderAccordion); + AssistantPaymentRequestTermsSection termsSection = new AssistantPaymentRequestTermsSection( + mActivity, paymentRequestExpanderAccordion, /* showAsSingleCheckbox= */ false); + AssistantPaymentRequestTermsSection termsAsCheckboxSection = + new AssistantPaymentRequestTermsSection(mActivity, paymentRequestExpanderAccordion, + /* showAsSingleCheckbox= */ true); paymentRequestExpanderAccordion.setTag( AssistantTagsForTesting.PAYMENT_REQUEST_ACCORDION_TAG); @@ -79,7 +82,8 @@ // Bind view and mediator through the model. mViewHolder = new AssistantPaymentRequestBinder.ViewHolder(mPaymentRequestUI, paymentRequestExpanderAccordion, sectionToSectionPadding, contactDetailsSection, - paymentMethodSection, shippingAddressSection, termsSection, DIVIDER_TAG, activity); + paymentMethodSection, shippingAddressSection, termsSection, termsAsCheckboxSection, + DIVIDER_TAG, activity); AssistantPaymentRequestBinder binder = new AssistantPaymentRequestBinder(); PropertyModelChangeProcessor.create(model, mViewHolder, binder);
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestDelegate.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestDelegate.java index 68a0eeb..f3c67672 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestDelegate.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestDelegate.java
@@ -26,6 +26,9 @@ /** The currently selected payment method has changed. */ void onPaymentMethodChanged(@Nullable AutofillPaymentInstrument paymentInstrument); - /** the currently selected terms & conditions state has changed. */ + /** The currently selected terms & conditions state has changed. */ void onTermsAndConditionsChanged(@AssistantTermsAndConditionsState int state); + + /** Called when a link on the terms and conditions message is clicked. */ + void onTermsAndConditionsLinkClicked(int link); }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestModel.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestModel.java index e579265..0c1716e 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestModel.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestModel.java
@@ -57,7 +57,9 @@ new WritableBooleanPropertyKey(); public static final WritableBooleanPropertyKey REQUEST_PAYMENT = new WritableBooleanPropertyKey(); - public static final WritableBooleanPropertyKey REQUEST_TERMS_AND_CONDITIONS = + public static final WritableObjectPropertyKey<String> ACCEPT_TERMS_AND_CONDITIONS_TEXT = + new WritableObjectPropertyKey<>(); + public static final WritableBooleanPropertyKey SHOW_TERMS_AS_CHECKBOX = new WritableBooleanPropertyKey(); public static final WritableObjectPropertyKey<List<PersonalDataManager.AutofillProfile>> @@ -80,9 +82,9 @@ public AssistantPaymentRequestModel() { super(DELEGATE, WEB_CONTENTS, VISIBLE, SHIPPING_ADDRESS, PAYMENT_METHOD, CONTACT_DETAILS, TERMS_STATUS, REQUEST_NAME, REQUEST_EMAIL, REQUEST_PHONE, REQUEST_SHIPPING_ADDRESS, - REQUEST_PAYMENT, REQUEST_TERMS_AND_CONDITIONS, AVAILABLE_PROFILES, - AVAILABLE_AUTOFILL_PAYMENT_METHODS, SUPPORTED_BASIC_CARD_NETWORKS, - SUPPORTED_PAYMENT_METHODS, EXPANDED_SECTION); + REQUEST_PAYMENT, ACCEPT_TERMS_AND_CONDITIONS_TEXT, SHOW_TERMS_AS_CHECKBOX, + AVAILABLE_PROFILES, AVAILABLE_AUTOFILL_PAYMENT_METHODS, + SUPPORTED_BASIC_CARD_NETWORKS, SUPPORTED_PAYMENT_METHODS, EXPANDED_SECTION); /** * Set initial state for basic type properties (others are implicitly null). @@ -123,8 +125,13 @@ } @CalledByNative - private void setRequestTermsAndConditions(boolean requestTermsAndConditions) { - set(REQUEST_TERMS_AND_CONDITIONS, requestTermsAndConditions); + private void setAcceptTermsAndConditionsText(String text) { + set(ACCEPT_TERMS_AND_CONDITIONS_TEXT, text); + } + + @CalledByNative + private void setShowTermsAsCheckbox(boolean showTermsAsCheckbox) { + set(SHOW_TERMS_AS_CHECKBOX, showTermsAsCheckbox); } @CalledByNative
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestNativeDelegate.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestNativeDelegate.java index 456d5fe..a583578 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestNativeDelegate.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestNativeDelegate.java
@@ -68,6 +68,13 @@ } } + @Override + public void onTermsAndConditionsLinkClicked(int link) { + if (mNativeAssistantPaymentRequestDelegate != 0) { + nativeOnTermsAndConditionsLinkClicked(mNativeAssistantPaymentRequestDelegate, link); + } + } + @CalledByNative private void clearNativePtr() { mNativeAssistantPaymentRequestDelegate = 0; @@ -81,4 +88,6 @@ @Nullable PersonalDataManager.CreditCard card); private native void nativeOnTermsAndConditionsChanged( long nativeAssistantPaymentRequestDelegate, int state); + private native void nativeOnTermsAndConditionsLinkClicked( + long nativeAssistantPaymentRequestDelegate, int link); }
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestTermsSection.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestTermsSection.java index 565f9ac..37e24d4 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestTermsSection.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestTermsSection.java
@@ -5,6 +5,8 @@ package org.chromium.chrome.browser.autofill_assistant.payment; import android.content.Context; +import android.support.annotation.Nullable; +import android.text.method.LinkMovementMethod; import android.text.style.StyleSpan; import android.view.Gravity; import android.view.LayoutInflater; @@ -14,22 +16,45 @@ import android.widget.TextView; import org.chromium.base.ApiCompatibilityUtils; -import org.chromium.base.Callback; import org.chromium.chrome.autofill_assistant.R; +import org.chromium.ui.text.NoUnderlineClickableSpan; import org.chromium.ui.text.SpanApplier; +import org.chromium.ui.text.SpanApplier.SpanInfo; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * The third party terms and conditions section of the Autofill Assistant payment request. */ public class AssistantPaymentRequestTermsSection { + private static final Pattern LINK_PATTERN = Pattern.compile("<link(\\d+)>"); + + interface Delegate { + void onStateChanged(@AssistantTermsAndConditionsState int state); + + void onLinkClicked(int link); + } + private final View mView; private final AssistantChoiceList mTermsList; private final TextView mTermsAgree; + @Nullable private final TextView mTermsRequiresReview; private final TextView mThirdPartyPrivacyNotice; - private Callback<Integer> mListener; + private Delegate mDelegate; - AssistantPaymentRequestTermsSection(Context context, ViewGroup parent) { + private final SpanInfo mBoldSpanInfo = + new SpanInfo("<b>", "</b>", new StyleSpan(android.graphics.Typeface.BOLD)); + private String mOrigin = ""; + private String mAcceptTermsText = ""; + + AssistantPaymentRequestTermsSection( + Context context, ViewGroup parent, boolean showAsSingleCheckbox) { mView = LayoutInflater.from(context).inflate( R.layout.autofill_assistant_payment_request_terms_and_conditions, parent, false); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( @@ -37,43 +62,88 @@ parent.addView(mView, lp); mTermsList = mView.findViewById(R.id.third_party_terms_list); + // This will display the terms as a checkbox instead of radio buttons. + mTermsList.setAllowMultipleChoices(showAsSingleCheckbox); + mTermsAgree = new TextView(context); ApiCompatibilityUtils.setTextAppearance(mTermsAgree, R.style.TextAppearance_BlackCaption); mTermsAgree.setGravity(Gravity.CENTER_VERTICAL); mTermsList.addItem(mTermsAgree, /*hasEditButton=*/false, selected -> { - if (selected && mListener != null) { - mListener.onResult(AssistantTermsAndConditionsState.ACCEPTED); + if (selected) { + if (mDelegate != null) { + mDelegate.onStateChanged(AssistantTermsAndConditionsState.ACCEPTED); + } + } else if (showAsSingleCheckbox && mDelegate != null) { + mDelegate.onStateChanged(AssistantTermsAndConditionsState.NOT_SELECTED); } }, /* itemEditedListener=*/null); - mTermsRequiresReview = new TextView(context); - ApiCompatibilityUtils.setTextAppearance( - mTermsRequiresReview, R.style.TextAppearance_BlackCaption); - mTermsRequiresReview.setGravity(Gravity.CENTER_VERTICAL); - mTermsList.addItem(mTermsRequiresReview, /*hasEditButton=*/false, selected -> { - if (selected && mListener != null) { - mListener.onResult(AssistantTermsAndConditionsState.REQUIRES_REVIEW); - } - }, /* itemEditedListener=*/null); + if (showAsSingleCheckbox) { + mTermsRequiresReview = null; + } else { + mTermsRequiresReview = new TextView(context); + ApiCompatibilityUtils.setTextAppearance( + mTermsRequiresReview, R.style.TextAppearance_BlackCaption); + mTermsRequiresReview.setGravity(Gravity.CENTER_VERTICAL); + mTermsList.addItem(mTermsRequiresReview, /*hasEditButton=*/false, selected -> { + if (selected && mDelegate != null) { + mDelegate.onStateChanged(AssistantTermsAndConditionsState.REQUIRES_REVIEW); + } + }, /* itemEditedListener=*/null); + } mThirdPartyPrivacyNotice = mView.findViewById(R.id.payment_request_3rd_party_privacy_notice); } public void setOrigin(String origin) { - StyleSpan boldSpan = new StyleSpan(android.graphics.Typeface.BOLD); - Context context = mView.getContext(); - mTermsAgree.setText(SpanApplier.applySpans( - context.getString(R.string.autofill_assistant_3rd_party_terms_accept, origin), - new SpanApplier.SpanInfo("<b>", "</b>", boldSpan))); + mOrigin = origin; - mTermsRequiresReview.setText(SpanApplier.applySpans( - context.getString(R.string.autofill_assistant_3rd_party_terms_review, origin), - new SpanApplier.SpanInfo("<b>", "</b>", boldSpan))); + setAcceptTermsText(); + + Context context = mView.getContext(); + if (mTermsRequiresReview != null) { + mTermsRequiresReview.setText(SpanApplier.applySpans( + context.getString(R.string.autofill_assistant_3rd_party_terms_review, origin), + mBoldSpanInfo)); + } mThirdPartyPrivacyNotice.setText(SpanApplier.applySpans( context.getString(R.string.autofill_assistant_3rd_party_privacy_notice, origin), - new SpanApplier.SpanInfo("<b>", "</b>", boldSpan))); + mBoldSpanInfo)); + } + + private void setAcceptTermsText() { + if (mAcceptTermsText.isEmpty()) return; + + List<SpanInfo> spans = new ArrayList<>(); + if (mAcceptTermsText.contains("<b>")) { + spans.add(mBoldSpanInfo); + } + + // We first collect the link IDs into a set to allow multiple links with same ID. + Set<Integer> linkIds = new HashSet<>(); + Matcher matcher = LINK_PATTERN.matcher(mAcceptTermsText); + while (matcher.find()) { + linkIds.add(Integer.parseInt(matcher.group(1))); + } + + for (Integer linkId : linkIds) { + spans.add(new SpanInfo("<link" + linkId + ">", "</link" + linkId + ">", + new NoUnderlineClickableSpan(mView.getContext().getResources(), + (unusedView) -> onTermsAndConditionsLinkClicked(linkId)))); + } + + mTermsAgree.setText(SpanApplier.applySpans(String.format(mAcceptTermsText, mOrigin), + spans.toArray(new SpanInfo[spans.size()]))); + mTermsAgree.setMovementMethod(linkIds.isEmpty() ? null : LinkMovementMethod.getInstance()); + } + + private void onTermsAndConditionsLinkClicked(int link) { + // Ignore first click if the option is not selected yet. + if (!mTermsList.isChecked(mTermsAgree) || mDelegate == null) return; + + mDelegate.onLinkClicked(link); } public void setTermsStatus(@AssistantTermsAndConditionsState int status) { @@ -85,7 +155,9 @@ mTermsList.setCheckedItem(mTermsAgree); break; case AssistantTermsAndConditionsState.REQUIRES_REVIEW: - mTermsList.setCheckedItem(mTermsRequiresReview); + if (mTermsRequiresReview != null) { + mTermsList.setCheckedItem(mTermsRequiresReview); + } break; } } @@ -95,12 +167,18 @@ mView.getPaddingLeft(), topPadding, mView.getPaddingRight(), bottomPadding); } - public void setListener(Callback<Integer> listener) { - mListener = listener; + public void setDelegate(Delegate delegate) { + mDelegate = delegate; } - public void setTermsListVisible(boolean visible) { - mTermsList.setVisibility(visible ? View.VISIBLE : View.GONE); + void setAcceptTermsAndConditionsText(String text) { + if (text.isEmpty()) { + mTermsList.setVisibility(View.GONE); + } else { + mTermsList.setVisibility(View.VISIBLE); + mAcceptTermsText = text; + setAcceptTermsText(); + } } View getView() {
diff --git a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd index 45eecf7..59f9fab 100644 --- a/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd +++ b/chrome/android/features/autofill_assistant/java/strings/android_chrome_autofill_assistant_strings.grd
@@ -124,9 +124,6 @@ <message name="IDS_AUTOFILL_ASSISTANT_GOOGLE_TERMS_URL" desc="URL for Google Autofill Assistant Terms of Service" translateable="false"> http://support.google.com/assistant?p=fast_checkout </message> - <message name="IDS_AUTOFILL_ASSISTANT_3RD_PARTY_TERMS_ACCEPT" desc="Message that indicates that the user agrees to the terms and conditions of a 3rd party's domain, e.g., 'odeon.co.uk'."> - I agree to the terms & conditions, privacy policy, and right of withdrawal of <ph name="BEGIN_BOLD"><b></ph><ph name="DOMAIN">%1$s<ex>google.com</ex></ph><ph name="END_BOLD"></b></ph> - </message> <message name="IDS_AUTOFILL_ASSISTANT_3RD_PARTY_TERMS_REVIEW" desc="Message that indicates that the user wants to review the terms and conditions of a 3rd party's domain, e.g., 'odeon.co.uk'."> Read and agree to the terms & conditions on <ph name="BEGIN_BOLD"><b></ph><ph name="DOMAIN">%1$s<ex>google.com</ex></ph><ph name="END_BOLD"></b></ph> later </message>
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestTestHelper.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestTestHelper.java index 12c5d3a..b3daec3 100644 --- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestTestHelper.java +++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPaymentRequestTestHelper.java
@@ -102,6 +102,11 @@ public void onTermsAndConditionsChanged(@AssistantTermsAndConditionsState int state) { mTermsStatus = state; } + + @Override + public void onTermsAndConditionsLinkClicked(int link) { + // TODO(crbug.com/860868): Add tests that use this method. + } } public AutofillAssistantPaymentRequestTestHelper()
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn index 421df94c..2bf62b9 100644 --- a/chrome/android/features/tab_ui/BUILD.gn +++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -27,6 +27,7 @@ "java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/SelectableTabGridView.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/SelectableTabGridViewHolder.java", + "java/src/org/chromium/chrome/browser/tasks/tab_management/TabCarouselViewHolder.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinder.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java",
diff --git a/chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_background_grey.xml b/chrome/android/features/tab_ui/java/res/drawable/hovered_tab_grid_card_background.xml similarity index 67% rename from chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_background_grey.xml rename to chrome/android/features/tab_ui/java/res/drawable/hovered_tab_grid_card_background.xml index 0bd6ef9..12c08b26 100644 --- a/chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_background_grey.xml +++ b/chrome/android/features/tab_ui/java/res/drawable/hovered_tab_grid_card_background.xml
@@ -4,6 +4,6 @@ found in the LICENSE file. --> <shape xmlns:android="http://schemas.android.com/apk/res/android"> - <solid android:color="@color/modern_grey_200"/> - <corners android:radius="@dimen/default_rounded_corner_radius" /> + <solid android:color="@color/tab_list_mini_card_default_background_color"/> + <corners android:radius="@dimen/tab_list_card_radius"/> </shape> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/drawable/selected_tab_background.xml b/chrome/android/features/tab_ui/java/res/drawable/selected_tab_background.xml index 6c49104..75f65f2 100644 --- a/chrome/android/features/tab_ui/java/res/drawable/selected_tab_background.xml +++ b/chrome/android/features/tab_ui/java/res/drawable/selected_tab_background.xml
@@ -7,5 +7,5 @@ <stroke android:width="2dp" android:color="@color/light_active_color" /> - <corners android:radius="@dimen/default_rounded_corner_radius" /> + <corners android:radius="@dimen/tab_list_card_radius" /> </shape> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_background.xml b/chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_background.xml index e4de6a38..0a43dbd5 100644 --- a/chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_background.xml +++ b/chrome/android/features/tab_ui/java/res/drawable/tab_grid_card_background.xml
@@ -4,6 +4,6 @@ found in the LICENSE file. --> <shape xmlns:android="http://schemas.android.com/apk/res/android"> - <solid android:color="@android:color/white"/> - <corners android:radius="@dimen/default_rounded_corner_radius" /> + <solid android:color="@color/tab_grid_dialog_background_color"/> + <corners android:radius="@dimen/tab_list_card_radius" /> </shape> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/drawable/tabstrip_favicon_background.xml b/chrome/android/features/tab_ui/java/res/drawable/tabstrip_favicon_background.xml index 445c96ca..58aacb0f 100644 --- a/chrome/android/features/tab_ui/java/res/drawable/tabstrip_favicon_background.xml +++ b/chrome/android/features/tab_ui/java/res/drawable/tabstrip_favicon_background.xml
@@ -12,7 +12,7 @@ android:bottom="8dp"> <shape android:shape="oval"> - <solid android:color="@color/modern_grey_100" /> + <solid android:color="@color/favicon_background_color" /> </shape> </item> </layer-list> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml index 5c4d46a..da41db1 100644 --- a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml +++ b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml
@@ -8,7 +8,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@color/modern_primary_color"> + android:background="@drawable/tab_grid_card_background"> <LinearLayout android:id="@+id/main_content" android:layout_width="match_parent"
diff --git a/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item.xml b/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item.xml index ca2b033..d2f80507 100644 --- a/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item.xml +++ b/chrome/android/features/tab_ui/java/res/layout/tab_grid_card_item.xml
@@ -6,12 +6,19 @@ <merge xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <View + android:id="@+id/background_view" android:layout_width="match_parent" android:layout_height="match_parent" - android:id="@+id/background_view" - android:background="@drawable/popup_bg" - android:layout_margin="3dp" - android:visibility="visible"/> + android:background="@drawable/hovered_tab_grid_card_background" + android:layout_margin="8dp" + android:visibility="gone"/> + <View + android:id="@+id/selected_view_below_lollipop" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@drawable/selected_tab_background" + android:layout_margin="6dp" + android:visibility="gone"/> <FrameLayout android:id="@+id/content_view" android:layout_width="match_parent" @@ -20,8 +27,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" - android:background="@drawable/tab_grid_card_background" - android:layout_margin="8dp"> + android:background="@drawable/popup_bg_tinted" + android:layout_margin="2dp"> <ImageView android:id="@+id/tab_favicon" android:layout_width="@dimen/tab_grid_favicon_size" @@ -52,12 +59,13 @@ android:scaleType="fitCenter" android:importantForAccessibility="no" android:src="@color/thumbnail_placeholder_on_primary_bg" - app:cornerRadiusBottomStart="@dimen/default_rounded_corner_radius" - app:cornerRadiusBottomEnd="@dimen/default_rounded_corner_radius" - app:roundedfillColor="@color/default_bg_color_light"/> + app:cornerRadiusBottomStart="@dimen/tab_list_card_radius" + app:cornerRadiusBottomEnd="@dimen/tab_list_card_radius"/> <View + android:id="@+id/divider_view" style="@style/HorizontalDivider" - android:layout_below="@id/tab_title"/> + android:layout_below="@id/tab_title" + android:background="@color/divider_bg_color"/> <org.chromium.ui.widget.ButtonCompat android:id="@+id/create_group_button" android:layout_width="wrap_content" @@ -76,6 +84,6 @@ android:layout_height="48dp" android:scaleType="center" android:layout_gravity="end" - android:tint="@color/modern_grey_800"/> + android:tint="@color/default_icon_color"/> </FrameLayout> </merge> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml b/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml index edf63d9..136d503 100644 --- a/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml +++ b/chrome/android/features/tab_ui/java/res/layout/tab_grid_dialog_layout.xml
@@ -19,7 +19,7 @@ android:id="@+id/dialog_ungroup_bar" android:text="@string/tab_grid_dialog_remove_from_group" android:textAppearance="@style/TextAppearance.WhiteHeadline" - android:background="@color/modern_blue_600" + android:background="@color/light_active_color" android:gravity="center" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true"
diff --git a/chrome/android/features/tab_ui/java/res/values/colors.xml b/chrome/android/features/tab_ui/java/res/values/colors.xml new file mode 100644 index 0000000..c93dcbc --- /dev/null +++ b/chrome/android/features/tab_ui/java/res/values/colors.xml
@@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. --> + +<resources xmlns:tools="http://schemas.android.com/tools"> + <color name="tab_list_mini_card_default_background_color">@color/modern_secondary_color</color> + <color name="tab_grid_dialog_background_color">@color/default_bg_color_elev_1</color> + <color name="favicon_background_color">@color/modern_secondary_color</color> +</resources>
diff --git a/chrome/android/features/tab_ui/java/res/values/dimens.xml b/chrome/android/features/tab_ui/java/res/values/dimens.xml index 9ecafbb..cc8d0ace 100644 --- a/chrome/android/features/tab_ui/java/res/values/dimens.xml +++ b/chrome/android/features/tab_ui/java/res/values/dimens.xml
@@ -5,9 +5,8 @@ <resources xmlns:tools="http://schemas.android.com/tools"> <dimen name="tab_grid_favicon_size">32dp</dimen> <dimen name="tab_list_selected_inset">7dp</dimen> - <dimen name="tab_list_selected_inset_kitkat">2dp</dimen> <dimen name="tab_list_card_padding">8dp</dimen> - <dimen name="tab_list_card_background_margin">3dp</dimen> + <dimen name="tab_list_card_radius">4dp</dimen> <dimen name="tab_list_mini_card_radius">4dp</dimen> <dimen name="tab_list_mini_card_frame_size">1dp</dimen> <dimen name="tab_grid_close_button_size">18dp</dimen> @@ -24,4 +23,6 @@ <dimen name="tab_group_toolbar_topic_margin">8dp</dimen> <dimen name="swipe_to_dismiss_threshold">72dp</dimen> <dimen name="selection_tab_grid_toggle_button_inset">14dp</dimen> + <dimen name="tab_carousel_height">192dp</dimen> + <dimen name="tab_carousel_card_width">168dp</dimen> </resources>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ClosableTabGridViewHolder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ClosableTabGridViewHolder.java index 5b7abd7..43cd17f 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ClosableTabGridViewHolder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/ClosableTabGridViewHolder.java
@@ -8,16 +8,11 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; -import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.InsetDrawable; import android.os.Build; import android.support.annotation.IntDef; -import android.support.v7.content.res.AppCompatResources; import android.view.View; -import android.view.ViewGroup; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.tab_ui.R; @@ -72,20 +67,9 @@ assert status < AnimationStatus.NUM_ENTRIES; View view = itemView; - Context context = view.getContext(); final View backgroundView = view.findViewById(R.id.background_view); final View contentView = view.findViewById(R.id.content_view); - final int cardNormalMargin = - (int) context.getResources().getDimension(R.dimen.tab_list_card_padding); - final int cardBackgroundMargin = - (int) context.getResources().getDimension(R.dimen.tab_list_card_background_margin); - final Drawable greyBackground = - AppCompatResources.getDrawable(context, R.drawable.tab_grid_card_background_grey); - final Drawable normalBackground = - AppCompatResources.getDrawable(context, R.drawable.popup_bg); - final Drawable selectedBackground = new InsetDrawable( - AppCompatResources.getDrawable(context, R.drawable.selected_tab_background), - (int) context.getResources().getDimension(R.dimen.tab_list_selected_inset_kitkat)); + final View selectedViewBelowLollipop = view.findViewById(R.id.selected_view_below_lollipop); boolean isZoomIn = status == AnimationStatus.SELECTED_CARD_ZOOM_IN || status == AnimationStatus.HOVERED_CARD_ZOOM_IN; boolean isHovered = status == AnimationStatus.HOVERED_CARD_ZOOM_IN @@ -94,14 +78,10 @@ long duration = isRestore ? RESTORE_ANIMATION_DURATION_MS : TabListRecyclerView.BASE_ANIMATION_DURATION_MS; float scale = isZoomIn ? ZOOM_IN_SCALE : 1f; - ViewGroup.MarginLayoutParams backgroundParams = - (ViewGroup.MarginLayoutParams) backgroundView.getLayoutParams(); View animateView = isHovered ? contentView : view; if (status == AnimationStatus.HOVERED_CARD_ZOOM_IN) { - backgroundParams.setMargins( - cardNormalMargin, cardNormalMargin, cardNormalMargin, cardNormalMargin); - backgroundView.setBackground(greyBackground); + backgroundView.setVisibility(View.VISIBLE); } AnimatorSet scaleAnimator = new AnimatorSet(); @@ -109,13 +89,10 @@ @Override public void onAnimationEnd(Animator animation) { if (!isZoomIn) { - backgroundParams.setMargins(cardBackgroundMargin, cardBackgroundMargin, - cardBackgroundMargin, cardBackgroundMargin); + backgroundView.setVisibility(View.GONE); if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { - backgroundView.setBackground( - isSelected ? selectedBackground : normalBackground); - } else { - backgroundView.setBackground(normalBackground); + selectedViewBelowLollipop.setVisibility( + isSelected ? View.VISIBLE : View.GONE); } } mIsAnimating = false;
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java index c07ff4e..cf97591 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
@@ -74,7 +74,6 @@ mTabSelectionEditorCoordinator = new TabSelectionEditorCoordinator( context, compositorViewHolder, tabModelSelector, tabContentManager); - TabListMediator.GridCardOnClickListenerProvider gridCardOnClickListenerProvider; mMediator = new GridTabSwitcherMediator(this, containerViewModel, tabModelSelector, fullscreenManager, compositorViewHolder, mTabSelectionEditorCoordinator.getController()); @@ -228,6 +227,9 @@ if (mTabGridDialogCoordinator != null) { mTabGridDialogCoordinator.destroy(); } + if (mUndoGroupSnackbarController != null) { + mUndoGroupSnackbarController.destroy(); + } mMediator.destroy(); mLifecycleDispatcher.unregister(this); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java index dfc38ca..d24cf5a2 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.tasks.tab_management; import android.content.Context; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -45,6 +46,7 @@ private final Paint mThumbnailFramePaint; private final Paint mTextPaint; private final Paint mFaviconBackgroundPaint; + private final int mFaviconBackgroundPaintColor; private final List<Rect> mFaviconRects = new ArrayList<>(4); private final List<RectF> mThumbnailRects = new ArrayList<>(4); private final List<RectF> mFaviconBackgroundRects = new ArrayList<>(4); @@ -190,55 +192,55 @@ MultiThumbnailCardProvider(Context context, TabContentManager tabContentManager, TabModelSelector tabModelSelector) { + Resources resource = context.getResources(); + mTabContentManager = tabContentManager; mTabModelSelector = tabModelSelector; - mRadius = context.getResources().getDimension(R.dimen.tab_list_mini_card_radius); - mSize = (int) context.getResources().getDimension( - R.dimen.tab_grid_thumbnail_card_default_size); - mFaviconCirclePadding = context.getResources().getDimension( - R.dimen.tab_grid_thumbnail_favicon_background_padding); + mRadius = resource.getDimension(R.dimen.tab_list_mini_card_radius); + mSize = (int) resource.getDimension(R.dimen.tab_grid_thumbnail_card_default_size); + mFaviconCirclePadding = + resource.getDimension(R.dimen.tab_grid_thumbnail_favicon_background_padding); mTabListFaviconProvider = new TabListFaviconProvider(context, Profile.getLastUsedProfile()); // Initialize Paints to use. mEmptyThumbnailPaint = new Paint(); mEmptyThumbnailPaint.setStyle(Paint.Style.FILL); - mEmptyThumbnailPaint.setColor( - ApiCompatibilityUtils.getColor(context.getResources(), R.color.modern_grey_100)); + mEmptyThumbnailPaint.setColor(ApiCompatibilityUtils.getColor( + resource, R.color.tab_list_mini_card_default_background_color)); mEmptyThumbnailPaint.setAntiAlias(true); mThumbnailFramePaint = new Paint(); mThumbnailFramePaint.setStyle(Paint.Style.STROKE); mThumbnailFramePaint.setStrokeWidth( - context.getResources().getDimension(R.dimen.tab_list_mini_card_frame_size)); + resource.getDimension(R.dimen.tab_list_mini_card_frame_size)); mThumbnailFramePaint.setColor( - ApiCompatibilityUtils.getColor(context.getResources(), R.color.modern_grey_300)); + ApiCompatibilityUtils.getColor(resource, R.color.divider_bg_color)); mThumbnailFramePaint.setAntiAlias(true); mTextPaint = new Paint(); - mTextPaint.setTextSize( - context.getResources().getDimension(R.dimen.compositor_tab_title_text_size)); + mTextPaint.setTextSize(resource.getDimension(R.dimen.compositor_tab_title_text_size)); mTextPaint.setFakeBoldText(true); mTextPaint.setAntiAlias(true); mTextPaint.setTextAlign(Paint.Align.CENTER); + mTextPaint.setColor(ApiCompatibilityUtils.getColor(resource, R.color.default_text_color)); + mFaviconBackgroundPaintColor = + ApiCompatibilityUtils.getColor(resource, R.color.favicon_background_color); mFaviconBackgroundPaint = new Paint(); mFaviconBackgroundPaint.setAntiAlias(true); - mFaviconBackgroundPaint.setColor(Color.WHITE); + mFaviconBackgroundPaint.setColor(mFaviconBackgroundPaintColor); mFaviconBackgroundPaint.setStyle(Paint.Style.FILL); mFaviconBackgroundPaint.setShadowLayer( - context.getResources().getDimension( - R.dimen.tab_grid_thumbnail_favicon_background_radius), - 0, - context.getResources().getDimension( - R.dimen.tab_grid_thumbnail_favicon_background_down_shift), - context.getResources().getColor(R.color.modern_grey_800_alpha_38)); + resource.getDimension(R.dimen.tab_grid_thumbnail_favicon_background_radius), 0, + resource.getDimension(R.dimen.tab_grid_thumbnail_favicon_background_down_shift), + resource.getColor(R.color.modern_grey_800_alpha_38)); // Initialize Rects for thumbnails. - float thumbnailPadding = context.getResources().getDimension(R.dimen.tab_list_card_padding); + float thumbnailPadding = resource.getDimension(R.dimen.tab_list_card_padding); float thumbnailFaviconPadding = - context.getResources().getDimension(R.dimen.tab_grid_thumbnail_favicon_padding); - float thumbnailFaviconBackgroundPadding = context.getResources().getDimension( - R.dimen.tab_grid_thumbnail_favicon_frame_padding); + resource.getDimension(R.dimen.tab_grid_thumbnail_favicon_padding); + float thumbnailFaviconBackgroundPadding = + resource.getDimension(R.dimen.tab_grid_thumbnail_favicon_frame_padding); mThumbnailRects.add(new RectF(thumbnailPadding, thumbnailPadding, mSize / 2 - thumbnailPadding / 2, mSize / 2 - thumbnailPadding / 2));
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabCarouselViewHolder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabCarouselViewHolder.java new file mode 100644 index 0000000..926735e --- /dev/null +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabCarouselViewHolder.java
@@ -0,0 +1,31 @@ +// 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. + +package org.chromium.chrome.browser.tasks.tab_management; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import org.chromium.chrome.tab_ui.R; + +/** + * {@link TabGriViewHolder} for tab carousel. Owns the tab info card + * and the associated view hierarchy. + */ +final class TabCarouselViewHolder extends TabGridViewHolder { + protected TabCarouselViewHolder(View itemView) { + super(itemView); + } + + public static TabGridViewHolder create(ViewGroup parent, int itemViewType) { + final TabGridViewHolder viewHolder = TabGridViewHolder.create(parent, itemViewType); + // TODO(mattsimmons): Make this more dynamic based on parent/recycler view height. + final Context context = parent.getContext(); + viewHolder.itemView.getLayoutParams().width = + context.getResources().getDimensionPixelSize(R.dimen.tab_carousel_card_width); + + return viewHolder; + } +}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinder.java index 627e617..3782d5f6 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinder.java
@@ -14,7 +14,7 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.TOP_PADDING; import static org.chromium.chrome.browser.tasks.tab_management.TabListContainerProperties.VISIBILITY_LISTENER; -import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; import android.widget.FrameLayout; import org.chromium.chrome.browser.util.ColorUtils; @@ -47,7 +47,7 @@ } else if (INITIAL_SCROLL_INDEX == propertyKey) { // RecyclerView#scrollToPosition(int) behaves incorrectly first time after cold start. int index = (Integer) model.get(INITIAL_SCROLL_INDEX); - ((GridLayoutManager) view.getLayoutManager()).scrollToPositionWithOffset(index, 0); + ((LinearLayoutManager) view.getLayoutManager()).scrollToPositionWithOffset(index, 0); } else if (TOP_CONTROLS_HEIGHT == propertyKey) { FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams(); params.topMargin = model.get(TOP_CONTROLS_HEIGHT);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java index ec811e8..f67bd7e4 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewBinder.java
@@ -45,13 +45,11 @@ Resources res = holder.itemView.getResources(); Resources.Theme theme = holder.itemView.getContext().getTheme(); if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { - Drawable selectedDrawable = new InsetDrawable( - ResourcesCompat.getDrawable(res, R.drawable.selected_tab_background, theme), - (int) res.getDimension(R.dimen.tab_list_selected_inset_kitkat)); - Drawable elevationDrawable = - ResourcesCompat.getDrawable(res, R.drawable.popup_bg, theme); - holder.backgroundView.setBackground( - item.get(TabProperties.IS_SELECTED) ? selectedDrawable : elevationDrawable); + if (item.get(TabProperties.IS_SELECTED)) { + holder.selectedViewBelowLollipop.setVisibility(View.VISIBLE); + } else { + holder.selectedViewBelowLollipop.setVisibility(View.GONE); + } } else { Drawable drawable = new InsetDrawable( ResourcesCompat.getDrawable(res, R.drawable.selected_tab_background, theme),
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewHolder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewHolder.java index a492e97..c4047c07 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewHolder.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridViewHolder.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.tasks.tab_management; import android.support.annotation.IntDef; -import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -19,6 +18,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +// TODO(mattsimmons): Rename this to be less `grid` specific since it's used by both GRID and +// CAROUSEL modes. Do the same for the grid layouts inflated in `create`. /** * {@link RecyclerView.ViewHolder} for tab grid. Owns the tab info card * and the associated view hierarchy. @@ -37,6 +38,8 @@ public final ImageView thumbnail; public final ButtonCompat createGroupButton; public final View backgroundView; + public final View selectedViewBelowLollipop; + public final View dividerView; public final ImageView actionButton; private int mTabId; @@ -45,13 +48,12 @@ super(itemView); this.thumbnail = itemView.findViewById(R.id.tab_thumbnail); this.title = itemView.findViewById(R.id.tab_title); - // TODO(yuezhanggg): Remove this when the strip is properly tinted. (crbug/939915) - title.setTextColor( - ContextCompat.getColor(itemView.getContext(), R.color.default_text_color_dark)); this.favicon = itemView.findViewById(R.id.tab_favicon); this.actionButton = itemView.findViewById(R.id.action_button); this.createGroupButton = itemView.findViewById(R.id.create_group_button); this.backgroundView = itemView.findViewById(R.id.background_view); + this.selectedViewBelowLollipop = itemView.findViewById(R.id.selected_view_below_lollipop); + this.dividerView = itemView.findViewById(R.id.divider_view); } public static TabGridViewHolder create(ViewGroup parent, int itemViewType) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java index d626a23e..85bcfa3 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java
@@ -7,7 +7,6 @@ import android.content.Context; import android.content.res.ColorStateList; import android.support.v4.widget.TextViewCompat; -import android.support.v7.content.res.AppCompatResources; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; @@ -89,7 +88,6 @@ */ void setupDialogToolbarLayout() { Context context = getContext(); - setBackground(AppCompatResources.getDrawable(context, R.drawable.tab_grid_card_background)); mLeftButton.setImageResource(org.chromium.chrome.R.drawable.ic_arrow_back_24dp); int topicMargin = (int) context.getResources().getDimension(R.dimen.tab_group_toolbar_topic_margin);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java index 8c6eb5e8..a5653f4 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
@@ -37,20 +37,27 @@ * Coordinator for showing UI for a list of tabs. Can be used in GRID or STRIP modes. */ public class TabListCoordinator implements Destroyable { - /** Modes of showing the list of tabs */ - @IntDef({TabListMode.GRID, TabListMode.STRIP}) + /** + * Modes of showing the list of tabs. + * + * NOTE: CAROUSEL mode currently uses a fixed height and card width set in dimens.xml with names + * tab_carousel_height and tab_carousel_card_width. + * + * STRIP and GRID modes will have height equal to that of the container view. + * */ + @IntDef({TabListMode.GRID, TabListMode.STRIP, TabListMode.CAROUSEL}) @Retention(RetentionPolicy.SOURCE) public @interface TabListMode { int GRID = 0; int STRIP = 1; - int NUM_ENTRIES = 2; + int CAROUSEL = 2; + int NUM_ENTRIES = 3; } static final int GRID_LAYOUT_SPAN_COUNT_PORTRAIT = 2; static final int GRID_LAYOUT_SPAN_COUNT_LANDSCAPE = 3; private final SimpleRecyclerViewMcpBase mModelChangeProcessor; private final TabListMediator mMediator; - private final TabModelSelector mTabModelSelector; private final TabListRecyclerView mRecyclerView; private final @TabListMode int mMode; private final Rect mThumbnailLocationOfCurrentTab = new Rect(); @@ -96,10 +103,9 @@ boolean attachToParent, String componentName) { TabListModel tabListModel = new TabListModel(); mMode = mode; - mTabModelSelector = tabModelSelector; RecyclerViewAdapter adapter; - if (mMode == TabListMode.GRID) { + if (mMode == TabListMode.GRID || mMode == TabListMode.CAROUSEL) { if (itemViewTypeCallback == null) { itemViewTypeCallback = mGridDefaultItemViewTypeCallback; } @@ -113,7 +119,11 @@ viewHolder.resetThumbnail(); } }; - adapter = new RecyclerViewAdapter<>(mcp, TabGridViewHolder::create); + if (mode == TabListMode.CAROUSEL) { + adapter = new RecyclerViewAdapter<>(mcp, TabCarouselViewHolder::create); + } else { + adapter = new RecyclerViewAdapter<>(mcp, TabGridViewHolder::create); + } mModelChangeProcessor = mcp; } else if (mMode == TabListMode.STRIP) { SimpleRecyclerViewMcpBase<PropertyModel, TabStripViewHolder, PropertyKey> mcp = @@ -135,6 +145,14 @@ mRecyclerView = parentView.findViewById(R.id.tab_list_view); } + if (mode == TabListMode.CAROUSEL) { + // TODO(mattsimmons): Remove this height and let the parent determine the correct + // height. This can be done once the width is dynamic as well in + // TabCarouselViewHolder. + mRecyclerView.getLayoutParams().height = + context.getResources().getDimensionPixelSize(R.dimen.tab_carousel_height); + } + mRecyclerView.setAdapter(adapter); if (mMode == TabListMode.GRID) { @@ -143,7 +161,7 @@ == Configuration.ORIENTATION_PORTRAIT ? GRID_LAYOUT_SPAN_COUNT_PORTRAIT : GRID_LAYOUT_SPAN_COUNT_LANDSCAPE)); - } else if (mMode == TabListMode.STRIP) { + } else if (mMode == TabListMode.STRIP || mMode == TabListMode.CAROUSEL) { mRecyclerView.setLayoutManager( new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)); } @@ -170,9 +188,6 @@ touchHelper.attachToRecyclerView(mRecyclerView); mMediator.registerOrientationListener( (GridLayoutManager) mRecyclerView.getLayoutManager()); - touchHelper.attachToRecyclerView(mRecyclerView); - mMediator.registerOrientationListener( - (GridLayoutManager) mRecyclerView.getLayoutManager()); } if (actionOnRelatedTabs) {
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java index 45457ec..4404768 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java
@@ -8,7 +8,9 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; +import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; +import android.support.annotation.ColorInt; import android.support.v7.content.res.AppCompatResources; import org.chromium.base.Callback; @@ -27,6 +29,9 @@ private final int mFaviconSize; private final Profile mProfile; private final FaviconHelper mFaviconHelper; + private final Context mContext; + @ColorInt + private final int mDefaultIconColor; /** * Construct the provider that provides favicons for tab list. @@ -34,6 +39,7 @@ * @param profile The profile to use for getting favicons. */ public TabListFaviconProvider(Context context, Profile profile) { + mContext = context; mFaviconSize = context.getResources().getDimensionPixelSize(R.dimen.default_favicon_size); mProfile = profile; mFaviconHelper = new FaviconHelper(); @@ -52,6 +58,7 @@ BitmapFactory.decodeResource(context.getResources(), R.drawable.chromelogo16); sRoundedChromeDrawable = processBitmap(chromeBitmap); } + mDefaultIconColor = mContext.getResources().getColor(R.color.default_icon_color); } private Drawable processBitmap(Bitmap bitmap) { @@ -64,7 +71,7 @@ * @return The scaled rounded Globe Drawable as default favicon. */ public Drawable getDefaultFaviconDrawable() { - return sRoundedGlobeDrawable; + return getRoundedGlobeDrawable(); } /** @@ -76,12 +83,12 @@ public void getFaviconForUrlAsync( String url, boolean isIncognito, Callback<Drawable> faviconCallback) { if (NativePageFactory.isNativePageUrl(url, isIncognito)) { - faviconCallback.onResult(sRoundedChromeDrawable); + faviconCallback.onResult(getRoundedChromeDrawable()); } else { mFaviconHelper.getLocalFaviconImageForURL( mProfile, url, mFaviconSize, (image, iconUrl) -> { if (image == null) { - faviconCallback.onResult(sRoundedGlobeDrawable); + faviconCallback.onResult(getRoundedGlobeDrawable()); } else { faviconCallback.onResult(processBitmap(image)); } @@ -99,9 +106,25 @@ public Drawable getFaviconForUrlSync(String url, boolean isIncognito, Bitmap icon) { if (icon == null) { boolean isNativeUrl = NativePageFactory.isNativePageUrl(url, isIncognito); - return isNativeUrl ? sRoundedChromeDrawable : sRoundedGlobeDrawable; + return isNativeUrl ? getRoundedChromeDrawable() : getRoundedGlobeDrawable(); } else { return processBitmap(icon); } } + + private Drawable getRoundedChromeDrawable() { + // Since static variable is still loaded when activity is destroyed due to configuration + // changes, e.g. light/dark theme changes, setColorFilter is needed when we retrieve the + // drawable. setColorFilter would be a no-op if color and the mode are the same. + sRoundedChromeDrawable.setColorFilter(mDefaultIconColor, PorterDuff.Mode.SRC_IN); + return sRoundedChromeDrawable; + } + + private Drawable getRoundedGlobeDrawable() { + // Since static variable is still loaded when activity is destroyed due to configuration + // changes, e.g. light/dark theme changes, setColorFilter is needed when we retrieve the + // drawable. setColorFilter would be a no-op if color and the mode are the same. + sRoundedGlobeDrawable.setColorFilter(mDefaultIconColor, PorterDuff.Mode.SRC_IN); + return sRoundedGlobeDrawable; + } }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java index 0825136c..b77e3bd 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java
@@ -9,7 +9,10 @@ import org.chromium.chrome.browser.snackbar.Snackbar; import org.chromium.chrome.browser.snackbar.SnackbarManager; import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; +import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter; import org.chromium.chrome.tab_ui.R; @@ -27,6 +30,7 @@ private final TabModelSelector mTabModelSelector; private final SnackbarManager.SnackbarManageable mSnackbarManageable; private final TabGroupModelFilter.Observer mTabGroupModelFilterObserver; + private final TabModelSelectorObserver mTabModelSelectorObserver; private class TabUndoInfo { public final Tab tab; @@ -82,6 +86,32 @@ ((TabGroupModelFilter) mTabModelSelector.getTabModelFilterProvider().getTabModelFilter( true)) .addTabGroupObserver(mTabGroupModelFilterObserver); + + mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() { + @Override + public void onTabModelSelected(TabModel newModel, TabModel oldModel) { + mSnackbarManageable.getSnackbarManager().dismissSnackbars( + UndoGroupSnackbarController.this); + } + }; + + mTabModelSelector.addObserver(mTabModelSelectorObserver); + } + + /** + * Cleans up this class, removes {@link TabModelSelectorObserver} from {@link TabModelSelector} + * and {@link TabGroupModelFilter.Observer} from {@link TabGroupModelFilter}. + */ + public void destroy() { + if (mTabModelSelector != null) { + mTabModelSelector.removeObserver(mTabModelSelectorObserver); + ((TabGroupModelFilter) mTabModelSelector.getTabModelFilterProvider().getTabModelFilter( + false)) + .removeTabGroupObserver(mTabGroupModelFilterObserver); + ((TabGroupModelFilter) mTabModelSelector.getTabModelFilterProvider().getTabModelFilter( + true)) + .removeTabGroupObserver(mTabGroupModelFilterObserver); + } } private void showUndoGroupSnackbar(List<TabUndoInfo> tabUndoInfo) {
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java index 0ffca61..35dcd7b 100644 --- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java +++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java
@@ -12,10 +12,10 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.graphics.drawable.InsetDrawable; import android.os.Build; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.MediumTest; +import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.LinearLayout; @@ -145,14 +145,10 @@ Assert.assertFalse(((FrameLayout) (holder.itemView)).getForeground() != null); } else { model.set(TabProperties.IS_SELECTED, true); - Drawable selectedDrawable = - holder.itemView.findViewById(R.id.background_view).getBackground(); - Assert.assertTrue(selectedDrawable != null); + View selectedView = holder.itemView.findViewById(R.id.selected_view_below_lollipop); + Assert.assertTrue(selectedView.getVisibility() == View.VISIBLE); model.set(TabProperties.IS_SELECTED, false); - Drawable elevationDrawable = - holder.itemView.findViewById(R.id.background_view).getBackground(); - Assert.assertTrue(elevationDrawable != null); - Assert.assertNotSame(selectedDrawable, elevationDrawable); + Assert.assertTrue(selectedView.getVisibility() == View.GONE); } mStripModel.set(TabProperties.IS_SELECTED, true); Assert.assertTrue(((FrameLayout) (mTabStripViewHolder.itemView)).getForeground() != null); @@ -186,6 +182,8 @@ @Test @MediumTest public void testAnimationRestored() throws Exception { + View backgroundView = mTabGridViewHolder.itemView.findViewById(R.id.background_view); + TestThreadUtils.runOnUiThreadBlocking(() -> { mGridModel.set(TabProperties.IS_SELECTED, true); mGridModel.set(TabProperties.CARD_ANIMATION_STATUS, @@ -193,9 +191,16 @@ }); CriteriaHelper.pollUiThread( () -> !((ClosableTabGridViewHolder) mTabGridViewHolder).getIsAnimatingForTesting()); - Drawable selectedTabRestoredBackground = - mTabGridViewHolder.itemView.findViewById(R.id.background_view).getBackground(); - Assert.assertNotNull(selectedTabRestoredBackground); + + Assert.assertTrue(backgroundView.getVisibility() == View.GONE); + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { + View selectedView = + mTabGridViewHolder.itemView.findViewById(R.id.selected_view_below_lollipop); + Assert.assertTrue(selectedView.getVisibility() == View.VISIBLE); + } else { + Drawable selectedDrawable = mTabGridViewHolder.itemView.getForeground(); + Assert.assertNotNull(selectedDrawable); + } TestThreadUtils.runOnUiThreadBlocking(() -> { mGridModel.set(TabProperties.IS_SELECTED, false); @@ -204,19 +209,15 @@ }); CriteriaHelper.pollUiThread( () -> !((ClosableTabGridViewHolder) mTabGridViewHolder).getIsAnimatingForTesting()); - Drawable normalTabRestoredBackground = - mTabGridViewHolder.itemView.findViewById(R.id.background_view).getBackground(); - Assert.assertNotNull(normalTabRestoredBackground); + Assert.assertTrue(backgroundView.getVisibility() == View.GONE); - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { - // After restoring, the background should be the same because for post-M devices, the - // selected state is reflected through foreground and the background is always the same. - Assert.assertSame(selectedTabRestoredBackground, normalTabRestoredBackground); + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { + View selectedView = + mTabGridViewHolder.itemView.findViewById(R.id.selected_view_below_lollipop); + Assert.assertTrue(selectedView.getVisibility() == View.GONE); } else { - // For pre-M devices, after restoring, the background should still reflect the selection - // status. - Assert.assertTrue(selectedTabRestoredBackground instanceof InsetDrawable); - Assert.assertNotSame(normalTabRestoredBackground, selectedTabRestoredBackground); + Drawable selectedDrawable = mTabGridViewHolder.itemView.getForeground(); + Assert.assertNull(selectedDrawable); } }
diff --git a/chrome/android/features/vr/java/AndroidManifest.xml b/chrome/android/features/vr/java/AndroidManifest.xml index 4a2c233..388353f7 100644 --- a/chrome/android/features/vr/java/AndroidManifest.xml +++ b/chrome/android/features/vr/java/AndroidManifest.xml
@@ -8,9 +8,17 @@ featureSplit="vr"> <dist:module - dist:onDemand="true" - dist:title="@string/vr_module_title"> - <dist:fusing dist:include="false" /> + dist:instant="false" + dist:title="@string/vr_module_title"> + <dist:fusing dist:include="false" /> + <dist:delivery> + <dist:install-time> + <dist:conditions> + <dist:device-feature dist:name="android.hardware.vr.high_performance" /> + </dist:conditions> + </dist:install-time> + <dist:on-demand /> + </dist:delivery> </dist:module> <application>
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index c186f5e..dd75dd5b 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -77,6 +77,9 @@ <uses-feature android:name="android.hardware.screen.landscape" android:required="false"/> <!-- Indicates that head tracking should be done in 6DoF, if available --> <uses-feature android:name="android.hardware.vr.headtracking" android:version="1" android:required="false"/> + <!-- Feature declarations required to support conditional install for VR DFM --> + <uses-feature android:name="android.hardware.sensor.gyroscope" android:required="false"/> + <uses-feature android:name="android.hardware.sensor.accelerometer" android:required="false"/> {% endif %} <permission android:name="{{ manifest_package }}.permission.CHILD_SERVICE" android:protectionLevel="signature" />
diff --git a/chrome/android/java/monochrome_public_bundle.proguard_flags.expected b/chrome/android/java/monochrome_public_bundle.proguard_flags.expected index 7b7d0d25..7b9307d 100644 --- a/chrome/android/java/monochrome_public_bundle.proguard_flags.expected +++ b/chrome/android/java/monochrome_public_bundle.proguard_flags.expected
@@ -292,11 +292,6 @@ # Fragments loaded by name via Fragment.instantiate(Context,String) # Not all fragments in this package are PreferenceFragments. E.g. HomepageEditor # is a normal Fragment. -# TODO(crbug.com/967022): Remove the android.app.Fragment rule once all -# Fragments have been migrated to the support library. --keep public class org.chromium.chrome.browser.** extends android.app.Fragment { - public <init>(); -} -keep public class org.chromium.chrome.browser.preferences.** extends android.support.v4.app.Fragment { public <init>(); }
diff --git a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected index 5eae1d0..441a2a3b4d 100644 --- a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected +++ b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
@@ -51,6 +51,8 @@ android:required="false" android:version="1"/> <uses-feature android:name="android.hardware.touchscreen" android:required="false"/> + <uses-feature android:name="android.hardware.sensor.gyroscope" android:required="false"/> + <uses-feature android:name="android.hardware.sensor.accelerometer" android:required="false"/> <uses-feature android:name="android.hardware.screen.landscape" android:required="false"/> <uses-feature android:name="android.hardware.microphone" android:required="false"/> <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
diff --git a/chrome/android/java/proguard.flags b/chrome/android/java/proguard.flags index e1d86756..0cd07a3 100644 --- a/chrome/android/java/proguard.flags +++ b/chrome/android/java/proguard.flags
@@ -5,11 +5,6 @@ # Fragments loaded by name via Fragment.instantiate(Context,String) # Not all fragments in this package are PreferenceFragments. E.g. HomepageEditor # is a normal Fragment. -# TODO(crbug.com/967022): Remove the android.app.Fragment rule once all -# Fragments have been migrated to the support library. --keep public class org.chromium.chrome.browser.** extends android.app.Fragment { - public <init>(); -} -keep public class org.chromium.chrome.browser.preferences.** extends android.support.v4.app.Fragment { public <init>(); }
diff --git a/chrome/android/java/res/layout/context_menu_divider.xml b/chrome/android/java/res/layout/context_menu_divider.xml index a1dd372..51785dc 100644 --- a/chrome/android/java/res/layout/context_menu_divider.xml +++ b/chrome/android/java/res/layout/context_menu_divider.xml
@@ -5,6 +5,7 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingTop="@dimen/revamped_context_menu_divider_padding" android:paddingBottom="@dimen/revamped_context_menu_divider_padding">
diff --git a/chrome/android/java/res/layout/preference_switch.xml b/chrome/android/java/res/layout/preference_switch.xml deleted file mode 100644 index 4e8a4bc..0000000 --- a/chrome/android/java/res/layout/preference_switch.xml +++ /dev/null
@@ -1,13 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2014 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. --> - -<android.support.v7.widget.SwitchCompat - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/switch_widget" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:focusable="false" - android:clickable="false" - android:background="@null" />
diff --git a/chrome/android/java/res/layout/revamped_context_menu_header.xml b/chrome/android/java/res/layout/revamped_context_menu_header.xml index 2cdbba33..2fe64d0 100644 --- a/chrome/android/java/res/layout/revamped_context_menu_header.xml +++ b/chrome/android/java/res/layout/revamped_context_menu_header.xml
@@ -38,7 +38,7 @@ android:scaleType="centerInside" android:importantForAccessibility="no" android:layout_marginTop="@dimen/revamped_context_menu_header_vertical_padding" - android:layout_marginBottom="@dimen/revamped_context_menu_header_vertical_padding" + android:layout_marginBottom="@dimen/revamped_context_menu_bottom_padding" app:cornerRadiusTopStart="@dimen/default_rounded_corner_radius" app:cornerRadiusTopEnd="@dimen/default_rounded_corner_radius" app:cornerRadiusBottomStart="@dimen/default_rounded_corner_radius" @@ -53,7 +53,7 @@ android:orientation="vertical" android:layout_gravity="center_vertical" android:paddingTop="@dimen/revamped_context_menu_header_vertical_padding" - android:paddingBottom="@dimen/revamped_context_menu_header_vertical_padding"> + android:paddingBottom="@dimen/revamped_context_menu_bottom_padding"> <org.chromium.ui.widget.TextViewWithLeading android:id="@+id/menu_header_title"
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml index 1d52cede..5b41c992 100644 --- a/chrome/android/java/res/values-v17/styles.xml +++ b/chrome/android/java/res/values-v17/styles.xml
@@ -962,31 +962,6 @@ <item name="android:textColor">@color/suggestion_url_dark_modern</item> </style> - <style name="TextAppearance.OmniboxAnswerTextLarge"> - <item name="android:textSize">24sp</item> - <item name="android:textColor">@color/answers_answer_text</item> - </style> - - <style name="TextAppearance.OmniboxAnswerTextMedium"> - <item name="android:textSize">20sp</item> - <item name="android:textColor">@color/answers_answer_text</item> - </style> - - <style name="TextAppearance.OmniboxAnswerTextSmall"> - <item name="android:textSize">@dimen/text_size_small</item> - <item name="android:textColor">@color/answers_answer_text</item> - </style> - - <style name="TextAppearance.OmniboxAnswerDescriptionNegative"> - <item name="android:textSize">@dimen/text_size_large</item> - <item name="android:textColor">@color/answers_description_text_negative</item> - </style> - - <style name="TextAppearance.OmniboxAnswerDescriptionPositive"> - <item name="android:textSize">@dimen/text_size_large</item> - <item name="android:textColor">@color/answers_description_text_positive</item> - </style> - <style name="TextAppearance.OmniboxAnswerDescriptionNegativeSmall"> <item name="android:textSize">@dimen/text_size_small</item> <item name="android:textColor">@color/answers_description_text_negative</item>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml index 94e8ca49..d2ca0cf 100644 --- a/chrome/android/java/res/values/colors.xml +++ b/chrome/android/java/res/values/colors.xml
@@ -70,7 +70,6 @@ <color name="suggestion_url_light_modern">@color/modern_blue_300</color> <color name="answers_description_text_negative">@color/default_red</color> <color name="answers_description_text_positive">@color/default_green</color> - <color name="answers_answer_text">#8A8A8A</color> <!-- Distilled Page Prefs colors --> <color name="distilled_page_prefs_selected">#999999</color>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java index 5f46ae4..46f734b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -2110,7 +2110,7 @@ } if (id == R.id.preferences_id) { - PreferencesLauncher.launchSettingsPage(this, null); + PreferencesLauncher.launchSettingsPageCompat(this, null); RecordUserAction.record("MobileMenuSettings"); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index 72784eb..39ff630 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -277,7 +277,6 @@ "OmniboxUIExperimentHideSteadyStateUrlScheme"; public static final String OMNIBOX_HIDE_TRIVIAL_SUBDOMAINS_IN_STEADY_STATE = "OmniboxUIExperimentHideSteadyStateUrlTrivialSubdomains"; - public static final String OMNIBOX_NEW_ANSWER_LAYOUT = "OmniboxNewAnswerLayout"; public static final String OMNIBOX_RICH_ENTITY_SUGGESTIONS = "OmniboxRichEntitySuggestions"; public static final String OMNIBOX_SHOW_SUGGESTION_FAVICONS = "OmniboxUIExperimentShowSuggestionFavicons";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java index 92bb9ec..9135e3e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkManager.java
@@ -144,6 +144,8 @@ class BookmarkDragStateDelegate implements DragStateDelegate { private BookmarkDelegate mBookmarkDelegate; private SelectionDelegate<BookmarkId> mSelectionDelegate; + private AccessibilityManager mA11yManager; + private AccessibilityManager.AccessibilityStateChangeListener mA11yChangeListener; private boolean mA11yEnabled; void onBookmarkDelegateInitialized(BookmarkDelegate delegate) { @@ -151,11 +153,12 @@ mSelectionDelegate = delegate.getSelectionDelegate(); - AccessibilityManager a11yManager = + mA11yManager = (AccessibilityManager) getSelectableListLayout().getContext().getSystemService( Context.ACCESSIBILITY_SERVICE); - mA11yEnabled = a11yManager.isEnabled(); - a11yManager.addAccessibilityStateChangeListener(enabled -> mA11yEnabled = enabled); + mA11yEnabled = mA11yManager.isEnabled(); + mA11yChangeListener = enabled -> mA11yEnabled = enabled; + mA11yManager.addAccessibilityStateChangeListener(mA11yChangeListener); } // DragStateDelegate implementation @@ -169,6 +172,17 @@ public boolean getDragActive() { return getDragEnabled() && mSelectionDelegate.isSelectionEnabled(); } + + @VisibleForTesting + @Override + public void setA11yStateForTesting(boolean a11yEnabled) { + if (mA11yManager != null) { + mA11yManager.removeAccessibilityStateChangeListener(mA11yChangeListener); + } + mA11yChangeListener = null; + mA11yManager = null; + mA11yEnabled = a11yEnabled; + } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java index 0dadf40..63ad015 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkRow.java
@@ -7,6 +7,7 @@ import android.content.Context; import android.support.annotation.IntDef; import android.util.AttributeSet; +import android.view.View; import android.widget.ImageView; import org.chromium.base.VisibleForTesting; @@ -39,6 +40,8 @@ @Location private int mLocation; + private static final String TAG = "BookmarkRow"; + @IntDef({Location.TOP, Location.MIDDLE, Location.BOTTOM}) @Retention(RetentionPolicy.SOURCE) public @interface Location { @@ -57,6 +60,7 @@ /** * Updates this row for the given {@link BookmarkId}. + * * @return The {@link BookmarkItem} corresponding the given {@link BookmarkId}. */ // TODO(crbug.com/160194): Clean up these 2 functions after bookmark reordering launches. @@ -77,7 +81,7 @@ * within the list of bookmarks. * * @param bookmarkId The BookmarkId that this BookmarkRow now contains. - * @param location The location of this BookmarkRow. + * @param location The location of this BookmarkRow. * @return The BookmarkItem corresponding to BookmarkId. */ BookmarkItem setBookmarkId(BookmarkId bookmarkId, @Location int location) { @@ -87,26 +91,31 @@ private void updateVisualState() { BookmarkItem bookmarkItem = mDelegate.getModel().getBookmarkById(mBookmarkId); + // This check is needed because updateVisualState is called when the item has been deleted + // in the model but not in the adapter. If we hit this if-block, the + // item is about to be deleted, and we don't need to do anything. + if (bookmarkItem == null) { + return; + } + // TODO(jhimawan): Look into using cleanup(). Perhaps unhook the selection state observer? + // If the visibility of the drag handle or more icon is not set later, it will be gone. mDragHandle.setVisibility(GONE); mMoreIcon.setVisibility(GONE); - if (mReorderBookmarksEnabled) { - if (mDelegate.getDragStateDelegate().getDragActive()) { - mDragHandle.setVisibility(bookmarkItem.isEditable() ? VISIBLE : GONE); - mDragHandle.setEnabled(isItemSelected()); - } else { - mMoreIcon.setVisibility(bookmarkItem.isEditable() ? VISIBLE : GONE); - mMoreIcon.setEnabled(isSelectionModeActive()); - } + if (mReorderBookmarksEnabled && mDelegate.getDragStateDelegate().getDragActive()) { + mDragHandle.setVisibility(bookmarkItem.isEditable() ? VISIBLE : GONE); + mDragHandle.setEnabled(isItemSelected()); } else { - // Bookmark reordering is off mMoreIcon.setVisibility(bookmarkItem.isEditable() ? VISIBLE : GONE); + mMoreIcon.setClickable(!isSelectionModeActive()); + mMoreIcon.setEnabled(mMoreIcon.isClickable()); } } /** * Sets the delegate to use to handle UI actions related to this view. + * * @param delegate A {@link BookmarkDelegate} instance to handle all backend interaction. */ public void onDelegateInitialized(BookmarkDelegate delegate) { @@ -117,7 +126,6 @@ private void initialize() { mDelegate.addUIObserver(this); - updateSelectionState(); } private void cleanup() { @@ -125,10 +133,6 @@ if (mDelegate != null) mDelegate.removeUIObserver(this); } - private void updateSelectionState() { - mMoreIcon.setEnabled(!mDelegate.getSelectionDelegate().isSelectionEnabled()); - } - // PopupMenuItem.Delegate implementation. @Override public Item[] getItems() { @@ -226,7 +230,7 @@ @Override public void onSelectionStateChange(List<BookmarkId> selectedBookmarks) { super.onSelectionStateChange(selectedBookmarks); - updateSelectionState(); + updateVisualState(); } // BookmarkUIObserver implementation. @@ -253,4 +257,29 @@ String getTitle() { return String.valueOf(mTitleView.getText()); } -} + + private boolean isDragActive() { + if (mReorderBookmarksEnabled) { + return mDelegate.getDragStateDelegate().getDragActive(); + } + return false; + } + + @Override + public boolean onLongClick(View view) { + // Override is needed in order to support long-press-to-drag on already-selected items. + if (isDragActive() && isItemSelected()) return true; + return super.onLongClick(view); + } + + @Override + public void onClick(View view) { + // Override is needed in order to allow items to be selected / deselected with a click. + // Since we override #onLongClick(), we cannot rely on the base class for this behavior. + if (isDragActive()) { + toggleSelectionForItem(getItem()); + } else { + super.onClick(view); + } + } +} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReorderBookmarkItemsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReorderBookmarkItemsAdapter.java index 41428d84..348e68cf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReorderBookmarkItemsAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/ReorderBookmarkItemsAdapter.java
@@ -121,13 +121,10 @@ } private void setBookmarks(List<BookmarkId> bookmarks) { - // Update header in order to determine whether we have a Promo Header. - // Must be done before adding in all of our elements. - updateHeader(); mElements.clear(); - if (hasPromoHeader()) { - mElements.add(null); - } + // Restore the header, if it exists, then update it. + if (hasPromoHeader()) mElements.add(null); + updateHeader(false); for (BookmarkId bId : bookmarks) { mElements.add(mDelegate.getModel().getBookmarkById(bId)); } @@ -161,7 +158,7 @@ // ViewHolder is abstract and it cannot be instantiated directly. ViewHolder holder = new ViewHolder(row) {}; - ((BookmarkRow) holder.itemView).onDelegateInitialized(mDelegate); + ((BookmarkRow) row).onDelegateInitialized(mDelegate); return holder; } @@ -223,28 +220,9 @@ mDelegate = delegate; mDelegate.addUIObserver(this); mDelegate.getModel().addObserver(mBookmarkModelObserver); - // This must be registered directly with the selection delegate. - // addUIObserver (see above) is not sufficient. - // TODO(jhimawan): figure out why this is the case. - mDelegate.getSelectionDelegate().addObserver(ReorderBookmarkItemsAdapter.this); Runnable promoHeaderChangeAction = () -> { - assert mDelegate != null; - if (mDelegate.getCurrentState() != BookmarkUIState.STATE_FOLDER) { - return; - } - - boolean wasShowingPromo = hasPromoHeader(); - updateHeader(); - boolean willShowPromo = hasPromoHeader(); - - if (!wasShowingPromo && willShowPromo) { - notifyItemInserted(0); - } else if (wasShowingPromo && willShowPromo) { - notifyItemChanged(0); - } else if (wasShowingPromo && !willShowPromo) { - notifyItemRemoved(0); - } + updateHeader(true); }; mPromoHeaderManager = new BookmarkPromoHeader(mContext, promoHeaderChangeAction); @@ -284,14 +262,14 @@ @Override public void onSearchStateSet() { disableDrag(); - updateHeader(); + // Headers should not appear in Search mode + // Don't need to notify because we need to redraw everything in the next step + updateHeader(false); notifyDataSetChanged(); } @Override - public void onSelectionStateChange(List<BookmarkId> selectedBookmarks) { - notifyDataSetChanged(); - } + public void onSelectionStateChange(List<BookmarkId> selectedBookmarks) {} /** * Refresh the list of bookmarks within the currently visible folder. @@ -350,33 +328,52 @@ setOrder(mElements); } - private void updateHeader() { + /** + * Updates mPromoHeaderType. Makes sure that the 0th index of mElements is consistent with the + * promo header. This 0th index is null iff there is a promo header. + * + * @param shouldNotify True iff we should notify the RecyclerView of changes to the promoheader. + * (This should be false iff we are going to make further changes to the + * list of elements, as we do in setBookmarks, and true iff we are only + * changing the header, as we do in the promoHeaderChangeAction runnable). + */ + private void updateHeader(boolean shouldNotify) { if (mDelegate == null) return; - int currentUIState = mDelegate.getCurrentState(); - if (currentUIState == BookmarkUIState.STATE_LOADING) return; + boolean wasShowingPromo = hasPromoHeader(); - // Reset the promo header and get rid of the Promo Header placeholder inside of mElements. - if (hasPromoHeader()) { - mElements.remove(0); + int currentUIState = mDelegate.getCurrentState(); + if (currentUIState == BookmarkUIState.STATE_LOADING) { + return; + } else if (currentUIState == BookmarkUIState.STATE_SEARCHING) { mPromoHeaderType = ViewType.INVALID_PROMO; + } else { + switch (mPromoHeaderManager.getPromoState()) { + case BookmarkPromoHeader.PromoState.PROMO_NONE: + mPromoHeaderType = ViewType.INVALID_PROMO; + break; + case BookmarkPromoHeader.PromoState.PROMO_SIGNIN_PERSONALIZED: + mPromoHeaderType = ViewType.PERSONALIZED_SIGNIN_PROMO; + break; + case BookmarkPromoHeader.PromoState.PROMO_SYNC: + mPromoHeaderType = ViewType.SYNC_PROMO; + break; + default: + assert false : "Unexpected value for promo state!"; + } } - if (currentUIState == BookmarkUIState.STATE_SEARCHING) return; + boolean willShowPromo = hasPromoHeader(); - assert currentUIState == BookmarkUIState.STATE_FOLDER : "Unexpected UI state"; - - switch (mPromoHeaderManager.getPromoState()) { - case BookmarkPromoHeader.PromoState.PROMO_NONE: - return; - case BookmarkPromoHeader.PromoState.PROMO_SIGNIN_PERSONALIZED: - mPromoHeaderType = ViewType.PERSONALIZED_SIGNIN_PROMO; - return; - case BookmarkPromoHeader.PromoState.PROMO_SYNC: - mPromoHeaderType = ViewType.SYNC_PROMO; - return; - default: - assert false : "Unexpected value for promo state!"; + if (!wasShowingPromo && willShowPromo) { + // A null element at the 0th index represents a promo header. + mElements.add(0, null); + if (shouldNotify) notifyItemInserted(0); + } else if (wasShowingPromo && willShowPromo) { + if (shouldNotify) notifyItemChanged(0); + } else if (wasShowingPromo && !willShowPromo) { + mElements.remove(0); + if (shouldNotify) notifyItemRemoved(0); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceObservers.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceObservers.java index 8e0e26f..78e2943 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceObservers.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadForegroundServiceObservers.java
@@ -136,28 +136,11 @@ @Nullable private static Observer getObserverFromClassName(String observerClassName) { - if (observerClassName == null) return null; - - Class<?> observerClass; try { - observerClass = Class.forName(observerClassName); - } catch (ClassNotFoundException e) { - Log.w(TAG, "Unable to find observer class with name " + observerClassName); - return null; - } - - if (!Observer.class.isAssignableFrom(observerClass)) { - Log.w(TAG, "Class " + observerClass + " is not an observer"); - return null; - } - - try { + Class<?> observerClass = Class.forName(observerClassName); return (Observer) observerClass.newInstance(); - } catch (InstantiationException e) { - Log.w(TAG, "Unable to instantiate class (InstExc) " + observerClass); - return null; - } catch (IllegalAccessException e) { - Log.w(TAG, "Unable to instantiate class (IllAccExc) " + observerClass); + } catch (Throwable e) { + Log.w(TAG, "getObserverFromClassName(): %s", observerClassName, e); return null; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java index f40a7de5..555f389a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -167,9 +167,15 @@ .record(type); recordNotificationAgeHistogram("Mobile.SystemNotification.Content.Click.Age", createTime); - if (type == SystemNotificationType.SEND_TAB_TO_SELF) { - recordNotificationAgeHistogram( - "Mobile.SystemNotification.Content.Click.Age.SendTabToSelf", createTime); + switch (type) { + case SystemNotificationType.SEND_TAB_TO_SELF: + recordNotificationAgeHistogram( + "Mobile.SystemNotification.Content.Click.Age.SendTabToSelf", createTime); + break; + case SystemNotificationType.CLICK_TO_CALL: + recordNotificationAgeHistogram( + "Mobile.SystemNotification.Content.Click.Age.ClickToCall", createTime); + break; } } @@ -189,9 +195,15 @@ .record(type); recordNotificationAgeHistogram("Mobile.SystemNotification.Dismiss.Age", createTime); - if (type == SystemNotificationType.SEND_TAB_TO_SELF) { - recordNotificationAgeHistogram( - "Mobile.SystemNotification.Dismiss.Age.SendTabToSelf", createTime); + switch (type) { + case SystemNotificationType.SEND_TAB_TO_SELF: + recordNotificationAgeHistogram( + "Mobile.SystemNotification.Dismiss.Age.SendTabToSelf", createTime); + break; + case SystemNotificationType.CLICK_TO_CALL: + recordNotificationAgeHistogram( + "Mobile.SystemNotification.Dismiss.Age.ClickToCall", createTime); + break; } } @@ -213,9 +225,15 @@ .record(actionType); recordNotificationAgeHistogram("Mobile.SystemNotification.Action.Click.Age", createTime); - if (notificationType == SystemNotificationType.SEND_TAB_TO_SELF) { - recordNotificationAgeHistogram( - "Mobile.SystemNotification.Action.Click.Age.SendTabToSelf", createTime); + switch (notificationType) { + case SystemNotificationType.SEND_TAB_TO_SELF: + recordNotificationAgeHistogram( + "Mobile.SystemNotification.Action.Click.Age.SendTabToSelf", createTime); + break; + case SystemNotificationType.CLICK_TO_CALL: + recordNotificationAgeHistogram( + "Mobile.SystemNotification.Action.Click.Age.ClickToCall", createTime); + break; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessor.java index f0472d1..81ef0c1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerSuggestionProcessor.java
@@ -6,13 +6,9 @@ import android.content.Context; import android.graphics.Bitmap; -import android.util.Pair; -import android.util.TypedValue; -import android.view.View; import org.chromium.base.ThreadUtils; import org.chromium.base.metrics.RecordHistogram; -import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.GlobalDiscardableReferencePool; import org.chromium.chrome.browser.image_fetcher.ImageFetcher; import org.chromium.chrome.browser.image_fetcher.ImageFetcherConfig; @@ -25,9 +21,6 @@ import org.chromium.chrome.browser.omnibox.suggestions.answer.AnswerSuggestionViewProperties.AnswerIcon; import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionHost; import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewDelegate; -import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties; -import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties.SuggestionIcon; -import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties.SuggestionTextContainer; import org.chromium.chrome.browser.util.ConversionUtils; import org.chromium.components.omnibox.AnswerType; import org.chromium.components.omnibox.SuggestionAnswer; @@ -47,7 +40,6 @@ private final SuggestionHost mSuggestionHost; private ImageFetcher mImageFetcher; private final UrlBarEditingTextStateProvider mUrlBarEditingTextProvider; - private boolean mEnableNewAnswerLayout; /** * @param context An Android context. @@ -76,22 +68,16 @@ } @Override - public void onNativeInitialized() { - // Experiment: controls presence of certain answer icon types. - mEnableNewAnswerLayout = - ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_NEW_ANSWER_LAYOUT); - } + public void onNativeInitialized() {} @Override public int getViewTypeId() { - return mEnableNewAnswerLayout ? OmniboxSuggestionUiType.ANSWER_SUGGESTION - : OmniboxSuggestionUiType.DEFAULT; + return OmniboxSuggestionUiType.ANSWER_SUGGESTION; } @Override public PropertyModel createModelForSuggestion(OmniboxSuggestion suggestion) { - return mEnableNewAnswerLayout ? new PropertyModel(AnswerSuggestionViewProperties.ALL_KEYS) - : new PropertyModel(SuggestionViewProperties.ALL_KEYS); + return new PropertyModel(AnswerSuggestionViewProperties.ALL_KEYS); } @Override @@ -100,11 +86,7 @@ SuggestionViewDelegate delegate = mSuggestionHost.createSuggestionViewDelegate(suggestion, position); - if (mEnableNewAnswerLayout) { - setStateForNewSuggestion(model, suggestion, delegate); - } else { - setStateForClassicSuggestion(model, suggestion, delegate); - } + setStateForNewSuggestion(model, suggestion, delegate); } @Override @@ -169,12 +151,7 @@ for (int i = 0; i < currentModels.size(); i++) { PropertyModel currentModel = currentModels.get(i); if (!mSuggestionHost.isActiveModel(currentModel)) continue; - - if (mEnableNewAnswerLayout) { - model.set(AnswerSuggestionViewProperties.ANSWER_IMAGE, bitmap); - } else { - model.set(SuggestionViewProperties.ANSWER_IMAGE, bitmap); - } + model.set(AnswerSuggestionViewProperties.ANSWER_IMAGE, bitmap); didUpdate = true; } if (didUpdate) mSuggestionHost.notifyPropertyModelsChanged(); @@ -182,43 +159,6 @@ } /** - * Sets both lines of the Omnibox suggestion in a basic Suggestion result. - */ - private void setStateForClassicSuggestion( - PropertyModel model, OmniboxSuggestion suggestion, SuggestionViewDelegate delegate) { - AnswerText[] details = AnswerTextClassic.from(mContext, suggestion); - - SuggestionAnswer answer = suggestion.getAnswer(); - if (answer != null) { - model.set(SuggestionViewProperties.HAS_ANSWER_IMAGE, answer.getSecondLine().hasImage()); - } - - model.set(SuggestionViewProperties.IS_ANSWER, true); - model.set(SuggestionViewProperties.DELEGATE, delegate); - - model.set(SuggestionViewProperties.TEXT_LINE_1_SIZING, - Pair.create(TypedValue.COMPLEX_UNIT_SP, details[0].mHeightSp)); - model.set(SuggestionViewProperties.TEXT_LINE_1_TEXT, - new SuggestionTextContainer(details[0].mText)); - model.set(SuggestionViewProperties.TEXT_LINE_1_MAX_LINES, details[0].mMaxLines); - model.set(SuggestionViewProperties.TEXT_LINE_1_TEXT_DIRECTION, View.TEXT_DIRECTION_INHERIT); - - if (details[1] != null) { - model.set(SuggestionViewProperties.TEXT_LINE_2_SIZING, - Pair.create(TypedValue.COMPLEX_UNIT_SP, details[1].mHeightSp)); - model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT, - new SuggestionTextContainer(details[1].mText)); - model.set(SuggestionViewProperties.TEXT_LINE_2_MAX_LINES, details[1].mMaxLines); - model.set(SuggestionViewProperties.TEXT_LINE_2_TEXT_DIRECTION, - View.TEXT_DIRECTION_INHERIT); - } - - model.set(SuggestionViewProperties.SUGGESTION_ICON_TYPE, SuggestionIcon.MAGNIFIER); - - model.set(SuggestionViewProperties.REFINABLE, true); - } - - /** * Sets both lines of the Omnibox suggestion based on an Answers in Suggest result. */ private void setStateForNewSuggestion(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerTextClassic.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerTextClassic.java deleted file mode 100644 index 075ede0..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/answer/AnswerTextClassic.java +++ /dev/null
@@ -1,182 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.omnibox.suggestions.answer; - -import android.content.Context; -import android.graphics.Paint; -import android.support.annotation.StyleRes; -import android.text.TextPaint; -import android.text.style.MetricAffectingSpan; -import android.text.style.TextAppearanceSpan; - -import org.chromium.base.Log; -import org.chromium.chrome.R; -import org.chromium.chrome.browser.omnibox.OmniboxSuggestionType; -import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion; -import org.chromium.components.omnibox.AnswerTextType; -import org.chromium.components.omnibox.SuggestionAnswer; - -/** - * AnswerTextNewLayout builds Omnibox styled Answer suggestion texts for classic answer layouts. - */ -class AnswerTextClassic extends AnswerText { - private static final String TAG = "AnswerTextClassic"; - - /** - * Convert SuggestionAnswer to array of elements that directly translate to user-presented - * content. - * - * @param context Current context. - * @param suggestion Suggestion to be converted. - * @return array of AnswerText elements to use to construct suggestion item. - */ - static AnswerText[] from(Context context, OmniboxSuggestion suggestion) { - AnswerText[] result = new AnswerText[2]; - SuggestionAnswer answer = suggestion.getAnswer(); - if (answer == null) { - // As an exception, we handle calculation suggestions, too, considering them an Answer, - // even if these are not one. - assert suggestion.getType() == OmniboxSuggestionType.CALCULATOR; - result[0] = new AnswerTextClassic(context, suggestion.getDisplayText()); - result[1] = null; - } else { - result[0] = new AnswerTextClassic(context, answer.getFirstLine()); - result[1] = new AnswerTextClassic(context, answer.getSecondLine()); - } - - // Trim number of presented query lines. - result[0].mMaxLines = 1; - - return result; - } - - /** - * Create new instance of AnswerTextClassic for answer suggestions. - * - * @param context Current context. - * @param line Suggestion line that will be converted to Answer Text. - */ - AnswerTextClassic(Context context, SuggestionAnswer.ImageLine line) { - super(context); - build(line); - } - - /** - * Create new instance of AnswerTextClassic for non-answer suggestions. - * - * @param context Current context. - * @param text Suggestion text. - */ - AnswerTextClassic(Context context, String text) { - super(context); - appendAndStyleText(text, getAppearanceForText(AnswerTextType.SUGGESTION)); - } - - /** - * Return the TextAppearanceSpan array specifying text decorations for a given field type. - * - * @param type The answer type as specified at http://goto.google.com/ais_api. - * @return TextAppearanceSpan array specifying styles to be used to present text field. - */ - @Override - protected MetricAffectingSpan[] getAppearanceForText(@AnswerTextType int type) { - @StyleRes - int res = 0; - switch (type) { - case AnswerTextType.TOP_ALIGNED: - TextAppearanceSpan style = new TextAppearanceSpan( - mContext, R.style.TextAppearance_OmniboxAnswerTextSmall); - return new MetricAffectingSpan[] {style, - new TopAlignedSpan(style.getTextSize(), (int) (mHeightSp * mDensity))}; - - case AnswerTextType.DESCRIPTION_NEGATIVE: - res = R.style.TextAppearance_OmniboxAnswerDescriptionNegative; - break; - - case AnswerTextType.DESCRIPTION_POSITIVE: - res = R.style.TextAppearance_OmniboxAnswerDescriptionPositive; - break; - - case AnswerTextType.SUGGESTION: - res = R.style.TextAppearance_BlackTitle1; - break; - - case AnswerTextType.PERSONALIZED_SUGGESTION: - res = R.style.TextAppearance_BlackTitle1; - break; - - case AnswerTextType.ANSWER_TEXT_MEDIUM: - res = R.style.TextAppearance_OmniboxAnswerTextMedium; - break; - - case AnswerTextType.ANSWER_TEXT_LARGE: - res = R.style.TextAppearance_OmniboxAnswerTextLarge; - break; - - case AnswerTextType.SUGGESTION_SECONDARY_TEXT_SMALL: - res = R.style.TextAppearance_BlackCaption; - break; - - case AnswerTextType.SUGGESTION_SECONDARY_TEXT_MEDIUM: - res = R.style.TextAppearance_BlackHint2; - break; - - default: - Log.w(TAG, "Unknown answer type: " + type); - res = R.style.TextAppearance_BlackHint2; - break; - } - - return new TextAppearanceSpan[] {new TextAppearanceSpan(mContext, res)}; - } - - /** - * Aligns the top of the spanned text with the top of some other specified text height. This is - * done by calculating the ascent of both text heights and shifting the baseline of the spanned - * text by the difference. As a result, "top aligned" means the top of the ascents are - * aligned, which looks as expected in most cases (some glyphs in some fonts are drawn above - * the top of the ascent). - */ - private static class TopAlignedSpan extends MetricAffectingSpan { - private final int mTextHeightPx; - private final int mMaxTextHeightPx; - - private Integer mBaselineShift; - - /** - * Constructor for TopAlignedSpan. - * - * @param textHeightPx The total height in pixels of the text covered by this span. - * @param maxTextHeightPx The total height in pixels of the text we wish to top-align with. - */ - public TopAlignedSpan(int textHeightPx, int maxTextHeightPx) { - mTextHeightPx = textHeightPx; - mMaxTextHeightPx = maxTextHeightPx; - } - - @Override - public void updateDrawState(TextPaint tp) { - initBaselineShift(tp); - tp.baselineShift += mBaselineShift; - } - - @Override - public void updateMeasureState(TextPaint tp) { - initBaselineShift(tp); - tp.baselineShift += mBaselineShift; - } - - private void initBaselineShift(TextPaint tp) { - if (mBaselineShift != null) return; - Paint.FontMetrics metrics = tp.getFontMetrics(); - float ascentProportion = metrics.ascent / (metrics.top - metrics.bottom); - - int textAscentPx = (int) (mTextHeightPx * ascentProportion); - int maxTextAscentPx = (int) (mMaxTextHeightPx * ascentProportion); - - mBaselineShift = -(maxTextAscentPx - textAscentPx); // Up is -y. - } - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java index 91b0f0d..b660c44 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java
@@ -41,7 +41,6 @@ private final SuggestionHost mSuggestionHost; private final UrlBarEditingTextStateProvider mUrlBarEditingTextProvider; private LargeIconBridge mLargeIconBridge; - private boolean mEnableNewAnswerLayout; private boolean mEnableSuggestionFavicons; private final int mDesiredFaviconWidthPx; @@ -105,8 +104,6 @@ @Override public void onNativeInitialized() { // Experiment: controls presence of certain answer icon types. - mEnableNewAnswerLayout = - ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_NEW_ANSWER_LAYOUT); mEnableSuggestionFavicons = ChromeFeatureList.isEnabled(ChromeFeatureList.OMNIBOX_SHOW_SUGGESTION_FAVICONS); } @@ -148,10 +145,6 @@ return mEnableSuggestionFavicons ? SuggestionIcon.MAGNIFIER : SuggestionIcon.HISTORY; - case OmniboxSuggestionType.CALCULATOR: - return mEnableNewAnswerLayout ? SuggestionIcon.CALCULATOR - : SuggestionIcon.MAGNIFIER; - default: return SuggestionIcon.MAGNIFIER; } @@ -192,14 +185,6 @@ ? R.color.default_text_color_dark : R.color.default_text_color_light); textLine2Direction = View.TEXT_DIRECTION_INHERIT; - } else if (mEnableNewAnswerLayout - && suggestionType == OmniboxSuggestionType.CALCULATOR) { - textLine2 = SpannableString.valueOf( - mUrlBarEditingTextProvider.getTextWithAutocomplete()); - - textLine2Color = ApiCompatibilityUtils.getColor( - mContext.getResources(), R.color.answers_answer_text); - textLine2Direction = View.TEXT_DIRECTION_INHERIT; } else { textLine2 = null; } @@ -303,16 +288,6 @@ new OmniboxSuggestion.MatchClassification( 0, MatchClassificationStyle.NONE)); } - } else if (mEnableNewAnswerLayout - && suggestion.getType() == OmniboxSuggestionType.CALCULATOR) { - // Trim preceding equal sign since we're going to present an icon instead. - // This is probably best placed in search_suggestion_parser.cc file, but at this point - // this would affect other devices that still want to present the sign (eg. iOS) so - // until these devices adopt the new entities we need to manage this here. - if (suggestedQuery.subSequence(0, 2).equals("= ")) { - suggestedQuery = suggestedQuery.substring(2); - } - shouldHighlight = false; } Spannable str = SpannableString.valueOf(suggestedQuery);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java deleted file mode 100644 index 67fadc1..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreference.java +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.preferences; - -import android.content.Context; -import android.preference.Preference; -import android.util.AttributeSet; -import android.view.View; -import android.widget.Button; - -import org.chromium.chrome.R; - -/** - * A {@link Preference} that provides button functionality. - * - * Preference.getOnPreferenceClickListener().onPreferenceClick() is called when the button is - * clicked. - */ -public class ButtonPreference extends Preference { - - /** - * Constructor for inflating from XML - */ - public ButtonPreference(Context context, AttributeSet attrs) { - super(context, attrs); - setLayoutResource(R.layout.button_preference_layout); - setWidgetLayoutResource(R.layout.button_preference_button); - setSelectable(true); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - Button button = (Button) view.findViewById(R.id.button_preference); - button.setText(this.getTitle()); - button.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (getOnPreferenceClickListener() != null) { - getOnPreferenceClickListener().onPreferenceClick(ButtonPreference.this); - } - } - }); - - View viewFrame = view.findViewById(android.R.id.widget_frame); - viewFrame.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // This is intentionally left blank to prevent triggering an event after tapping - // any part of the view that is not the button. - } - }); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreferenceCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreferenceCompat.java index 80bbabc7..e0de80c8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreferenceCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ButtonPreferenceCompat.java
@@ -17,9 +17,6 @@ * * Preference.getOnPreferenceClickListener().onPreferenceClick() is called when the button is * clicked. - * - * TODO(crbug.com/967022): Remove {@link ButtonPreference} when Preference Support Library - * migration is complete in favor of this class. */ public class ButtonPreferenceCompat extends Preference { /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreference.java deleted file mode 100644 index 7b9e1151..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreference.java +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.preferences; - -import android.content.Context; -import android.preference.CheckBoxPreference; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView; - -/** - * Contains the basic functionality that should be shared by all CheckBoxPreference in Chrome. - */ -public class ChromeBaseCheckBoxPreference extends CheckBoxPreference { - - private ManagedPreferenceDelegate mManagedPrefDelegate; - - /** - * Constructor for inflating from XML. - */ - public ChromeBaseCheckBoxPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Sets the ManagedPreferenceDelegate which will determine whether this preference is managed. - */ - public void setManagedPreferenceDelegate(ManagedPreferenceDelegate delegate) { - mManagedPrefDelegate = delegate; - ManagedPreferencesUtils.initPreference(mManagedPrefDelegate, this); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - ((TextView) view.findViewById(android.R.id.title)).setSingleLine(false); - ManagedPreferencesUtils.onBindViewToPreference(mManagedPrefDelegate, this, view); - } - - @Override - protected void onClick() { - if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return; - super.onClick(); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreferenceCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreferenceCompat.java index d371c4b..485f9fd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreferenceCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseCheckBoxPreferenceCompat.java
@@ -12,11 +12,6 @@ /** * Contains the basic functionality that should be shared by all CheckBoxPreference in Chrome. - * - * TODO(crbug.com/967022): This class is a duplicate of {@link ChromeBaseCheckBoxPreference} that - * extends the Preference Support Library instead of the Framework Preference classes. {@link - * ChromeBaseCheckBoxPreference} will be removed in favor of this class once migration to the - * Preference Support library is complete. */ public class ChromeBaseCheckBoxPreferenceCompat extends CheckBoxPreference { private ManagedPreferenceDelegateCompat mManagedPrefDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreference.java deleted file mode 100644 index f9847237..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreference.java +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.preferences; - -import android.content.Context; -import android.preference.ListPreference; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView; - -/** - * Contains the basic functionality that should be shared by all ListPreference in Chrome. - */ -public class ChromeBaseListPreference extends ListPreference { - - private ManagedPreferenceDelegate mManagedPrefDelegate; - - /** - * Constructor for inflating from XML. - */ - public ChromeBaseListPreference(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Sets the ManagedPreferenceDelegate which will determine whether this preference is managed. - */ - public void setManagedPreferenceDelegate(ManagedPreferenceDelegate delegate) { - mManagedPrefDelegate = delegate; - ManagedPreferencesUtils.initPreference(mManagedPrefDelegate, this); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - ((TextView) view.findViewById(android.R.id.title)).setSingleLine(false); - ManagedPreferencesUtils.onBindViewToPreference(mManagedPrefDelegate, this, view); - } - - @Override - protected void onClick() { - if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return; - super.onClick(); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreferenceCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreferenceCompat.java index d55e4d8d..f031e5f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreferenceCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBaseListPreferenceCompat.java
@@ -11,9 +11,6 @@ /** * Contains the basic functionality that should be shared by all ListPreference in Chrome. - * - * TODO(crbug.com/967022): Remove {@link ChromeBaseListPreference} when Preference Support Library - * migration is complete in favor of this class. */ public class ChromeBaseListPreferenceCompat extends ListPreference { private ManagedPreferenceDelegateCompat mManagedPrefDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreference.java deleted file mode 100644 index f0a8956..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreference.java +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.preferences; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.TypedArray; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.preference.Preference; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView; - -import org.chromium.chrome.R; - -/** - * A preference that supports some Chrome-specific customizations: - * - * 1. This preference supports being managed. If this preference is managed (as determined by its - * ManagedPreferenceDelegate), it updates its appearance and behavior appropriately: shows an - * enterprise icon, disables clicks, etc. - * - * 2. This preference can have a multiline title. - * 3. This preference can set an icon color in XML through app:iconTint. Note that if a - * ColorStateList is set, only the default color will be used. - */ -public class ChromeBasePreference extends Preference { - private ColorStateList mIconTint; - private ManagedPreferenceDelegate mManagedPrefDelegate; - - /** - * Constructor for use in Java. - */ - public ChromeBasePreference(Context context) { - this(context, null); - } - - /** - * Constructor for inflating from XML. - */ - public ChromeBasePreference(Context context, AttributeSet attrs) { - super(context, attrs); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChromeBasePreference); - mIconTint = a.getColorStateList(R.styleable.ChromeBasePreference_iconTint); - a.recycle(); - } - - /** - * Sets the ManagedPreferenceDelegate which will determine whether this preference is managed. - */ - public void setManagedPreferenceDelegate(ManagedPreferenceDelegate delegate) { - mManagedPrefDelegate = delegate; - ManagedPreferencesUtils.initPreference(mManagedPrefDelegate, this); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - ((TextView) view.findViewById(android.R.id.title)).setSingleLine(false); - Drawable icon = getIcon(); - if (icon != null && mIconTint != null) { - icon.setColorFilter(mIconTint.getDefaultColor(), PorterDuff.Mode.SRC_IN); - } - ManagedPreferencesUtils.onBindViewToPreference(mManagedPrefDelegate, this, view); - } - - @Override - protected void onClick() { - if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return; - super.onClick(); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreferenceCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreferenceCompat.java index b2c3029..538d9f54 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreferenceCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeBasePreferenceCompat.java
@@ -26,11 +26,6 @@ * 2. This preference can have a multiline title. * 3. This preference can set an icon color in XML through app:iconTint. Note that if a * ColorStateList is set, only the default color will be used. - * - * TODO(crbug.com/967022): This class is analogous to {@link ChromeBasePreference}, but extends the - * Preference Support Library rather than the deprecated Framework preferences. Once all {@link - * ChromeBasePreference}s have been migrated to the Support Library, {@link ChromeBasePreference} - * will be removed in favor of {@link ChromeBasePreferenceCompat}. */ public class ChromeBasePreferenceCompat extends Preference { private ColorStateList mIconTint;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeImageViewPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeImageViewPreference.java deleted file mode 100644 index a955013..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeImageViewPreference.java +++ /dev/null
@@ -1,133 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.preferences; - -import android.content.Context; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.preference.Preference; -import android.support.annotation.DrawableRes; -import android.support.annotation.Nullable; -import android.support.annotation.StringRes; -import android.util.AttributeSet; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import org.chromium.chrome.R; - -/** - * A preference that supports some Chrome-specific customizations: - * - * 1. This preference supports being managed. If this preference is managed (as determined by its - * ManagedPreferenceDelegate), it updates its appearance and behavior appropriately: shows an - * enterprise icon in its widget ImageView, disables clicks, etc. - * 2. This preference can have a multiline title. - * 3. This preference can have an onClick listener set for its ImageView widget. - * - * The preference includes the preference_chrome_image_view widget layout to provide these - * customizations, however a custom widget may also be included as long as there is an ImageView - * with the image_view_widget ID. - */ -public class ChromeImageViewPreference extends Preference { - @Nullable - private ManagedPreferenceDelegate mManagedPrefDelegate; - - // The onClick listener to handle click events for the ImageView widget. - @Nullable - private View.OnClickListener mListener; - // The image resource ID to use for the ImageView widget source. - @DrawableRes - private int mImageRes; - // The string resource ID to use for the ImageView widget content description. - @StringRes - private int mContentDescriptionRes; - // Whether the ImageView should be enabled. - private boolean mImageViewEnabled = true; - - /** - * Constructor for use in Java. - */ - public ChromeImageViewPreference(Context context) { - this(context, null); - } - - /** - * Constructor for inflating from XML. - */ - public ChromeImageViewPreference(Context context, AttributeSet attrs) { - super(context, attrs); - - setWidgetLayoutResource(R.layout.preference_chrome_image_view); - } - - /** - * Sets the ManagedPreferenceDelegate which will determine whether this preference is managed. - */ - public void setManagedPreferenceDelegate(@Nullable ManagedPreferenceDelegate delegate) { - mManagedPrefDelegate = delegate; - ManagedPreferencesUtils.initPreference(mManagedPrefDelegate, this); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - ((TextView) view.findViewById(android.R.id.title)).setSingleLine(false); - - ImageView button = view.findViewById(R.id.image_view_widget); - - if (mImageRes != 0) { - Drawable buttonImg = PreferenceUtils.getTintedIcon(view.getContext(), mImageRes); - - button.setImageDrawable(buttonImg); - button.setBackgroundColor(Color.TRANSPARENT); - button.setVisibility(View.VISIBLE); - button.setEnabled(mImageViewEnabled); - if (mImageViewEnabled) button.setOnClickListener(mListener); - - if (mContentDescriptionRes != 0) { - button.setContentDescription(view.getResources().getString(mContentDescriptionRes)); - } - } - - ManagedPreferencesUtils.onBindViewToImageViewPreference(mManagedPrefDelegate, this, view); - } - - @Override - protected void onClick() { - if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return; - super.onClick(); - } - - /** - * Sets the Drawable resource ID, the String resource ID, and the OnClickListener for the - * ImageView widget's source, content description, and onClick, respectively. - */ - public void setImageView(@DrawableRes int imageRes, @StringRes int contentDescriptionRes, - @Nullable View.OnClickListener listener) { - mImageRes = imageRes; - mContentDescriptionRes = contentDescriptionRes; - mListener = listener; - notifyChanged(); - } - - /** - * Enables/Disables the ImageView, allowing for clicks to pass through (when disabled). - */ - public void setImageViewEnabled(boolean enabled) { - mImageViewEnabled = enabled; - } - - /** - * If a {@link ManagedPreferenceDelegate} has been set, check if this preference is managed. - * @return True if the preference is managed. - */ - public boolean isManaged() { - if (mManagedPrefDelegate == null) return false; - - return mManagedPrefDelegate.isPreferenceControlledByPolicy(this) - || mManagedPrefDelegate.isPreferenceControlledByCustodian(this); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeImageViewPreferenceCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeImageViewPreferenceCompat.java index c9b9444..0cca33f0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeImageViewPreferenceCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeImageViewPreferenceCompat.java
@@ -19,10 +19,6 @@ import org.chromium.chrome.R; /** - * TODO(crbug.com/967022): This class is a duplicate of {@link ChromeImageViewPreference}, but with - * Support Library classes replacing deprecated Framework classes. When Preference Support Library - * migration is complete remove {@link ChromeImageViewPreference} in favor of this class. - * * A preference that supports some Chrome-specific customizations: * * 1. This preference supports being managed. If this preference is managed (as determined by its
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreference.java deleted file mode 100644 index c2cf7d9a..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreference.java +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.preferences; - -import android.content.Context; -import android.content.res.TypedArray; -import android.os.Build; -import android.preference.SwitchPreference; -import android.support.v7.widget.SwitchCompat; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView; - -import org.chromium.chrome.R; -import org.chromium.ui.HorizontalListDividerDrawable; - -/** - * A super-powered SwitchPreference designed especially for Chrome. Special features: - * - Supports managed preferences - * - Displays a material-styled switch, even on pre-L devices - */ -public class ChromeSwitchPreference extends SwitchPreference { - - private ManagedPreferenceDelegate mManagedPrefDelegate; - - private boolean mDontUseSummaryAsTitle; - private boolean mDrawDivider; - - /** - * Constructor for inflating from XML. - */ - public ChromeSwitchPreference(Context context, AttributeSet attrs) { - super(context, attrs); - setWidgetLayoutResource(R.layout.preference_switch); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - // Fix animations. Background: setWidgetLayout resource call above disables view - // recycling, thus breaking SwitchCompat animations. Views recycling is safe in this - // case, as ChromeSwitchPreference doesn't change view types on the fly. - setRecycleEnabled(true); - } - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChromeSwitchPreference); - mDontUseSummaryAsTitle = - a.getBoolean(R.styleable.ChromeSwitchPreference_dontUseSummaryAsTitle, false); - mDrawDivider = a.getBoolean(R.styleable.ChromeSwitchPreference_drawDivider, false); - a.recycle(); - } - - /** - * Sets the ManagedPreferenceDelegate which will determine whether this preference is managed. - */ - public void setManagedPreferenceDelegate(ManagedPreferenceDelegate delegate) { - mManagedPrefDelegate = delegate; - ManagedPreferencesUtils.initPreference(mManagedPrefDelegate, this); - } - - /** - * Sets whether a horizontal divider line should be drawn at the bottom of this preference. - */ - public void setDrawDivider(boolean drawDivider) { - if (mDrawDivider != drawDivider) { - mDrawDivider = drawDivider; - notifyChanged(); - } - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - - if (mDrawDivider) { - int left = view.getPaddingLeft(); - int right = view.getPaddingRight(); - int top = view.getPaddingTop(); - int bottom = view.getPaddingBottom(); - view.setBackground(HorizontalListDividerDrawable.create(getContext())); - view.setPadding(left, top, right, bottom); - } - - SwitchCompat switchView = (SwitchCompat) view.findViewById(R.id.switch_widget); - // On BLU Life Play devices SwitchPreference.setWidgetLayoutResource() does nothing. As a - // result, the user will see a non-material Switch and switchView will be null, hence the - // null check below. http://crbug.com/451447 - if (switchView != null) { - switchView.setChecked(isChecked()); - } - - TextView title = (TextView) view.findViewById(android.R.id.title); - title.setSingleLine(false); - if (!mDontUseSummaryAsTitle && TextUtils.isEmpty(getTitle())) { - TextView summary = (TextView) view.findViewById(android.R.id.summary); - title.setText(summary.getText()); - title.setVisibility(View.VISIBLE); - summary.setVisibility(View.GONE); - } - - ManagedPreferencesUtils.onBindViewToPreference(mManagedPrefDelegate, this, view); - } - - @Override - protected void onClick() { - if (ManagedPreferencesUtils.onClickPreference(mManagedPrefDelegate, this)) return; - super.onClick(); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreferenceCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreferenceCompat.java index 44f8aba..234387a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreferenceCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromeSwitchPreferenceCompat.java
@@ -14,9 +14,6 @@ /** * A Chrome switch preference that supports managed preferences. - * - * TODO(crbug.com/967022): Remove {@link ChromeSwitchPreference} when Preference Support Library - * migration is complete in favor of this class. */ public class ChromeSwitchPreferenceCompat extends SwitchPreferenceCompat { private ManagedPreferenceDelegateCompat mManagedPrefDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java index b0d94678..fb130ee 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/HomepageEditor.java
@@ -4,8 +4,8 @@ package org.chromium.chrome.browser.preferences; -import android.app.Fragment; import android.os.Bundle; +import android.support.v4.app.Fragment; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreference.java deleted file mode 100644 index c40e6367..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreference.java +++ /dev/null
@@ -1,64 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.preferences; - -import android.app.Activity; -import android.content.Context; -import android.content.res.TypedArray; -import android.preference.Preference; -import android.util.AttributeSet; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.TextView; - -import org.chromium.base.ApiCompatibilityUtils; -import org.chromium.chrome.R; -import org.chromium.chrome.browser.help.HelpAndFeedback; -import org.chromium.chrome.browser.profiles.Profile; - -/** - * A preference that opens a HelpAndFeedback activity to learn more about the specified context. - */ -public class LearnMorePreference extends Preference { - - private final int mHelpContext; - private final int mColor; - - public LearnMorePreference(Context context, AttributeSet attrs) { - super(context, attrs); - TypedArray a = context.obtainStyledAttributes(attrs, - R.styleable.LearnMorePreference, 0, 0); - mHelpContext = a.getResourceId(R.styleable.LearnMorePreference_helpContext, 0); - mColor = ApiCompatibilityUtils.getColor( - context.getResources(), R.color.default_text_color_link); - a.recycle(); - setTitle(R.string.learn_more); - } - - @Override - protected void onClick() { - HelpAndFeedback.getInstance(getContext()) - .show((Activity) getContext(), getContext().getString(mHelpContext), - Profile.getLastUsedProfile(), null); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - TextView titleView = (TextView) view.findViewById(android.R.id.title); - titleView.setSingleLine(false); - - setSelectable(false); - - titleView.setClickable(true); - titleView.setTextColor(mColor); - titleView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - LearnMorePreference.this.onClick(); - } - }); - } -} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreferenceCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreferenceCompat.java index c670c05..af2e34a3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreferenceCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/LearnMorePreferenceCompat.java
@@ -20,11 +20,6 @@ /** * A preference that opens a HelpAndFeedback activity to learn more about the specified context. - * - * TODO(crbug.com/967022): This class is mostly a duplicate of {@link LearnMorePreference}, but is - * implemented for Support Library preferences rather than the deprecated Framework preferences. - * Once all {@link LearnMorePreference}s have been migrated to the Support Library, {@link - * LearnMorePreference} will be removed in favor of this class. */ public class LearnMorePreferenceCompat extends Preference { /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegate.java deleted file mode 100644 index 0b6f31837..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegate.java +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.preferences; - -import android.preference.Preference; - -/** - * A delegate that determines whether a Preference is managed by enterprise policy. This is used - * in various Preference subclasses (e.g. ChromeSwitchPreference) to determine whether to show - * an enterprise icon next to the Preference and whether to disable clicks on the Preference. - * - * An implementation of this delegate should override isPreferenceControlledByPolicy() and, - * optionally, isPreferenceClickDisabledByPolicy(). Example: - * - * class RocketManagedPreferenceDelegate extends ManagedPreferenceDelegate { - * @Override - * public boolean isPreferenceControlledByPolicy(Preference preference) { - * if ("enable_rockets".equals(preference.getKey())) { - * return RocketUtils.isEnableRocketsManaged(); - * } - * return false; - * } - * } - * - * ChromeSwitchPreference enableRocketsPref = ...; - * enableRocketsPref.setManagedPreferenceDelegate(new RocketManagedPreferenceDelegate()); - */ -public interface ManagedPreferenceDelegate { - /** - * Returns whether the given Preference is controlled by an enterprise policy. - * @param preference the {@link Preference} under consideration. - * @return whether the given Preference is controlled by an enterprise policy. - */ - boolean isPreferenceControlledByPolicy(Preference preference); - - /** - * Returns whether the given Preference is controlled by the supervised user's custodian. - * @param preference the {@link Preference} under consideration. - * @return whether the given Preference is controlled by the supervised user's custodian. - */ - default boolean isPreferenceControlledByCustodian(Preference preference) { - return false; - } - - /** - * Returns whether clicking on the given Preference is disabled due to a policy. The default - * implementation just returns whether the preference is not modifiable by the user. - * However, some preferences that are controlled by policy may still be clicked to show an - * informational subscreen, in which case this method needs a custom implementation. - */ - // TODO(bauerb): Rename to isPreferenceClickDisabled. - default boolean isPreferenceClickDisabledByPolicy(Preference preference) { - return isPreferenceControlledByPolicy(preference) - || isPreferenceControlledByCustodian(preference); - } -} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegateCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegateCompat.java index 193a856a..4810c016 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegateCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferenceDelegateCompat.java
@@ -26,11 +26,6 @@ * * ChromeSwitchPreference enableRocketsPref = ...; * enableRocketsPref.setManagedPreferenceDelegate(new RocketManagedPreferenceDelegate()); - * - * TODO(crbug.com/967022): This class is analogous to {@link ManagedPreferenceDelegate}, but is - * implemented for Support Library preferences rather than the deprecated Framework preferences. - * Once all managed preferences have been migrated to the Support Library, {@link - * ManagedPreferenceDelegate} will be removed in favor of this class. */ public interface ManagedPreferenceDelegateCompat { /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java index 11dcbf0..3e3802d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ManagedPreferencesUtils.java
@@ -6,9 +6,9 @@ import android.content.Context; import android.graphics.drawable.Drawable; -import android.preference.Preference; import android.support.annotation.Nullable; import android.support.annotation.StringRes; +import android.support.v7.preference.Preference; import android.text.TextUtils; import android.view.View; import android.widget.ImageView; @@ -81,7 +81,7 @@ * a custodian. */ public static Drawable getManagedIconDrawable( - @Nullable ManagedPreferenceDelegate delegate, Preference preference) { + @Nullable ManagedPreferenceDelegateCompat delegate, Preference preference) { if (delegate == null) return preference.getIcon(); if (delegate.isPreferenceControlledByPolicy(preference)) { @@ -96,67 +96,6 @@ } /** - * TODO(crbug.com/967022): This method is a duplicate of {@link - * #getManagedIconDrawable(ManagedPreferenceDelegate, Preference)}, but with Support Library - * classes replacing deprecated Framework classes. When Preference Support Library migration is - * complete remove {@link #getManagedIconDrawable(ManagedPreferenceDelegate, Preference)} in - * favor of this method. - * - * @return The appropriate Drawable based on whether the preference is controlled by a policy or - * a custodian. - */ - public static Drawable getManagedIconDrawable( - @Nullable ManagedPreferenceDelegateCompat delegate, - android.support.v7.preference.Preference preference) { - if (delegate == null) return preference.getIcon(); - - if (delegate.isPreferenceControlledByPolicy(preference)) { - return PreferenceUtils.getTintedIcon( - preference.getContext(), getManagedByEnterpriseIconId()); - } else if (delegate.isPreferenceControlledByCustodian(preference)) { - return PreferenceUtils.getTintedIcon( - preference.getContext(), getManagedByCustodianIconId()); - } - - return preference.getIcon(); - } - - /** - * Initializes the Preference based on the state of any policies that may affect it, - * e.g. by showing a managed icon or disabling clicks on the preference. If |preference| is an - * instance of ChromeImageViewPreference, the icon is not set since the ImageView widget will - * display the managed icons. - * - * This should be called once, before the preference is displayed. - * - * TODO(crbug.com/967022): Remove this method once all fragments are migrated to the Support - * Library in favor of {@link #initPreference(ManagedPreferenceDelegateCompat, - * android.support.v7.preference.Preference)}. - * - * @param delegate The delegate that controls whether the preference is managed. May be null, - * then this method does nothing. - * @param preference The Preference that is being initialized - */ - public static void initPreference( - @Nullable ManagedPreferenceDelegate delegate, Preference preference) { - if (delegate == null) return; - - if (!(preference instanceof ChromeImageViewPreference)) { - preference.setIcon(getManagedIconDrawable(delegate, preference)); - } - - if (delegate.isPreferenceClickDisabledByPolicy(preference)) { - // Disable the views and prevent the Preference from mucking with the enabled state. - preference.setShouldDisableView(false); - - // Prevent default click behavior. - preference.setFragment(null); - preference.setIntent(null); - preference.setOnPreferenceClickListener(null); - } - } - - /** * Initializes the Preference based on the state of any policies that may affect it, * e.g. by showing a managed icon or disabling clicks on the preference. If |preference| is an * instance of ChromeImageViewPreference, the icon is not set since the ImageView widget will @@ -168,8 +107,8 @@ * then this method does nothing. * @param preference The Preference that is being initialized */ - public static void initPreference(@Nullable ManagedPreferenceDelegateCompat delegate, - android.support.v7.preference.Preference preference) { + public static void initPreference( + @Nullable ManagedPreferenceDelegateCompat delegate, Preference preference) { if (delegate == null) return; if (!(preference instanceof ChromeImageViewPreferenceCompat)) { @@ -195,17 +134,13 @@ * * This should be called from the Preference's onBindView() method. * - * TODO(crbug.com/967022): Remove this method once all fragments are migrated to the Support - * Library in favor of {@link #onBindViewToPreference(ManagedPreferenceDelegateCompat, - * android.support.v7.preference.Preference, View)}. - * * @param delegate The delegate that controls whether the preference is managed. May be null, * then this method does nothing. * @param preference The Preference that owns the view * @param view The View that was bound to the Preference */ public static void onBindViewToPreference( - @Nullable ManagedPreferenceDelegate delegate, Preference preference, View view) { + @Nullable ManagedPreferenceDelegateCompat delegate, Preference preference, View view) { if (delegate == null) return; if (delegate.isPreferenceClickDisabledByPolicy(preference)) { @@ -224,78 +159,6 @@ } /** - * Disables the Preference's views if the preference is not clickable. - * - * Note: this disables the View instead of disabling the Preference, so that the Preference - * still receives click events, which will trigger a "Managed by your administrator" toast. - * - * This should be called from the Preference's onBindView() method. - * - * @param delegate The delegate that controls whether the preference is managed. May be null, - * then this method does nothing. - * @param preference The Preference that owns the view - * @param view The View that was bound to the Preference - */ - public static void onBindViewToPreference(@Nullable ManagedPreferenceDelegateCompat delegate, - android.support.v7.preference.Preference preference, View view) { - if (delegate == null) return; - - if (delegate.isPreferenceClickDisabledByPolicy(preference)) { - ViewUtils.setEnabledRecursive(view, false); - } - - // Append managed information to summary if necessary. - TextView summaryView = view.findViewById(android.R.id.summary); - CharSequence summary = - ManagedPreferencesUtils.getSummaryWithManagedInfo(delegate, preference, - summaryView.getVisibility() == View.VISIBLE ? summaryView.getText() : null); - if (!TextUtils.isEmpty(summary)) { - summaryView.setText(summary); - summaryView.setVisibility(View.VISIBLE); - } - } - - /** - * Calls onBindViewToPreference() above. Then, if the ChromeImageViewPreference is managed, the - * widget ImageView is set to the appropriate managed icon, and its onClick listener is set to - * show the appropriate managed message toast. - * - * This should be called from the Preference's onBindView() method. - * - * @param delegate The delegate that controls whether the preference is managed. May be null, - * then this method does nothing. - * @param preference The ChromeImageViewPreference that owns the view. - * @param view The View that was bound to the ChromeImageViewPreference. - */ - public static void onBindViewToImageViewPreference(@Nullable ManagedPreferenceDelegate delegate, - ChromeImageViewPreference preference, View view) { - if (delegate == null) return; - - onBindViewToPreference(delegate, preference, view); - - if (!delegate.isPreferenceControlledByPolicy(preference) - && !delegate.isPreferenceControlledByCustodian(preference)) { - return; - } - - ImageView button = view.findViewById(R.id.image_view_widget); - button.setImageDrawable(getManagedIconDrawable(delegate, preference)); - button.setOnClickListener((View v) -> { - if (delegate.isPreferenceControlledByPolicy(preference)) { - showManagedByAdministratorToast(preference.getContext()); - } else if (delegate.isPreferenceControlledByCustodian(preference)) { - showManagedByParentToast(preference.getContext()); - } - }); - } - - /** - * TODO(crbug.com/967022): This method is a duplicate of {@link - * #onBindViewToPreference(ManagedPreferenceDelegate, Preference, View)}, but with Support - * Library classes replacing deprecated Framework classes. When Preference Support Library - * migration is complete remove {@link #onBindViewToPreference(ManagedPreferenceDelegate, - * Preference, View)} in favor of this method. - * * Calls onBindViewToPreference() above. Then, if the ChromeImageViewPreference is managed, the * widget ImageView is set to the appropriate managed icon, and its onClick listener is set to * show the appropriate managed message toast. @@ -335,10 +198,6 @@ * * This should be called from the Preference's onClick() method. * - * TODO(crbug.com/967022): Remove this method once all fragments are migrated to the Support - * Library in favor of {@link #onClickPreference(ManagedPreferenceDelegateCompat, - * android.support.v7.preference.Preference)}. - * * @param delegate The delegate that controls whether the preference is managed. May be null, * then this method does nothing and returns false. * @param preference The Preference that was clicked. @@ -346,7 +205,7 @@ * propagated; false otherwise. */ public static boolean onClickPreference( - @Nullable ManagedPreferenceDelegate delegate, Preference preference) { + @Nullable ManagedPreferenceDelegateCompat delegate, Preference preference) { if (delegate == null || !delegate.isPreferenceClickDisabledByPolicy(preference)) { return false; } @@ -364,76 +223,18 @@ } /** - * Intercepts the click event if the given Preference is managed and shows a toast in that case. - * - * This should be called from the Preference's onClick() method. - * - * @param delegate The delegate that controls whether the preference is managed. May be null, - * then this method does nothing and returns false. - * @param preference The Preference that was clicked. - * @return true if the click event was handled by this helper and shouldn't be further - * propagated; false otherwise. - */ - public static boolean onClickPreference(@Nullable ManagedPreferenceDelegateCompat delegate, - android.support.v7.preference.Preference preference) { - if (delegate == null || !delegate.isPreferenceClickDisabledByPolicy(preference)) { - return false; - } - - if (delegate.isPreferenceControlledByPolicy(preference)) { - showManagedByAdministratorToast(preference.getContext()); - } else if (delegate.isPreferenceControlledByCustodian(preference)) { - showManagedByParentToast(preference.getContext()); - } else { - // If the preference is disabled, it should be either because it's managed by enterprise - // policy or by the custodian. - assert false; - } - return true; - } - - /** - * TODO(crbug.com/967022): Remove this method once all fragments are migrated to the Support - * Library in favor of {@link #getSummaryWithManagedInfo(ManagedPreferenceDelegateCompat, - * android.support.v7.preference.Preference, CharSequence)}. - * - * @param delegate The {@link ManagedPreferenceDelegate} that controls whether the preference is - * managed. - * @param preference The {@link Preference} that the summary should be used for. - * @param summary The original summary without the managed information. - * @return The summary appended with information about whether the specified preference is - * managed. - */ - private static CharSequence getSummaryWithManagedInfo( - @Nullable ManagedPreferenceDelegate delegate, Preference preference, - @Nullable CharSequence summary) { - if (delegate == null) return summary; - - String extraSummary = null; - if (delegate.isPreferenceControlledByPolicy(preference)) { - extraSummary = preference.getContext().getString(R.string.managed_by_your_organization); - } else if (delegate.isPreferenceControlledByCustodian(preference)) { - extraSummary = preference.getContext().getString(getManagedByParentStringRes()); - } - - if (TextUtils.isEmpty(extraSummary)) return summary; - if (TextUtils.isEmpty(summary)) return extraSummary; - return String.format(Locale.getDefault(), "%s\n%s", summary, extraSummary); - } - - /** * @param delegate The {@link ManagedPreferenceDelegateCompat} that controls whether the * preference is * managed. - * @param preference The {@link android.support.v7.preference.Preference} that the summary + * @param preference The {@link Preference} that the summary * should be used for. * @param summary The original summary without the managed information. * @return The summary appended with information about whether the specified preference is * managed. */ private static CharSequence getSummaryWithManagedInfo( - @Nullable ManagedPreferenceDelegateCompat delegate, - android.support.v7.preference.Preference preference, @Nullable CharSequence summary) { + @Nullable ManagedPreferenceDelegateCompat delegate, Preference preference, + @Nullable CharSequence summary) { if (delegate == null) return summary; String extraSummary = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferenceUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferenceUtils.java index ed45a7a..27c31e0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferenceUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferenceUtils.java
@@ -9,7 +9,6 @@ import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.StrictMode; -import android.preference.PreferenceFragment; import android.support.annotation.DrawableRes; import android.support.annotation.Nullable; import android.support.annotation.XmlRes; @@ -32,26 +31,6 @@ * A helper that is used to load preferences from XML resources without causing a * StrictModeViolation. See http://crbug.com/692125. * - * TODO(crbug.com/967022): Once all {@link PreferenceFragment}s are migrated to the Support - * Library {@link PreferenceFragmentCompat}s, remove this method in favor of the below method. - * - * @param preferenceFragment A Framework {@link PreferenceFragment}. - * @param preferencesResId The id of the XML resource to add to the PreferenceFragment. - */ - public static void addPreferencesFromResource( - PreferenceFragment preferenceFragment, @XmlRes int preferencesResId) { - StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); - try { - preferenceFragment.addPreferencesFromResource(preferencesResId); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - } - - /** - * A helper that is used to load preferences from XML resources without causing a - * StrictModeViolation. See http://crbug.com/692125. - * * @param preferenceFragment A Support Library {@link PreferenceFragmentCompat}. * @param preferencesResId The id of the XML resource to add to the PreferenceFragment. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java index e933be13..8c8c06d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/Preferences.java
@@ -6,7 +6,6 @@ import android.Manifest; import android.annotation.SuppressLint; -import android.app.Fragment; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -14,13 +13,11 @@ import android.content.res.Resources; import android.graphics.BitmapFactory; import android.nfc.NfcAdapter; -import android.os.Build; import android.os.Bundle; import android.os.Process; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceFragment.OnPreferenceStartFragmentCallback; import android.support.graphics.drawable.VectorDrawableCompat; +import android.support.v4.app.Fragment; +import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceFragmentCompat; import android.support.v7.widget.RecyclerView; import android.util.Log; @@ -29,7 +26,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; -import android.widget.ListView; import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.VisibleForTesting; @@ -55,8 +51,7 @@ * PreferenceUtils.getShowShadowOnScrollListener(...). */ public class Preferences extends ChromeBaseAppCompatActivity - implements OnPreferenceStartFragmentCallback, - PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { + implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback { /** * Preference fragments may implement this interface to intercept "Back" button taps in this * activity. @@ -119,21 +114,11 @@ if (savedInstanceState == null) { if (initialFragment == null) initialFragment = MainPreferences.class.getName(); - if (isCompat(initialFragment)) { - android.support.v4.app.Fragment fragment = - android.support.v4.app.Fragment.instantiate( - this, initialFragment, initialArguments); - getSupportFragmentManager() - .beginTransaction() - .replace(android.R.id.content, fragment) - .commit(); - } else { - Fragment fragment = Fragment.instantiate(this, initialFragment, initialArguments); - getFragmentManager() - .beginTransaction() - .replace(android.R.id.content, fragment) - .commit(); - } + Fragment fragment = Fragment.instantiate(this, initialFragment, initialArguments); + getSupportFragmentManager() + .beginTransaction() + .replace(android.R.id.content, fragment) + .commit(); } if (ApiCompatibilityUtils.checkPermission( @@ -151,39 +136,11 @@ ApiCompatibilityUtils.getColor(res, R.color.default_primary_color)); } - /** - * Given a Fragment class name (as a string), determine whether it is a Support Library Fragment - * class, as opposed to a Framework Fragment. - * - * TODO(crbug.com/967022): Remove this method once all fragments are migrated to the Support - * Library. - * - * @param fragmentClass The fully qualified class name of a Fragment. - * @return Whether the class represents a Support Library Fragment. - */ - private boolean isCompat(String fragmentClass) { - try { - return android.support.v4.app.Fragment.class.isAssignableFrom( - Class.forName(fragmentClass)); - } catch (ClassNotFoundException e) { - return false; - } - } - // OnPreferenceStartFragmentCallback: @Override - // TODO(crbug.com/967022): Remove this method once all fragments are migrated to the Support - // Library. public boolean onPreferenceStartFragment( - PreferenceFragment preferenceFragment, Preference preference) { - startFragment(preference.getFragment(), preference.getExtras()); - return true; - } - - @Override - public boolean onPreferenceStartFragment( - PreferenceFragmentCompat caller, android.support.v7.preference.Preference preference) { + PreferenceFragmentCompat caller, Preference preference) { startFragment(preference.getFragment(), preference.getExtras()); return true; } @@ -205,48 +162,7 @@ @Override public void onAttachedToWindow() { super.onAttachedToWindow(); - Fragment fragment = getMainFragment(); - if (fragment == null) { - onAttachedToWindowCompat(); - return; - } - if (fragment.getView() == null - || fragment.getView().findViewById(android.R.id.list) == null) { - return; - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (fragment instanceof PreferenceFragment && fragment.getView() != null) { - // Set list view padding to 0 so dividers are the full width of the screen. - fragment.getView().findViewById(android.R.id.list).setPadding(0, 0, 0, 0); - } - } - View contentView = fragment.getActivity().findViewById(android.R.id.content); - if (contentView == null || !(contentView instanceof FrameLayout)) { - return; - } - - View inflatedView = View.inflate(getApplicationContext(), - R.layout.preferences_action_bar_shadow, (ViewGroup) contentView); - ListView listView = fragment.getView().findViewById(android.R.id.list); - listView.getViewTreeObserver().addOnScrollChangedListener( - PreferenceUtils.getShowShadowOnScrollListener( - listView, inflatedView.findViewById(R.id.shadow))); - } - - /** - * This method performs similar actions to {@link #onAttachedToWindow()}, but modified for the - * case where the main fragment is a Support Library fragment. - * - * Differences include: - * * List ID reference is R.id.list instead of android.R.id.list. - * * The {@link ListView} is now a {@link RecyclerView}. - * - * TODO(crbug.com/967022): Once all fragments are migrated to the Support Library, replace - * {@link #onAttachedToWindow()} with this method body. - */ - public void onAttachedToWindowCompat() { - super.onAttachedToWindow(); - android.support.v4.app.Fragment fragment = getMainFragmentCompat(); + Fragment fragment = getMainFragmentCompat(); if (fragment == null || fragment.getView() == null || fragment.getView().findViewById(R.id.list) == null) { return; @@ -299,27 +215,11 @@ /** * Returns the fragment showing as this activity's main content, typically a {@link - * PreferenceFragment}. This does not include {@link android.app.DialogFragment}s or other - * {@link Fragment}s shown on top of the main content. - * - * This method only returns Framework {@link Fragment}s. If the main fragment is a Support - * Library fragment (of type {@link android.support.v4.app.Fragment}), this method returns null. - * - * TODO(crbug.com/967022): Remove this method once all fragments are migrated to the Support - * Library. + * PreferenceFragmentCompat}. This does not include dialogs or other {@link Fragment}s shown on + * top of the main content. */ @VisibleForTesting - public Fragment getMainFragment() { - return getFragmentManager().findFragmentById(android.R.id.content); - } - - /** - * This method should be called to retrieve the activity's main content if {@link - * #getMainFragment()} returned null, which may indicate that the main fragment is a Support - * Library fragment. - */ - @VisibleForTesting - public android.support.v4.app.Fragment getMainFragmentCompat() { + public Fragment getMainFragmentCompat() { return getSupportFragmentManager().findFragmentById(android.R.id.content); } @@ -345,9 +245,7 @@ @Override public boolean onOptionsItemSelected(MenuItem item) { - Fragment mainFragment = getMainFragment(); - if (mainFragment != null && mainFragment.onOptionsItemSelected(item)) return true; - android.support.v4.app.Fragment mainFragmentCompat = getMainFragmentCompat(); + Fragment mainFragmentCompat = getMainFragmentCompat(); if (mainFragmentCompat != null && mainFragmentCompat.onOptionsItemSelected(item)) { return true; } @@ -365,7 +263,7 @@ @Override public void onBackPressed() { - android.support.v4.app.Fragment activeFragment = getMainFragmentCompat(); + Fragment activeFragment = getMainFragmentCompat(); if (!(activeFragment instanceof OnBackPressedListener)) { super.onBackPressed(); return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java index 6d19a05..000deed 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.preferences; import android.app.Activity; -import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.os.Build; @@ -60,20 +59,6 @@ * * @param context The current Activity, or an application context if no Activity is available. * @param fragment The fragment to show, or null to show the top-level page. - * - * TODO(crbug.com/967022): Remove this method when Preference Support Library migration is - * complete. - */ - public static void launchSettingsPage( - Context context, @Nullable Class<? extends Fragment> fragment) { - launchSettingsPage(context, fragment, null); - } - - /** - * Launches settings, either on the top-level page or on a subpage. - * - * @param context The current Activity, or an application context if no Activity is available. - * @param fragment The fragment to show, or null to show the top-level page. */ public static void launchSettingsPageCompat( Context context, @Nullable Class<? extends android.support.v4.app.Fragment> fragment) { @@ -86,23 +71,6 @@ * @param context The current Activity, or an application context if no Activity is available. * @param fragment The name of the fragment to show, or null to show the top-level page. * @param fragmentArgs The arguments bundle to initialize the instance of subpage fragment. - * - * TODO(crbug.com/967022): Remove this method when Preference Support Library migration is - * complete. - */ - public static void launchSettingsPage(Context context, - @Nullable Class<? extends Fragment> fragment, @Nullable Bundle fragmentArgs) { - String fragmentName = fragment != null ? fragment.getName() : null; - Intent intent = createIntentForSettingsPage(context, fragmentName, fragmentArgs); - IntentUtils.safeStartActivity(context, intent); - } - - /** - * Launches settings, either on the top-level page or on a subpage. - * - * @param context The current Activity, or an application context if no Activity is available. - * @param fragment The name of the fragment to show, or null to show the top-level page. - * @param fragmentArgs The arguments bundle to initialize the instance of subpage fragment. */ public static void launchSettingsPageCompat(Context context, @Nullable Class<? extends android.support.v4.app.Fragment> fragment,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessagePreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessagePreference.java deleted file mode 100644 index 5b33b6a3..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessagePreference.java +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.preferences; - -import android.content.Context; -import android.text.TextUtils; -import android.text.method.LinkMovementMethod; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView; - -/** - * A preference that displays informational text. - */ -public class TextMessagePreference extends ChromeBasePreference { - /** - * Constructor for inflating from XML. - */ - public TextMessagePreference(Context context, AttributeSet attrs) { - super(context, attrs); - setSelectable(false); - } - - @Override - protected void onBindView(View view) { - super.onBindView(view); - - TextView titleView = (TextView) view.findViewById(android.R.id.title); - if (!TextUtils.isEmpty(getTitle())) { - titleView.setVisibility(View.VISIBLE); - titleView.setSingleLine(false); - titleView.setMaxLines(Integer.MAX_VALUE); - titleView.setMovementMethod(LinkMovementMethod.getInstance()); - } else { - titleView.setVisibility(View.GONE); - } - - TextView summaryView = (TextView) view.findViewById(android.R.id.summary); - // No need to manually toggle visibility for summary - it is done in super.onBindView. - summaryView.setMovementMethod(LinkMovementMethod.getInstance()); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessagePreferenceCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessagePreferenceCompat.java index bf32e46..929c11d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessagePreferenceCompat.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessagePreferenceCompat.java
@@ -14,11 +14,6 @@ /** * A preference that displays informational text. - * - * TODO(crbug.com/967022): This class is analogous to {@link TextMessagePreference}, but extends - * {@link ChromeBasePreferenceCompat} rather than {@link ChromeBasePreference}. Once all {@link - * TextMessagePreference}-containing fragments have been migrated to the Support Library, remove - * {@link TextMessagePreference} in favor of this class. */ public class TextMessagePreferenceCompat extends ChromeBasePreferenceCompat { /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java index 912f8573..9ac9392 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java
@@ -5,9 +5,9 @@ package org.chromium.chrome.browser.preferences.autofill; import android.annotation.SuppressLint; -import android.app.Fragment; import android.content.Context; import android.os.Bundle; +import android.support.v4.app.Fragment; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/AddLanguageFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/AddLanguageFragment.java index e8b6a3a..ba9d8c2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/AddLanguageFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/languages/AddLanguageFragment.java
@@ -5,10 +5,10 @@ package org.chromium.chrome.browser.preferences.languages; import android.app.Activity; -import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.support.v4.app.Fragment; import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/ManageSyncPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/ManageSyncPreferences.java index 85f172b..d9256b0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/ManageSyncPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/ManageSyncPreferences.java
@@ -59,17 +59,28 @@ @VisibleForTesting public static final String FRAGMENT_PASSPHRASE_TYPE = "password_type"; - private static final String PREF_SYNC_EVERYTHING = "sync_everything"; - private static final String PREF_SYNC_AUTOFILL = "sync_autofill"; - private static final String PREF_SYNC_BOOKMARKS = "sync_bookmarks"; - private static final String PREF_SYNC_PAYMENTS_INTEGRATION = "sync_payments_integration"; - private static final String PREF_SYNC_HISTORY = "sync_history"; - private static final String PREF_SYNC_PASSWORDS = "sync_passwords"; - private static final String PREF_SYNC_RECENT_TABS = "sync_recent_tabs"; - private static final String PREF_SYNC_SETTINGS = "sync_settings"; - private static final String PREF_GOOGLE_ACTIVITY_CONTROLS = "google_activity_controls"; - private static final String PREF_ENCRYPTION = "encryption"; - private static final String PREF_SYNC_MANAGE_DATA = "sync_manage_data"; + @VisibleForTesting + public static final String PREF_SYNC_EVERYTHING = "sync_everything"; + @VisibleForTesting + public static final String PREF_SYNC_AUTOFILL = "sync_autofill"; + @VisibleForTesting + public static final String PREF_SYNC_BOOKMARKS = "sync_bookmarks"; + @VisibleForTesting + public static final String PREF_SYNC_PAYMENTS_INTEGRATION = "sync_payments_integration"; + @VisibleForTesting + public static final String PREF_SYNC_HISTORY = "sync_history"; + @VisibleForTesting + public static final String PREF_SYNC_PASSWORDS = "sync_passwords"; + @VisibleForTesting + public static final String PREF_SYNC_RECENT_TABS = "sync_recent_tabs"; + @VisibleForTesting + public static final String PREF_SYNC_SETTINGS = "sync_settings"; + @VisibleForTesting + public static final String PREF_GOOGLE_ACTIVITY_CONTROLS = "google_activity_controls"; + @VisibleForTesting + public static final String PREF_ENCRYPTION = "encryption"; + @VisibleForTesting + public static final String PREF_SYNC_MANAGE_DATA = "sync_manage_data"; private final ProfileSyncService mProfileSyncService = ProfileSyncService.get(); @@ -230,8 +241,8 @@ // Note: mSyncPaymentsIntegration should be checked if mSyncEverything is checked, but if // mSyncEverything was just enabled, then that state may not have propagated to // mSyncPaymentsIntegration yet. See crbug.com/972863. - PersonalDataManager.setPaymentsIntegrationEnabled( - mSyncEverything.isChecked() || mSyncPaymentsIntegration.isChecked()); + PersonalDataManager.setPaymentsIntegrationEnabled(mSyncEverything.isChecked() + || (mSyncPaymentsIntegration.isChecked() && mSyncAutofill.isChecked())); // Some calls to setChosenDataTypes don't trigger syncStateChanged, so schedule update here. PostTask.postTask(UiThreadTaskTraits.DEFAULT, this::updateSyncPreferences); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/SyncAndServicesPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/SyncAndServicesPreferences.java index 0137bdae5..7b201412 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/SyncAndServicesPreferences.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/sync/SyncAndServicesPreferences.java
@@ -88,7 +88,8 @@ private static final String PREF_SYNC_ERROR_CARD = "sync_error_card"; private static final String PREF_SYNC_DISABLED_BY_ADMINISTRATOR = "sync_disabled_by_administrator"; - private static final String PREF_SYNC_REQUESTED = "sync_requested"; + @VisibleForTesting + public static final String PREF_SYNC_REQUESTED = "sync_requested"; private static final String PREF_MANAGE_SYNC = "manage_sync"; private static final String PREF_SERVICES_CATEGORY = "services_category";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java index c34b9d5..b0be9d2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java
@@ -20,7 +20,6 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.favicon.FaviconHelper; import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback; -import org.chromium.chrome.browser.preferences.ChromeImageViewPreference; import org.chromium.chrome.browser.preferences.ChromeImageViewPreferenceCompat; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.widget.RoundedIconGenerator; @@ -28,8 +27,8 @@ /** * A preference that displays a website's favicon and URL and, optionally, the amount of local * storage used by the site. This preference can also display an additional icon on the right side - * of the preference. See {@link ChromeImageViewPreference} for more details on how this icon can - * be used. + * of the preference. See {@link ChromeImageViewPreferenceCompat} for more details on how this icon + * can be used. */ class WebsitePreference extends ChromeImageViewPreferenceCompat implements FaviconImageCallback { private final Website mSite;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java index 9356c825..02cf286 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -27,7 +27,7 @@ /** Manages whether to check update for the WebAPK, and starts update check if needed. */ private WebApkUpdateManager mUpdateManager; - /** The start time that the activity becomes focused. */ + /** The start time that the activity becomes focused in milliseconds since boot. */ private long mStartTime; private static final String TAG = "cr_WebApkActivity"; @@ -110,8 +110,10 @@ @Override public void onPauseWithNative() { WebApkInfo info = (WebApkInfo) getWebappInfo(); - WebApkUma.recordWebApkSessionDuration( - info.distributor(), SystemClock.elapsedRealtime() - mStartTime); + long sessionDuration = SystemClock.elapsedRealtime() - mStartTime; + WebApkUma.recordWebApkSessionDuration(info.distributor(), sessionDuration); + WebApkUkmRecorder.recordWebApkSessionDuration( + info.manifestUrl(), info.distributor(), info.webApkVersionCode(), sessionDuration); super.onPauseWithNative(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java index 7e15ca4..85328d89 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
@@ -138,6 +138,7 @@ public static final String RESOURCE_SHORT_NAME = "short_name"; public static final String RESOURCE_STRING_TYPE = "string"; + // This enum is used to back UMA/UKM histograms, and should therefore be treated as append-only. @IntDef({WebApkDistributor.BROWSER, WebApkDistributor.DEVICE_POLICY, WebApkDistributor.OTHER}) @Retention(RetentionPolicy.SOURCE) public @interface WebApkDistributor { @@ -157,6 +158,7 @@ private @WebApkDistributor int mDistributor; private ShareTarget mShareTarget; private String mShareTargetActivityName; + private int mApkVersionCode; private Map<String, String> mIconUrlToMurmur2HashMap; private boolean mIsSplashProvidedByWebApk; @@ -282,9 +284,12 @@ } Context appContext = ContextUtils.getApplicationContext(); + PackageManager pm = appContext.getPackageManager(); Resources res = null; + int apkVersion = 0; try { - res = appContext.getPackageManager().getResourcesForApplication(webApkPackageName); + res = pm.getResourcesForApplication(webApkPackageName); + apkVersion = pm.getPackageInfo(webApkPackageName, 0).versionCode; } catch (PackageManager.NameNotFoundException e) { return null; } @@ -337,6 +342,9 @@ int primaryIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.ICON_ID, 0); Bitmap primaryIcon = decodeBitmapFromDrawable(res, primaryIconId); + boolean isPrimaryIconMaskable = + IntentUtils.safeGetBoolean(bundle, WebApkMetaDataKeys.IS_ICON_MASKABLE, false); + int badgeIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.BADGE_ICON_ID, 0); Bitmap badgeIcon = decodeBitmapFromDrawable(res, badgeIconId); @@ -355,9 +363,10 @@ return create(WebApkConstants.WEBAPK_ID_PREFIX + webApkPackageName, url, scope, new Icon(primaryIcon), new Icon(badgeIcon), new Icon(splashIcon), name, shortName, displayMode, orientation, source, themeColor, backgroundColor, - defaultBackgroundColor, webApkPackageName, shellApkVersion, manifestUrl, - manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget, - shareTargetActivityName, forceNavigation, isSplashProvidedByWebApk, shareData); + defaultBackgroundColor, isPrimaryIconMaskable, webApkPackageName, shellApkVersion, + manifestUrl, manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget, + shareTargetActivityName, forceNavigation, isSplashProvidedByWebApk, shareData, + apkVersion); } /** @@ -377,6 +386,7 @@ * @param backgroundColor The background color of the WebAPK. * @param defaultBackgroundColor The background color to use if the Web Manifest does not * provide a background color. + * @param isPrimaryIconMaskable Is the primary icon maskable. * @param webApkPackageName The package of the WebAPK. * @param shellApkVersion Version of the code in //chrome/android/webapk/shell_apk. * @param manifestUrl URL of the Web Manifest. @@ -395,15 +405,17 @@ * display the splash screen and (2) has a content provider * which provides a screenshot of the splash screen. * @param shareData Shared information from the share intent. + * @param webApkVersionCode WebAPK's version code. */ public static WebApkInfo create(String id, String url, String scope, Icon primaryIcon, Icon badgeIcon, Icon splashIcon, String name, String shortName, @WebDisplayMode int displayMode, int orientation, int source, long themeColor, - long backgroundColor, int defaultBackgroundColor, String webApkPackageName, - int shellApkVersion, String manifestUrl, String manifestStartUrl, - @WebApkDistributor int distributor, Map<String, String> iconUrlToMurmur2HashMap, - ShareTarget shareTarget, String shareTargetActivityName, boolean forceNavigation, - boolean isSplashProvidedByWebApk, ShareData shareData) { + long backgroundColor, int defaultBackgroundColor, boolean isPrimaryIconMaskable, + String webApkPackageName, int shellApkVersion, String manifestUrl, + String manifestStartUrl, @WebApkDistributor int distributor, + Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget, + String shareTargetActivityName, boolean forceNavigation, + boolean isSplashProvidedByWebApk, ShareData shareData, int webApkVersionCode) { if (id == null || url == null || manifestStartUrl == null || webApkPackageName == null) { Log.e(TAG, "Incomplete data provided: " + id + ", " + url + ", " + manifestStartUrl + ", " @@ -420,22 +432,23 @@ return new WebApkInfo(id, url, scope, primaryIcon, badgeIcon, splashIcon, name, shortName, displayMode, orientation, source, themeColor, backgroundColor, - defaultBackgroundColor, webApkPackageName, shellApkVersion, manifestUrl, - manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget, - shareTargetActivityName, forceNavigation, isSplashProvidedByWebApk, shareData); + defaultBackgroundColor, isPrimaryIconMaskable, webApkPackageName, shellApkVersion, + manifestUrl, manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget, + shareTargetActivityName, forceNavigation, isSplashProvidedByWebApk, shareData, + webApkVersionCode); } protected WebApkInfo(String id, String url, String scope, Icon primaryIcon, Icon badgeIcon, Icon splashIcon, String name, String shortName, @WebDisplayMode int displayMode, int orientation, int source, long themeColor, long backgroundColor, - int defaultBackgroundColor, String webApkPackageName, int shellApkVersion, - String manifestUrl, String manifestStartUrl, @WebApkDistributor int distributor, - Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget, - String shareTargetActivityName, boolean forceNavigation, - boolean isSplashProvidedByWebApk, ShareData shareData) { + int defaultBackgroundColor, boolean isPrimaryIconMaskable, String webApkPackageName, + int shellApkVersion, String manifestUrl, String manifestStartUrl, + @WebApkDistributor int distributor, Map<String, String> iconUrlToMurmur2HashMap, + ShareTarget shareTarget, String shareTargetActivityName, boolean forceNavigation, + boolean isSplashProvidedByWebApk, ShareData shareData, int webApkVersionCode) { super(id, url, scope, primaryIcon, name, shortName, displayMode, orientation, source, themeColor, backgroundColor, defaultBackgroundColor, false /* isIconGenerated */, - false /* isIconAdaptive */, forceNavigation); + isPrimaryIconMaskable /* isIconAdaptive */, forceNavigation); mBadgeIcon = badgeIcon; mSplashIcon = splashIcon; mApkPackageName = webApkPackageName; @@ -451,6 +464,7 @@ mShareTarget = new ShareTarget(); } mShareTargetActivityName = shareTargetActivityName; + mApkVersionCode = webApkVersionCode; } protected WebApkInfo() {} @@ -481,6 +495,13 @@ return mShareTargetActivityName; } + /** + * Returns the WebAPK's version code. + */ + public int webApkVersionCode() { + return mApkVersionCode; + } + @Override public boolean isForWebApk() { return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUkmRecorder.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUkmRecorder.java new file mode 100644 index 0000000..ba17c7b --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUkmRecorder.java
@@ -0,0 +1,23 @@ +// 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. + +package org.chromium.chrome.browser.webapps; + +/** + * A class to record User Keyed Metrics relevant to WebAPKs. This + * will allow us to concentrate on the use cases for the most used WebAPKs. + */ +public class WebApkUkmRecorder { + /** + * Records the duration, in exponentially-bucketed milliseconds, of a WebAPK session (from + * launch/foreground to background). + */ + public static void recordWebApkSessionDuration(String manifestUrl, + @WebApkInfo.WebApkDistributor int distributor, int versionCode, long duration) { + nativeRecordSessionDuration(manifestUrl, distributor, versionCode, duration); + } + + private static native void nativeRecordSessionDuration( + String manifestUrl, int distributor, int versionCode, long duration); +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java index 4ad4d92..52a967a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java
@@ -100,11 +100,11 @@ @CalledByNative protected void onDataAvailable(String manifestStartUrl, String scopeUrl, String name, String shortName, String primaryIconUrl, String primaryIconMurmur2Hash, - Bitmap primaryIconBitmap, String badgeIconUrl, String badgeIconMurmur2Hash, - Bitmap badgeIconBitmap, String[] iconUrls, @WebDisplayMode int displayMode, - int orientation, long themeColor, long backgroundColor, String shareAction, - String shareParamsTitle, String shareParamsText, String shareParamsUrl, - boolean isShareMethodPost, boolean isShareEncTypeMultipart, + Bitmap primaryIconBitmap, boolean isPrimaryIconMaskable, String badgeIconUrl, + String badgeIconMurmur2Hash, Bitmap badgeIconBitmap, String[] iconUrls, + @WebDisplayMode int displayMode, int orientation, long themeColor, long backgroundColor, + String shareAction, String shareParamsTitle, String shareParamsText, + String shareParamsUrl, boolean isShareMethodPost, boolean isShareEncTypeMultipart, String[] shareParamsFileNames, String[][] shareParamsAccepts) { Context appContext = ContextUtils.getApplicationContext(); @@ -130,10 +130,11 @@ WebApkInfo info = WebApkInfo.create(mOldInfo.id(), mOldInfo.uri().toString(), scopeUrl, new WebApkInfo.Icon(primaryIconBitmap), new WebApkInfo.Icon(badgeIconBitmap), null, name, shortName, displayMode, orientation, mOldInfo.source(), themeColor, - backgroundColor, defaultBackgroundColor, mOldInfo.webApkPackageName(), - mOldInfo.shellApkVersion(), mOldInfo.manifestUrl(), manifestStartUrl, - WebApkInfo.WebApkDistributor.BROWSER, iconUrlToMurmur2HashMap, shareTarget, null, - mOldInfo.shouldForceNavigation(), mOldInfo.isSplashProvidedByWebApk(), null); + backgroundColor, defaultBackgroundColor, isPrimaryIconMaskable, + mOldInfo.webApkPackageName(), mOldInfo.shellApkVersion(), mOldInfo.manifestUrl(), + manifestStartUrl, WebApkInfo.WebApkDistributor.BROWSER, iconUrlToMurmur2HashMap, + shareTarget, null, mOldInfo.shouldForceNavigation(), + mOldInfo.isSplashProvidedByWebApk(), null, mOldInfo.webApkVersionCode()); mObserver.onGotManifestData(info, primaryIconUrl, badgeIconUrl); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java index d1275006..47af076c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java
@@ -6,8 +6,6 @@ import static org.chromium.webapk.lib.common.WebApkConstants.WEBAPK_PACKAGE_PREFIX; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; import android.graphics.Bitmap; import android.os.Handler; import android.text.TextUtils; @@ -232,21 +230,6 @@ } /** - * Reads the WebAPK's version code. Returns 0 on failure. - */ - private int readVersionCodeFromAndroidManifest(String webApkPackage) { - try { - PackageManager packageManager = - ContextUtils.getApplicationContext().getPackageManager(); - PackageInfo packageInfo = packageManager.getPackageInfo(webApkPackage, 0); - return packageInfo.versionCode; - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return 0; - } - - /** * Whether there is a new version of the //chrome/android/webapk/shell_apk code. */ private static boolean isShellApkVersionOutOfDate(WebApkInfo info) { @@ -377,7 +360,7 @@ protected void storeWebApkUpdateRequestToFile(String updateRequestPath, WebApkInfo info, String primaryIconUrl, String badgeIconUrl, boolean isManifestStale, @WebApkUpdateReason int updateReason, Callback<Boolean> callback) { - int versionCode = readVersionCodeFromAndroidManifest(info.webApkPackageName()); + int versionCode = info.webApkVersionCode(); int size = info.iconUrlToMurmur2HashMap().size(); String[] iconUrls = new String[size]; String[] iconHashes = new String[size]; @@ -391,11 +374,11 @@ WebApkUpdateManagerJni.get().storeWebApkUpdateRequestToFile(updateRequestPath, info.manifestStartUrl(), info.scopeUri().toString(), info.name(), info.shortName(), - primaryIconUrl, info.icon(), badgeIconUrl, info.badgeIcon(), iconUrls, iconHashes, - info.displayMode(), info.orientation(), info.themeColor(), info.backgroundColor(), - info.shareTarget().getAction(), info.shareTarget().getParamTitle(), - info.shareTarget().getParamText(), info.shareTarget().getParamUrl(), - info.shareTarget().isShareMethodPost(), + primaryIconUrl, info.icon(), info.isIconAdaptive(), badgeIconUrl, info.badgeIcon(), + iconUrls, iconHashes, info.displayMode(), info.orientation(), info.themeColor(), + info.backgroundColor(), info.shareTarget().getAction(), + info.shareTarget().getParamTitle(), info.shareTarget().getParamText(), + info.shareTarget().getParamUrl(), info.shareTarget().isShareMethodPost(), info.shareTarget().isShareEncTypeMultipart(), info.shareTarget().getFileNames(), info.shareTarget().getFileAccepts(), info.manifestUrl(), info.webApkPackageName(), versionCode, isManifestStale, updateReason, callback); @@ -405,14 +388,15 @@ interface Natives { public void storeWebApkUpdateRequestToFile(String updateRequestPath, String startUrl, String scope, String name, String shortName, String primaryIconUrl, - Bitmap primaryIcon, String badgeIconUrl, Bitmap badgeIcon, String[] iconUrls, - String[] iconHashes, @WebDisplayMode int displayMode, int orientation, - long themeColor, long backgroundColor, String shareTargetAction, - String shareTargetParamTitle, String shareTargetParamText, - String shareTargetParamUrl, boolean shareTargetParamIsMethodPost, - boolean shareTargetParamIsEncTypeMultipart, String[] shareTargetParamFileNames, - Object[] shareTargetParamAccepts, String manifestUrl, String webApkPackage, - int webApkVersion, boolean isManifestStale, @WebApkUpdateReason int updateReason, + Bitmap primaryIcon, boolean isPrimaryIconMaskable, String badgeIconUrl, + Bitmap badgeIcon, String[] iconUrls, String[] iconHashes, + @WebDisplayMode int displayMode, int orientation, long themeColor, + long backgroundColor, String shareTargetAction, String shareTargetParamTitle, + String shareTargetParamText, String shareTargetParamUrl, + boolean shareTargetParamIsMethodPost, boolean shareTargetParamIsEncTypeMultipart, + String[] shareTargetParamFileNames, Object[] shareTargetParamAccepts, + String manifestUrl, String webApkPackage, int webApkVersion, + boolean isManifestStale, @WebApkUpdateReason int updateReason, Callback<Boolean> callback); public void updateWebApkFromFile(String updateRequestPath, WebApkUpdateCallback callback); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java index b2c577e..77d7470d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappSplashDelegate.java
@@ -135,6 +135,7 @@ Bitmap selectedIcon = splashImage; boolean selectedIconGenerated = false; + // TODO(crbug.com/977173): assign selectedIconAdaptive to correct value boolean selectedIconAdaptive = false; if (selectedIcon == null) { selectedIcon = mWebappInfo.icon(); @@ -190,7 +191,7 @@ splashView.setBackgroundColor(backgroundColor); Bitmap splashBitmap = null; - try (StrictModeContext smc = StrictModeContext.allowDiskReads()) { + try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) { splashBitmap = FileUtils.queryBitmapFromContentProvider(appContext, Uri.parse(WebApkCommonUtils.generateSplashContentProviderUri( mWebappInfo.webApkPackageName())));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/dragreorder/DragReorderableListAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/dragreorder/DragReorderableListAdapter.java index 45c08570..24fdb1aa8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/dragreorder/DragReorderableListAdapter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/dragreorder/DragReorderableListAdapter.java
@@ -14,7 +14,6 @@ import android.support.v7.widget.helper.ItemTouchHelper; import org.chromium.base.ApiCompatibilityUtils; -import org.chromium.base.Log; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; @@ -28,7 +27,6 @@ */ public abstract class DragReorderableListAdapter<T> extends RecyclerView.Adapter<ViewHolder> { private static final int ANIMATION_DELAY_MS = 100; - private static final String TAG = "DragAdapter"; protected final Context mContext; @@ -237,12 +235,10 @@ int increment = start < end ? 1 : -1; int i = start; while (i != end) { - Log.i(TAG, "Moving ViewHolder %s from %d to %d", viewHolder, i, i + increment); i += increment; mTouchHelperCallback.onMove( mRecyclerView, viewHolder, mRecyclerView.findViewHolderForAdapterPosition(i)); } - Log.i(TAG, "Letting go of ViewHolder %s", viewHolder); mTouchHelperCallback.onSelectedChanged(viewHolder, ItemTouchHelper.ACTION_STATE_IDLE); mTouchHelperCallback.clearView(mRecyclerView, viewHolder); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/dragreorder/DragStateDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/dragreorder/DragStateDelegate.java index a2e7d75..3ac3a734 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/dragreorder/DragStateDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/dragreorder/DragStateDelegate.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.widget.dragreorder; +import org.chromium.base.VisibleForTesting; + /** * Responsible for keeping track of the drag state (whether drag is enabled, and if so, whether drag * is active). @@ -21,4 +23,7 @@ * dragged). Activating drag is only valid if drag is currently enabled. */ boolean getDragActive(); + + @VisibleForTesting + void setA11yStateForTesting(boolean a11yEnabled); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUpstreamTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUpstreamTest.java new file mode 100644 index 0000000..3189087e --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillUpstreamTest.java
@@ -0,0 +1,172 @@ +// 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. + +package org.chromium.chrome.browser.autofill; + +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.MediumTest; +import android.view.ViewGroup; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Restriction; +import org.chromium.base.test.util.RetryOnFailure; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.infobar.AutofillSaveCardInfoBar; +import org.chromium.chrome.browser.infobar.InfoBar; +import org.chromium.chrome.browser.infobar.InfoBarLayout; +import org.chromium.chrome.browser.sync.SyncTestRule; +import org.chromium.chrome.test.ChromeActivityTestRule; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.content_public.browser.WebContents; +import org.chromium.content_public.browser.test.util.Criteria; +import org.chromium.content_public.browser.test.util.CriteriaHelper; +import org.chromium.content_public.browser.test.util.DOMUtils; +import org.chromium.net.test.EmbeddedTestServer; +import org.chromium.ui.widget.ButtonCompat; + +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + +/** + * Integration tests for the Autofill Upstream and Expiration Date Fix Flow. + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@RetryOnFailure +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, + "enable-features=AutofillUpstreamEditableExpirationDate"}) +public class AutofillUpstreamTest { + private static final String TEST_SERVER_DIR = "components/test/data/autofill"; + private static final String TEST_FORM_URL = "/credit_card_upload_form_address_and_cc.html"; + private static final String SAVE_BUTTON_LABEL = "Save"; + private static final String CONTINUE_BUTTON_LABEL = "Continue"; + + @Rule + public SyncTestRule mSyncTestRule = new SyncTestRule(); + + @Rule + public ChromeActivityTestRule<ChromeActivity> mActivityTestRule = + new ChromeActivityTestRule<>(ChromeActivity.class); + + private EmbeddedTestServer mServer; + + @Before + public void setUp() throws Exception { + mSyncTestRule.setUpTestAccountAndSignIn(); + mServer = new EmbeddedTestServer(); + mServer.initializeNative(InstrumentationRegistry.getContext(), + EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP); + mServer.addDefaultHandlers(TEST_SERVER_DIR); + mServer.start(); + } + + @After + public void tearDown() throws Exception { + mServer.stopAndDestroyServer(); + } + + private void assertPrimaryButtonLabel(String buttonLabel) { + List<InfoBar> infobars = mActivityTestRule.getInfoBars(); + if (hasAutofillSaveCardInfobar(infobars)) { + InfoBarLayout view = (InfoBarLayout) infobars.get(0).getView(); + ButtonCompat primaryButton = view.getPrimaryButton(); + Assert.assertEquals(buttonLabel, primaryButton.getText().toString()); + } else { + Assert.fail("Save card infobar not found"); + } + } + + private void waitForSaveCardInfoBar(final ViewGroup view) { + CriteriaHelper.pollUiThread( + new Criteria("Autofill Save Card Infobar view was never added.") { + @Override + public boolean isSatisfied() { + return hasAutofillSaveCardInfobar(mActivityTestRule.getInfoBars()); + } + }); + } + + private boolean hasAutofillSaveCardInfobar(List<InfoBar> infobars) { + return (infobars != null && infobars.size() == 1 + && infobars.get(0) instanceof AutofillSaveCardInfoBar); + } + + @Test + @MediumTest + @Restriction(Restriction.RESTRICTION_TYPE_INTERNET) + public void testSaveCardInfoBarWithAllFieldsFilled() + throws InterruptedException, ExecutionException, TimeoutException { + mActivityTestRule.startMainActivityWithURL(mServer.getURL(TEST_FORM_URL)); + final WebContents webContents = mActivityTestRule.getActivity().getCurrentWebContents(); + + DOMUtils.clickNode(webContents, "fill_form"); + DOMUtils.clickNode(webContents, "submit"); + final ViewGroup view = webContents.getViewAndroidDelegate().getContainerView(); + waitForSaveCardInfoBar(view); + + assertPrimaryButtonLabel(SAVE_BUTTON_LABEL); + } + + @Test + @MediumTest + @Restriction(Restriction.RESTRICTION_TYPE_INTERNET) + public void testSaveCardInfoBarWithEmptyMonth() + throws InterruptedException, ExecutionException, TimeoutException { + mActivityTestRule.startMainActivityWithURL(mServer.getURL(TEST_FORM_URL)); + final WebContents webContents = mActivityTestRule.getActivity().getCurrentWebContents(); + + DOMUtils.clickNode(webContents, "fill_form"); + // Clear the month field + DOMUtils.clickNode(webContents, "clear_month"); + DOMUtils.clickNode(webContents, "submit"); + final ViewGroup view = webContents.getViewAndroidDelegate().getContainerView(); + waitForSaveCardInfoBar(view); + + assertPrimaryButtonLabel(CONTINUE_BUTTON_LABEL); + } + + @Test + @MediumTest + @Restriction(Restriction.RESTRICTION_TYPE_INTERNET) + public void testSaveCardInfoBarWithEmptyYear() + throws InterruptedException, ExecutionException, TimeoutException { + mActivityTestRule.startMainActivityWithURL(mServer.getURL(TEST_FORM_URL)); + final WebContents webContents = mActivityTestRule.getActivity().getCurrentWebContents(); + + DOMUtils.clickNode(webContents, "fill_form"); + // Clear the year field + DOMUtils.clickNode(webContents, "clear_year"); + DOMUtils.clickNode(webContents, "submit"); + final ViewGroup view = webContents.getViewAndroidDelegate().getContainerView(); + waitForSaveCardInfoBar(view); + + assertPrimaryButtonLabel(CONTINUE_BUTTON_LABEL); + } + + @Test + @MediumTest + @Restriction(Restriction.RESTRICTION_TYPE_INTERNET) + public void testSaveCardInfoBarWithEmptyMonthAndYear() + throws InterruptedException, ExecutionException, TimeoutException { + mActivityTestRule.startMainActivityWithURL(mServer.getURL(TEST_FORM_URL)); + final WebContents webContents = mActivityTestRule.getActivity().getCurrentWebContents(); + + DOMUtils.clickNode(webContents, "fill_form"); + // Clear the month and year field + DOMUtils.clickNode(webContents, "clear_expiration_date"); + DOMUtils.clickNode(webContents, "submit"); + final ViewGroup view = webContents.getViewAndroidDelegate().getContainerView(); + waitForSaveCardInfoBar(view); + + assertPrimaryButtonLabel(CONTINUE_BUTTON_LABEL); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/OWNERS index b946bf67..e716fed5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/OWNERS +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/OWNERS
@@ -1 +1,2 @@ -file://chrome/android/java/src/org/chromium/chrome/browser/autofill/OWNERS \ No newline at end of file +file://chrome/android/java/src/org/chromium/chrome/browser/autofill/OWNERS +per-file AutofillUpstreamTest.java=file://components/autofill/core/browser/payments/OWNERS \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkReorderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkReorderTest.java index 45262cd7..390301a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkReorderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkReorderTest.java
@@ -4,13 +4,15 @@ package org.chromium.chrome.browser.bookmarks; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + import android.support.test.filters.MediumTest; import android.support.v7.widget.RecyclerView.ViewHolder; import android.view.View; -import org.chromium.base.test.util.DisabledTest; -import org.chromium.base.test.util.Feature; -import org.chromium.chrome.browser.night_mode.NightModeTestUtils; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -23,6 +25,8 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.night_mode.NightModeTestUtils; +import org.chromium.chrome.browser.widget.ListMenuButton; import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; import org.chromium.chrome.test.util.BookmarkTestUtil; import org.chromium.chrome.test.util.browser.Features; @@ -57,22 +61,15 @@ private static final String TEST_URL_A = "http://a.com"; private static final String TAG = "BookmarkReorderTest"; - @Override - @Test - @MediumTest - @Feature({"RenderTest"}) - @DisabledTest(message = "https://crbug.com/986915") - @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class) - public void testBookmarkFolderIcon(boolean nightModeEnabled) throws Exception { - Assert.assertTrue("Expected Bookmark Reordering to be enabled", - ChromeFeatureList.isEnabled(ChromeFeatureList.REORDER_BOOKMARKS)); - super.testBookmarkFolderIcon(nightModeEnabled); + @ParameterAnnotations.UseMethodParameterBefore(NightModeTestUtils.NightModeParams.class) + public void setupNightMode(boolean nightModeEnabled) { + NightModeTestUtils.setUpNightModeForChromeActivity(nightModeEnabled); + mRenderTestRule.setNightModeEnabled(nightModeEnabled); } @Test @MediumTest - @DisabledTest(message = "https://crbug.com/986915") public void testEndIconVisibilityInSelectionMode() throws Exception { BookmarkId testId = addFolder(TEST_FOLDER_TITLE); addBookmark(TEST_TITLE_A, TEST_URL_A); @@ -88,8 +85,7 @@ View aMoreButton = testFolderA.findViewById(R.id.more); View aDragHandle = testFolderA.findViewById(R.id.drag_handle); - TestThreadUtils.runOnUiThreadBlocking( - () -> mManager.getSelectionDelegate().toggleSelectionForItem(testId)); + toggleSelectionAndEndAnimation(testId, test); // Callback occurs when Item "test" is selected. CriteriaHelper.pollUiThread(test::isChecked, "Expected item \"test\" to become selected"); @@ -141,8 +137,7 @@ .isSearching(), "Expected to enter search mode"); - TestThreadUtils.runOnUiThreadBlocking( - () -> mManager.getSelectionDelegate().toggleSelectionForItem(testId)); + toggleSelectionAndEndAnimation(testId, test); // Callback occurs when Item "test" is selected. CriteriaHelper.pollUiThread(test::isChecked, "Expected item \"test\" to become selected"); @@ -205,33 +200,22 @@ } }; - // Callback occurs upon layout changes. - CallbackHelper layoutHelper = new CallbackHelper(); - - // Perform registration to make all of these callbacks work. + // Perform registration to make callbacks work. TestThreadUtils.runOnUiThreadBlocking(() -> { mBookmarkModel.addObserver(bookmarkModelObserver); - mItemsContainer.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, - oldBottom) -> layoutHelper.notifyCalled()); }); View foo = mItemsContainer.findViewHolderForAdapterPosition(3).itemView; Assert.assertEquals("Wrong bookmark item selected.", TEST_PAGE_TITLE_FOO, ((BookmarkItemRow) foo).getTitle()); - View dragHandle = foo.findViewById(R.id.drag_handle); - - TestThreadUtils.runOnUiThreadBlocking( - () -> mManager.getSelectionDelegate().toggleSelectionForItem(fooId)); - - // Entering selection mode - items are getting redrawn. - layoutHelper.waitForCallback(); + toggleSelectionAndEndAnimation(fooId, (BookmarkRow) foo); // Starts as last bookmark (2nd index) and ends as 0th bookmark (promo header not included). TestThreadUtils.runOnUiThreadBlocking(() -> { ((ReorderBookmarkItemsAdapter) mItemsContainer.getAdapter()).simulateDragForTests(3, 1); }); + modelReorderHelper.waitForCallback(0, 1); RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -280,33 +264,23 @@ } }; - // Callback occurs upon layout changes. - CallbackHelper layoutHelper = new CallbackHelper(); - - // Perform registration to make all of these callbacks work. + // Perform registration to make callbacks work. TestThreadUtils.runOnUiThreadBlocking(() -> { mBookmarkModel.addObserver(bookmarkModelObserver); - mItemsContainer.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, - oldBottom) -> layoutHelper.notifyCalled()); }); View test = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, ((BookmarkFolderRow) test).getTitle()); - View dragHandle = test.findViewById(R.id.drag_handle); - TestThreadUtils.runOnUiThreadBlocking( - () -> mManager.getSelectionDelegate().toggleSelectionForItem(testId)); - - // Entering selection mode - items are getting redrawn. - layoutHelper.waitForCallback(); + toggleSelectionAndEndAnimation(testId, (BookmarkRow) test); // Starts as 0th bookmark (not counting promo header) and ends as last (index 3). TestThreadUtils.runOnUiThreadBlocking(() -> { ((ReorderBookmarkItemsAdapter) mItemsContainer.getAdapter()).simulateDragForTests(1, 4); }); + modelReorderHelper.waitForCallback(0, 1); RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -351,27 +325,16 @@ modelReorderHelper.notifyCalled(); } }; - - // Callback occurs upon layout changes. - CallbackHelper layoutHelper = new CallbackHelper(); - - // Perform registration to make all of these callbacks work. + // Perform registration to make callbacks work. TestThreadUtils.runOnUiThreadBlocking(() -> { mBookmarkModel.addObserver(bookmarkModelObserver); - mItemsContainer.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, - oldBottom) -> layoutHelper.notifyCalled()); }); View test = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, ((BookmarkFolderRow) test).getTitle()); - TestThreadUtils.runOnUiThreadBlocking( - () -> mManager.getSelectionDelegate().toggleSelectionForItem(testId)); - - // Entering selection mode - items are getting redrawn. - layoutHelper.waitForCallback(); + toggleSelectionAndEndAnimation(testId, (BookmarkRow) test); // Starts as 0th bookmark (not counting promo header) and ends at the 1st index. TestThreadUtils.runOnUiThreadBlocking(() -> { @@ -396,23 +359,10 @@ openBookmarkManager(); - // Callback occurs upon layout changes. - CallbackHelper layoutHelper = new CallbackHelper(); - - // Perform registration to make all of these callbacks work. - TestThreadUtils.runOnUiThreadBlocking(() -> { - mItemsContainer.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, - oldBottom) -> layoutHelper.notifyCalled()); - }); - ViewHolder promo = mItemsContainer.findViewHolderForAdapterPosition(0); - TestThreadUtils.runOnUiThreadBlocking( - () -> mManager.getSelectionDelegate().toggleSelectionForItem(testId)); - - // Entering selection mode - items are getting redrawn. - layoutHelper.waitForCallback(); + toggleSelectionAndEndAnimation( + testId, (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView); ReorderBookmarkItemsAdapter adapter = ((ReorderBookmarkItemsAdapter) mItemsContainer.getAdapter()); @@ -428,23 +378,10 @@ BookmarkId testId = addFolderWithPartner(TEST_FOLDER_TITLE); openBookmarkManager(); - // Callback occurs upon layout changes. - CallbackHelper layoutHelper = new CallbackHelper(); - - // Perform registration to make all of these callbacks work. - TestThreadUtils.runOnUiThreadBlocking(() -> { - mItemsContainer.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, - oldBottom) -> layoutHelper.notifyCalled()); - }); - ViewHolder partner = mItemsContainer.findViewHolderForAdapterPosition(2); - TestThreadUtils.runOnUiThreadBlocking( - () -> mManager.getSelectionDelegate().toggleSelectionForItem(testId)); - - // Entering selection mode - items are getting redrawn. - layoutHelper.waitForCallback(); + toggleSelectionAndEndAnimation( + testId, (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView); ReorderBookmarkItemsAdapter adapter = ((ReorderBookmarkItemsAdapter) mItemsContainer.getAdapter()); @@ -462,25 +399,12 @@ openBookmarkManager(); - // Callback occurs upon layout changes. - CallbackHelper layoutHelper = new CallbackHelper(); - - // Perform registration to make all of these callbacks work. - TestThreadUtils.runOnUiThreadBlocking(() -> { - mItemsContainer.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, - oldBottom) -> layoutHelper.notifyCalled()); - }); - ViewHolder test = mItemsContainer.findViewHolderForAdapterPosition(1); Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, ((BookmarkFolderRow) test.itemView).getTitle()); - TestThreadUtils.runOnUiThreadBlocking( - () -> mManager.getSelectionDelegate().toggleSelectionForItem(aId)); - - // Entering selection mode - items are getting redrawn. - layoutHelper.waitForCallback(); + toggleSelectionAndEndAnimation( + aId, (BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView); ReorderBookmarkItemsAdapter adapter = ((ReorderBookmarkItemsAdapter) mItemsContainer.getAdapter()); @@ -497,27 +421,9 @@ openBookmarkManager(); - // Callback occurs upon changes to the bookmark model. - CallbackHelper modelReorderHelper = new CallbackHelper(); - BookmarkBridge.BookmarkModelObserver bookmarkModelObserver = - new BookmarkBridge.BookmarkModelObserver() { - @Override - public void bookmarkModelChanged() { - modelReorderHelper.notifyCalled(); - } - }; - - // Callback occurs upon layout changes. - CallbackHelper layoutHelper = new CallbackHelper(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - mBookmarkModel.addObserver(bookmarkModelObserver); - mItemsContainer.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, - oldBottom) -> layoutHelper.notifyCalled()); - }); - View promo = mItemsContainer.findViewHolderForAdapterPosition(0).itemView; TouchCommon.longPressView(promo); + RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); Assert.assertFalse("Expected that we would not be in selection mode " + "after long pressing on promo view.", mManager.getSelectionDelegate().isSelectionEnabled()); @@ -529,32 +435,129 @@ addFolderWithPartner(TEST_FOLDER_TITLE); openBookmarkManager(); - // Callback occurs upon changes to the bookmark model. - CallbackHelper modelReorderHelper = new CallbackHelper(); - BookmarkBridge.BookmarkModelObserver bookmarkModelObserver = - new BookmarkBridge.BookmarkModelObserver() { - @Override - public void bookmarkModelChanged() { - modelReorderHelper.notifyCalled(); - } - }; - - // Callback occurs upon layout changes. - CallbackHelper layoutHelper = new CallbackHelper(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - mBookmarkModel.addObserver(bookmarkModelObserver); - mItemsContainer.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, - oldBottom) -> layoutHelper.notifyCalled()); - }); - View partner = mItemsContainer.findViewHolderForAdapterPosition(2).itemView; TouchCommon.longPressView(partner); + RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); Assert.assertFalse("Expected that we would not be in selection mode " + "after long pressing on partner bookmark.", mManager.getSelectionDelegate().isSelectionEnabled()); } + @Test + @MediumTest + public void testMoveUpMenuItem() throws Exception { + addBookmark(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); + addFolder(TEST_FOLDER_TITLE); + openBookmarkManager(); + + View google = mItemsContainer.findViewHolderForAdapterPosition(2).itemView; + Assert.assertEquals("Wrong bookmark item selected.", TEST_PAGE_TITLE_GOOGLE, + ((BookmarkItemRow) google).getTitle()); + View more = google.findViewById(R.id.more); + TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); + onView(withText("Move up")).perform(click()); + + // Confirm that the "Google" bookmark is now on top, and that the "test" folder is 2nd + Assert.assertTrue( + ((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView) + .getTitle() + .equals(TEST_PAGE_TITLE_GOOGLE)); + Assert.assertTrue( + ((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView) + .getTitle() + .equals(TEST_FOLDER_TITLE)); + } + + @Test + @MediumTest + public void testMoveDownMenuItem() throws Exception { + addBookmark(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); + addFolder(TEST_FOLDER_TITLE); + openBookmarkManager(); + + View testFolder = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; + Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, + ((BookmarkFolderRow) testFolder).getTitle()); + ListMenuButton more = testFolder.findViewById(R.id.more); + TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); + onView(withText("Move down")).perform(click()); + + // Confirm that the "Google" bookmark is now on top, and that the "test" folder is 2nd + Assert.assertTrue( + ((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(1).itemView) + .getTitle() + .equals(TEST_PAGE_TITLE_GOOGLE)); + Assert.assertTrue( + ((BookmarkRow) mItemsContainer.findViewHolderForAdapterPosition(2).itemView) + .getTitle() + .equals(TEST_FOLDER_TITLE)); + } + + @Test + @MediumTest + public void testMoveDownGoneForBottomElement() throws Exception { + addBookmarkWithPartner(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); + addFolderWithPartner(TEST_FOLDER_TITLE); + openBookmarkManager(); + + View google = mItemsContainer.findViewHolderForAdapterPosition(2).itemView; + Assert.assertEquals("Wrong bookmark item selected.", TEST_PAGE_TITLE_GOOGLE, + ((BookmarkItemRow) google).getTitle()); + View more = google.findViewById(R.id.more); + TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); + onView(withText("Move down")).check(doesNotExist()); + } + + @Test + @MediumTest + public void testMoveUpGoneForTopElement() throws Exception { + addBookmark(TEST_PAGE_TITLE_GOOGLE, TEST_URL_A); + addFolder(TEST_FOLDER_TITLE); + openBookmarkManager(); + + View testFolder = mItemsContainer.findViewHolderForAdapterPosition(1).itemView; + Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, + ((BookmarkFolderRow) testFolder).getTitle()); + ListMenuButton more = testFolder.findViewById(R.id.more); + TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); + onView(withText("Move up")).check(doesNotExist()); + } + + @Test + @MediumTest + public void testMoveButtonsGoneInSearchMode() throws Exception { + addFolder(TEST_FOLDER_TITLE); + openBookmarkManager(); + + View searchButton = mManager.getToolbarForTests().findViewById(R.id.search_menu_id); + TestThreadUtils.runOnUiThreadBlocking(searchButton::performClick); + + // Callback occurs when Item "test" is selected. + CriteriaHelper.pollUiThread(() + -> mBookmarkActivity.getManagerForTesting() + .getToolbarForTests() + .isSearching(), + "Expected to enter search mode"); + + View testFolder = mItemsContainer.findViewHolderForAdapterPosition(0).itemView; + Assert.assertEquals("Wrong bookmark item selected.", TEST_FOLDER_TITLE, + ((BookmarkFolderRow) testFolder).getTitle()); + View more = testFolder.findViewById(R.id.more); + TestThreadUtils.runOnUiThreadBlocking(more::callOnClick); + + onView(withText("Move up")).check(doesNotExist()); + onView(withText("Move down")).check(doesNotExist()); + } + + @Override + protected void openBookmarkManager() throws InterruptedException { + super.openBookmarkManager(); + TestThreadUtils.runOnUiThreadBlocking(() -> { + mManager.getDragStateDelegate().setA11yStateForTesting(false); + BookmarkPromoHeader.forcePromoStateForTests(BookmarkPromoHeader.PromoState.PROMO_SYNC); + }); + } + /** * Loads an empty partner bookmarks folder for testing. The partner bookmarks folder will appear * in the mobile bookmarks folder.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java index 34b37b26..66a2b992 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
@@ -51,6 +51,7 @@ import org.chromium.chrome.test.util.MenuUtils; import org.chromium.chrome.test.util.RenderTestRule; import org.chromium.chrome.test.util.browser.Features; +import org.chromium.chrome.test.util.browser.RecyclerViewTestUtils; import org.chromium.components.bookmarks.BookmarkId; import org.chromium.components.bookmarks.BookmarkType; import org.chromium.components.sync.AndroidSyncSettings; @@ -141,8 +142,8 @@ protected void openBookmarkManager() throws InterruptedException { if (mActivityTestRule.getActivity().isTablet()) { mActivityTestRule.loadUrl(UrlConstants.BOOKMARKS_URL); - mItemsContainer = - (RecyclerView) mActivityTestRule.getActivity().findViewById(R.id.recycler_view); + mItemsContainer = mActivityTestRule.getActivity().findViewById(R.id.recycler_view); + mItemsContainer.setItemAnimator(null); // Disable animation to reduce flakiness. mManager = ((BookmarkPage) mActivityTestRule.getActivity() .getActivityTab() .getNativePage()) @@ -153,7 +154,7 @@ InstrumentationRegistry.getInstrumentation(), BookmarkActivity.class, new MenuUtils.MenuActivityTrigger(InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity(), R.id.all_bookmarks_menu_id)); - mItemsContainer = (RecyclerView) mBookmarkActivity.findViewById(R.id.recycler_view); + mItemsContainer = mBookmarkActivity.findViewById(R.id.recycler_view); mItemsContainer.setItemAnimator(null); // Disable animation to reduce flakiness. mManager = mBookmarkActivity.getManagerForTesting(); } @@ -367,14 +368,16 @@ // Start searching without entering a query. TestThreadUtils.runOnUiThreadBlocking(manager::openSearchUI); + RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); Assert.assertEquals("Wrong state, should be searching", BookmarkUIState.STATE_SEARCHING, manager.getCurrentState()); // Select the folder and delete it. + toggleSelectionAndEndAnimation(testFolder, + (BookmarkRow) mItemsContainer.findViewHolderForLayoutPosition(2).itemView); TestThreadUtils.runOnUiThreadBlocking( - () -> manager.getSelectionDelegate().toggleSelectionForItem(getIdByPosition(0))); - TestThreadUtils.runOnUiThreadBlocking( - () -> manager.getToolbarForTests().onMenuItemClick( + () + -> manager.getToolbarForTests().onMenuItemClick( manager.getToolbarForTests().getMenu().findItem( R.id.selection_mode_delete_menu_id))); @@ -418,7 +421,7 @@ @ParameterAnnotations.UseMethodParameter(NightModeTestUtils.NightModeParams.class) public void testBookmarkFolderIcon(boolean nightModeEnabled) throws Exception { BookmarkPromoHeader.forcePromoStateForTests(BookmarkPromoHeader.PromoState.PROMO_NONE); - addFolder(TEST_FOLDER_TITLE); + BookmarkId testId = addFolder(TEST_FOLDER_TITLE); openBookmarkManager(); RecyclerView.Adapter adapter = getAdapter(); @@ -430,21 +433,14 @@ .findViewHolderForAdapterPosition(0) .itemView; - TestThreadUtils.runOnUiThreadBlocking(() -> { - itemView.performLongClick(); - itemView.endAnimationsForTests(); - manager.getToolbarForTests().endAnimationsForTesting(); - }); + toggleSelectionAndEndAnimation(getIdByPosition(0), itemView); - // Callback occurs when Item "test" is selected. + // Make sure the Item "test" is selected. CriteriaHelper.pollUiThread( itemView::isChecked, "Expected item \"test\" to become selected"); mRenderTestRule.render(manager.getView(), "bookmark_manager_folder_selected"); - - TestThreadUtils.runOnUiThreadBlocking( - () -> manager.getSelectionDelegate().toggleSelectionForItem(getIdByPosition(0))); - + toggleSelectionAndEndAnimation(getIdByPosition(0), itemView); mRenderTestRule.render(manager.getView(), "bookmark_manager_one_folder"); } @@ -511,6 +507,15 @@ }); } + protected void toggleSelectionAndEndAnimation(BookmarkId id, BookmarkRow view) { + TestThreadUtils.runOnUiThreadBlocking(() -> { + mManager.getSelectionDelegate().toggleSelectionForItem(id); + view.endAnimationsForTests(); + mManager.getToolbarForTests().endAnimationsForTesting(); + }); + RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer); + } + protected BookmarkId addBookmark(final String title, final String url) throws InterruptedException, ExecutionException { readPartnerBookmarks();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java index ee49b73..3983bfd 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/PreferencesTest.java
@@ -15,9 +15,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceScreen; import android.provider.Settings; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; @@ -57,8 +54,6 @@ import org.chromium.content_public.browser.test.util.UiUtils; import org.chromium.policy.test.annotations.Policies; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.text.NumberFormat; import java.util.List; import java.util.concurrent.Callable; @@ -86,22 +81,6 @@ return (Preferences) activity; } - public static void clickPreference(PreferenceFragment fragment, Preference preference) { - try { - Method performClick = Preference.class.getDeclaredMethod("performClick", - PreferenceScreen.class); - performClick.invoke(preference, fragment.getPreferenceScreen()); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (IllegalArgumentException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } - } - /** * Change search engine and make sure it works correctly. */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninTest.java index f92979d..a040edb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/SigninTest.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.signin; -import android.app.Activity; import android.app.Instrumentation.ActivityMonitor; import android.content.Context; import android.content.DialogInterface; @@ -13,6 +12,7 @@ import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; import android.support.v7.preference.Preference; import android.widget.Button; @@ -406,9 +406,9 @@ signOutPref.getOnPreferenceClickListener().onPreferenceClick(signOutPref); } - private void acceptAlertDialogWithTag(Activity activity, String tag) { + private void acceptAlertDialogWithTag(AppCompatActivity activity, String tag) { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - DialogFragment fragment = ActivityUtils.waitForFragment(activity, tag); + DialogFragment fragment = ActivityUtils.waitForFragmentCompat(activity, tag); AlertDialog dialog = (AlertDialog) fragment.getDialog(); Assert.assertTrue(dialog != null); Assert.assertTrue(dialog.isShowing());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FakeProfileSyncService.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FakeProfileSyncService.java index 1ce5e78..8ae0ee6 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FakeProfileSyncService.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/FakeProfileSyncService.java
@@ -15,6 +15,7 @@ public class FakeProfileSyncService extends ProfileSyncService { private boolean mEngineInitialized; private int mNumberOfSyncedDevices; + private boolean mPassphraseRequiredForDecryption; private Set<Integer> mChosenTypes = new HashSet<>(); public FakeProfileSyncService() { @@ -53,4 +54,13 @@ public Set<Integer> getPreferredDataTypes() { return mChosenTypes; } + + @Override + public boolean isPassphraseRequiredForDecryption() { + return mPassphraseRequiredForDecryption; + } + + public void setPassphraseRequiredForDecryption(boolean passphraseRequiredForDecryption) { + mPassphraseRequiredForDecryption = passphraseRequiredForDecryption; + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncPreferencesTest.java new file mode 100644 index 0000000..22554333 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncPreferencesTest.java
@@ -0,0 +1,551 @@ +// 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. + +package org.chromium.chrome.browser.sync; + +import android.app.Dialog; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AlertDialog; +import android.support.v7.preference.CheckBoxPreference; +import android.support.v7.preference.Preference; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisabledTest; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.autofill.PersonalDataManager; +import org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat; +import org.chromium.chrome.browser.preferences.Preferences; +import org.chromium.chrome.browser.preferences.sync.ManageSyncPreferences; +import org.chromium.chrome.browser.sync.ui.PassphraseCreationDialogFragment; +import org.chromium.chrome.browser.sync.ui.PassphraseDialogFragment; +import org.chromium.chrome.browser.sync.ui.PassphraseTypeDialogFragment; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.util.ActivityUtils; +import org.chromium.chrome.test.util.browser.sync.SyncTestUtil; +import org.chromium.components.sync.ModelType; +import org.chromium.components.sync.Passphrase; +import org.chromium.content_public.browser.test.util.TestThreadUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Tests for ManageSyncPreferences. + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class ManageSyncPreferencesTest { + private static final String TAG = "ManageSyncPreferencesTest"; + + /** + * Maps ModelTypes to their UI element IDs. + */ + private static final Map<Integer, String> UI_DATATYPES = new HashMap<>(); + + static { + UI_DATATYPES.put(ModelType.AUTOFILL, ManageSyncPreferences.PREF_SYNC_AUTOFILL); + UI_DATATYPES.put(ModelType.BOOKMARKS, ManageSyncPreferences.PREF_SYNC_BOOKMARKS); + UI_DATATYPES.put(ModelType.TYPED_URLS, ManageSyncPreferences.PREF_SYNC_HISTORY); + UI_DATATYPES.put(ModelType.PASSWORDS, ManageSyncPreferences.PREF_SYNC_PASSWORDS); + UI_DATATYPES.put(ModelType.PROXY_TABS, ManageSyncPreferences.PREF_SYNC_RECENT_TABS); + UI_DATATYPES.put(ModelType.PREFERENCES, ManageSyncPreferences.PREF_SYNC_SETTINGS); + } + + private Preferences mPreferences; + + @Rule + public SyncTestRule mSyncTestRule = new SyncTestRule(); + + @After + public void tearDown() throws Exception { + TestThreadUtils.runOnUiThreadBlocking(() -> ProfileSyncService.resetForTests()); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testSyncEverythingAndDataTypes() { + mSyncTestRule.setUpTestAccountAndSignIn(); + SyncTestUtil.waitForSyncActive(); + ManageSyncPreferences fragment = startManageSyncPreferences(); + ChromeSwitchPreferenceCompat syncEverything = getSyncEverything(fragment); + Collection<CheckBoxPreference> dataTypes = getDataTypes(fragment).values(); + + assertSyncOnState(fragment); + mSyncTestRule.togglePreference(syncEverything); + // When syncEverything is toggled off all data types are checked and enabled by default. + // User needs to manually uncheck to toggle sync off for data types. + for (CheckBoxPreference dataType : dataTypes) { + Assert.assertTrue(dataType.isChecked()); + Assert.assertTrue(dataType.isEnabled()); + } + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testSettingDataTypes() { + mSyncTestRule.setUpTestAccountAndSignIn(); + SyncTestUtil.waitForSyncActive(); + ManageSyncPreferences fragment = startManageSyncPreferences(); + ChromeSwitchPreferenceCompat syncEverything = getSyncEverything(fragment); + Map<Integer, CheckBoxPreference> dataTypes = getDataTypes(fragment); + + assertSyncOnState(fragment); + mSyncTestRule.togglePreference(syncEverything); + for (CheckBoxPreference dataType : dataTypes.values()) { + Assert.assertTrue(dataType.isChecked()); + Assert.assertTrue(dataType.isEnabled()); + } + + Set<Integer> expectedTypes = new HashSet<>(dataTypes.keySet()); + assertChosenDataTypesAre(expectedTypes); + mSyncTestRule.togglePreference(dataTypes.get(ModelType.AUTOFILL)); + mSyncTestRule.togglePreference(dataTypes.get(ModelType.PASSWORDS)); + expectedTypes.remove(ModelType.AUTOFILL); + expectedTypes.remove(ModelType.PASSWORDS); + + closeFragment(fragment); + assertChosenDataTypesAre(expectedTypes); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testPaymentsIntegrationChecked() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.setPaymentsIntegrationEnabled(true); + + ManageSyncPreferences fragment = startManageSyncPreferences(); + assertSyncOnState(fragment); + + CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_PAYMENTS_INTEGRATION); + + Assert.assertFalse(paymentsIntegration.isEnabled()); + Assert.assertTrue(paymentsIntegration.isChecked()); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testPaymentsIntegrationUnchecked() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.setPaymentsIntegrationEnabled(false); + + mSyncTestRule.setChosenDataTypes(false, UI_DATATYPES.keySet()); + ManageSyncPreferences fragment = startManageSyncPreferences(); + + CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_PAYMENTS_INTEGRATION); + + // All data types are enabled by default as syncEverything is toggled off. + Assert.assertTrue(paymentsIntegration.isEnabled()); + Assert.assertFalse(paymentsIntegration.isChecked()); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testPaymentsIntegrationCheckboxDisablesPaymentsIntegration() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.setPaymentsIntegrationEnabled(true); + + ManageSyncPreferences fragment = startManageSyncPreferences(); + assertSyncOnState(fragment); + ChromeSwitchPreferenceCompat syncEverything = getSyncEverything(fragment); + mSyncTestRule.togglePreference(syncEverything); + + CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_PAYMENTS_INTEGRATION); + mSyncTestRule.togglePreference(paymentsIntegration); + + closeFragment(fragment); + assertPaymentsIntegrationEnabled(false); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testPaymentsIntegrationCheckboxEnablesPaymentsIntegration() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.setPaymentsIntegrationEnabled(false); + + mSyncTestRule.setChosenDataTypes(false, UI_DATATYPES.keySet()); + ManageSyncPreferences fragment = startManageSyncPreferences(); + + CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_PAYMENTS_INTEGRATION); + mSyncTestRule.togglePreference(paymentsIntegration); + + closeFragment(fragment); + assertPaymentsIntegrationEnabled(true); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testPaymentsIntegrationCheckboxClearsServerAutofillCreditCards() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.setPaymentsIntegrationEnabled(true); + + Assert.assertFalse( + "There should be no server cards", mSyncTestRule.hasServerAutofillCreditCards()); + mSyncTestRule.addServerAutofillCreditCard(); + Assert.assertTrue( + "There should be server cards", mSyncTestRule.hasServerAutofillCreditCards()); + + ManageSyncPreferences fragment = startManageSyncPreferences(); + assertSyncOnState(fragment); + ChromeSwitchPreferenceCompat syncEverything = getSyncEverything(fragment); + mSyncTestRule.togglePreference(syncEverything); + + CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_PAYMENTS_INTEGRATION); + mSyncTestRule.togglePreference(paymentsIntegration); + + closeFragment(fragment); + assertPaymentsIntegrationEnabled(false); + + Assert.assertFalse("There should be no server cards remaining", + mSyncTestRule.hasServerAutofillCreditCards()); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testPaymentsIntegrationDisabledByAutofillSyncCheckbox() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.setPaymentsIntegrationEnabled(true); + + ManageSyncPreferences fragment = startManageSyncPreferences(); + assertSyncOnState(fragment); + ChromeSwitchPreferenceCompat syncEverything = getSyncEverything(fragment); + mSyncTestRule.togglePreference(syncEverything); + + CheckBoxPreference syncAutofill = (CheckBoxPreference) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_AUTOFILL); + mSyncTestRule.togglePreference(syncAutofill); + + CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_PAYMENTS_INTEGRATION); + Assert.assertFalse(paymentsIntegration.isEnabled()); + Assert.assertFalse(paymentsIntegration.isChecked()); + + closeFragment(fragment); + assertPaymentsIntegrationEnabled(false); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testPaymentsIntegrationEnabledBySyncEverything() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.setPaymentsIntegrationEnabled(false); + mSyncTestRule.disableDataType(ModelType.AUTOFILL); + + // Get the UI elements. + ManageSyncPreferences fragment = startManageSyncPreferences(); + ChromeSwitchPreferenceCompat syncEverything = getSyncEverything(fragment); + CheckBoxPreference syncAutofill = (CheckBoxPreference) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_AUTOFILL); + CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_PAYMENTS_INTEGRATION); + + // All three are unchecked and payments is disabled. + Assert.assertFalse(syncEverything.isChecked()); + Assert.assertFalse(syncAutofill.isChecked()); + Assert.assertTrue(syncAutofill.isEnabled()); + Assert.assertFalse(paymentsIntegration.isChecked()); + Assert.assertFalse(paymentsIntegration.isEnabled()); + + // All three are checked after toggling sync everything. + mSyncTestRule.togglePreference(syncEverything); + Assert.assertTrue(syncEverything.isChecked()); + Assert.assertTrue(syncAutofill.isChecked()); + Assert.assertFalse(syncAutofill.isEnabled()); + Assert.assertTrue(paymentsIntegration.isChecked()); + Assert.assertFalse(paymentsIntegration.isEnabled()); + + // Closing the fragment enabled payments integration. + closeFragment(fragment); + assertPaymentsIntegrationEnabled(true); + } + + /** + * Test that choosing a passphrase type while sync is off doesn't crash. + * + * This is a regression test for http://crbug.com/507557. + */ + @Test + @SmallTest + @Feature({"Sync"}) + public void testChoosePassphraseTypeWhenSyncIsOff() { + mSyncTestRule.setUpTestAccountAndSignIn(); + SyncTestUtil.waitForSyncActive(); + ManageSyncPreferences fragment = startManageSyncPreferences(); + Preference encryption = getEncryption(fragment); + clickPreference(encryption); + + final PassphraseTypeDialogFragment typeFragment = getPassphraseTypeDialogFragment(); + mSyncTestRule.stopSync(); + TestThreadUtils.runOnUiThreadBlocking( + () -> { typeFragment.onItemClick(null, null, 0, Passphrase.Type.CUSTOM); }); + // No crash means we passed. + } + + /** + * Test that entering a passphrase while sync is off doesn't crash. + */ + @Test + @SmallTest + @Feature({"Sync"}) + public void testEnterPassphraseWhenSyncIsOff() { + mSyncTestRule.setUpTestAccountAndSignIn(); + SyncTestUtil.waitForSyncActive(); + final ManageSyncPreferences fragment = startManageSyncPreferences(); + mSyncTestRule.stopSync(); + TestThreadUtils.runOnUiThreadBlockingNoException( + () -> fragment.onPassphraseEntered("passphrase")); + // No crash means we passed. + } + + /** + * Test that triggering OnPassphraseAccepted dismisses PassphraseDialogFragment. + */ + @Test + @SmallTest + @Feature({"Sync"}) + @DisabledTest(message = "https://crbug.com/986243") + public void testPassphraseDialogDismissed() { + final FakeProfileSyncService pss = overrideProfileSyncService(); + + mSyncTestRule.setUpTestAccountAndSignIn(); + SyncTestUtil.waitForSyncActive(); + // Trigger PassphraseDialogFragment to be shown when taping on Encryption. + pss.setPassphraseRequiredForDecryption(true); + + final ManageSyncPreferences fragment = startManageSyncPreferences(); + Preference encryption = getEncryption(fragment); + clickPreference(encryption); + + final PassphraseDialogFragment passphraseFragment = getPassphraseDialogFragment(); + Assert.assertTrue(passphraseFragment.isAdded()); + + // Simulate OnPassphraseAccepted from external event by setting PassphraseRequired to false + // and triggering syncStateChanged(). + // PassphraseDialogFragment should be dismissed. + pss.setPassphraseRequiredForDecryption(false); + TestThreadUtils.runOnUiThreadBlocking(() -> { + pss.syncStateChanged(); + fragment.getFragmentManager().executePendingTransactions(); + Assert.assertNull("PassphraseDialogFragment should be dismissed.", + mPreferences.getFragmentManager().findFragmentByTag( + ManageSyncPreferences.FRAGMENT_ENTER_PASSPHRASE)); + }); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testPassphraseCreation() { + mSyncTestRule.setUpTestAccountAndSignIn(); + SyncTestUtil.waitForSyncActive(); + final ManageSyncPreferences fragment = startManageSyncPreferences(); + TestThreadUtils.runOnUiThreadBlocking( + () -> fragment.onPassphraseTypeSelected(Passphrase.Type.CUSTOM)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + PassphraseCreationDialogFragment pcdf = getPassphraseCreationDialogFragment(); + AlertDialog dialog = (AlertDialog) pcdf.getDialog(); + Button okButton = dialog.getButton(Dialog.BUTTON_POSITIVE); + EditText enterPassphrase = (EditText) dialog.findViewById(R.id.passphrase); + EditText confirmPassphrase = (EditText) dialog.findViewById(R.id.confirm_passphrase); + + // Error if you try to submit empty passphrase. + Assert.assertNull(confirmPassphrase.getError()); + clickButton(okButton); + Assert.assertTrue(pcdf.isResumed()); + Assert.assertNotNull(enterPassphrase.getError()); + Assert.assertNull(confirmPassphrase.getError()); + + // Error if you try to submit with only the first box filled. + clearError(confirmPassphrase); + setText(enterPassphrase, "foo"); + clickButton(okButton); + Assert.assertTrue(pcdf.isResumed()); + Assert.assertNull(enterPassphrase.getError()); + Assert.assertNotNull(confirmPassphrase.getError()); + + // Remove first box should only show empty error message + setText(enterPassphrase, ""); + clickButton(okButton); + Assert.assertNotNull(enterPassphrase.getError()); + Assert.assertNull(confirmPassphrase.getError()); + + // Error if you try to submit with only the second box filled. + clearError(confirmPassphrase); + setText(confirmPassphrase, "foo"); + clickButton(okButton); + Assert.assertTrue(pcdf.isResumed()); + Assert.assertNull(enterPassphrase.getError()); + Assert.assertNotNull(confirmPassphrase.getError()); + + // No error if text doesn't match without button press. + setText(enterPassphrase, "foo"); + clearError(confirmPassphrase); + setText(confirmPassphrase, "bar"); + Assert.assertNull(enterPassphrase.getError()); + Assert.assertNull(confirmPassphrase.getError()); + + // Error if you try to submit unmatching text. + clearError(confirmPassphrase); + clickButton(okButton); + Assert.assertTrue(pcdf.isResumed()); + Assert.assertNull(enterPassphrase.getError()); + Assert.assertNotNull(confirmPassphrase.getError()); + + // Success if text matches. + setText(confirmPassphrase, "foo"); + clickButton(okButton); + Assert.assertFalse(pcdf.isResumed()); + } + + private FakeProfileSyncService overrideProfileSyncService() { + return TestThreadUtils.runOnUiThreadBlockingNoException(() -> { + // PSS has to be constructed on the UI thread. + FakeProfileSyncService fakeProfileSyncService = new FakeProfileSyncService(); + ProfileSyncService.overrideForTests(fakeProfileSyncService); + return fakeProfileSyncService; + }); + } + + private ManageSyncPreferences startManageSyncPreferences() { + mPreferences = mSyncTestRule.startPreferences(ManageSyncPreferences.class.getName()); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + return (ManageSyncPreferences) mPreferences.getMainFragmentCompat(); + } + + private void closeFragment(ManageSyncPreferences fragment) { + FragmentTransaction transaction = + mPreferences.getSupportFragmentManager().beginTransaction(); + transaction.remove(fragment); + transaction.commit(); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } + + private ChromeSwitchPreferenceCompat getSyncEverything(ManageSyncPreferences fragment) { + return (ChromeSwitchPreferenceCompat) fragment.findPreference( + ManageSyncPreferences.PREF_SYNC_EVERYTHING); + } + + private Map<Integer, CheckBoxPreference> getDataTypes(ManageSyncPreferences fragment) { + Map<Integer, CheckBoxPreference> dataTypes = new HashMap<>(); + for (Map.Entry<Integer, String> uiDataType : UI_DATATYPES.entrySet()) { + Integer modelType = uiDataType.getKey(); + String prefId = uiDataType.getValue(); + dataTypes.put(modelType, (CheckBoxPreference) fragment.findPreference(prefId)); + } + return dataTypes; + } + + private Preference getGoogleActivityControls(ManageSyncPreferences fragment) { + return fragment.findPreference(ManageSyncPreferences.PREF_GOOGLE_ACTIVITY_CONTROLS); + } + + private Preference getEncryption(ManageSyncPreferences fragment) { + return fragment.findPreference(ManageSyncPreferences.PREF_ENCRYPTION); + } + + private Preference getManageData(ManageSyncPreferences fragment) { + return fragment.findPreference(ManageSyncPreferences.PREF_SYNC_MANAGE_DATA); + } + + private PassphraseDialogFragment getPassphraseDialogFragment() { + return ActivityUtils.waitForFragmentCompat( + mPreferences, ManageSyncPreferences.FRAGMENT_ENTER_PASSPHRASE); + } + + private PassphraseTypeDialogFragment getPassphraseTypeDialogFragment() { + return ActivityUtils.waitForFragmentCompat( + mPreferences, ManageSyncPreferences.FRAGMENT_PASSPHRASE_TYPE); + } + + private PassphraseCreationDialogFragment getPassphraseCreationDialogFragment() { + return ActivityUtils.waitForFragmentCompat( + mPreferences, ManageSyncPreferences.FRAGMENT_CUSTOM_PASSPHRASE); + } + + private void assertSyncOnState(ManageSyncPreferences fragment) { + ChromeSwitchPreferenceCompat syncEverything = getSyncEverything(fragment); + Assert.assertTrue("The sync everything switch should be on.", syncEverything.isChecked()); + Assert.assertTrue( + "The sync everything switch should be enabled.", syncEverything.isEnabled()); + for (CheckBoxPreference dataType : getDataTypes(fragment).values()) { + String key = dataType.getKey(); + Assert.assertTrue("Data type " + key + " should be checked.", dataType.isChecked()); + Assert.assertFalse("Data type " + key + " should be disabled.", dataType.isEnabled()); + } + Assert.assertTrue("The google activity controls button should always be enabled.", + getGoogleActivityControls(fragment).isEnabled()); + Assert.assertTrue("The encryption button should always be enabled.", + getEncryption(fragment).isEnabled()); + Assert.assertTrue("The manage sync data button should be always enabled.", + getManageData(fragment).isEnabled()); + } + + private void assertChosenDataTypesAre(final Set<Integer> enabledDataTypes) { + final Set<Integer> disabledDataTypes = new HashSet<>(UI_DATATYPES.keySet()); + disabledDataTypes.removeAll(enabledDataTypes); + TestThreadUtils.runOnUiThreadBlocking(() -> { + Set<Integer> actualDataTypes = + mSyncTestRule.getProfileSyncService().getChosenDataTypes(); + Assert.assertTrue(actualDataTypes.containsAll(enabledDataTypes)); + Assert.assertTrue(Collections.disjoint(disabledDataTypes, actualDataTypes)); + }); + } + + private void assertPaymentsIntegrationEnabled(final boolean enabled) { + TestThreadUtils.runOnUiThreadBlocking(() -> { + Assert.assertEquals(enabled, PersonalDataManager.isPaymentsIntegrationEnabled()); + }); + } + + private void clickPreference(final Preference pref) { + TestThreadUtils.runOnUiThreadBlockingNoException( + () -> pref.getOnPreferenceClickListener().onPreferenceClick(pref)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } + + private void clickButton(final Button button) { + TestThreadUtils.runOnUiThreadBlocking((Runnable) button::performClick); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } + + private void setText(final TextView textView, final String text) { + TestThreadUtils.runOnUiThreadBlocking(() -> textView.setText(text)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } + + private void clearError(final TextView textView) { + TestThreadUtils.runOnUiThreadBlocking(() -> textView.setError(null)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncAndServicesPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncAndServicesPreferencesTest.java new file mode 100644 index 0000000..28f25380 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncAndServicesPreferencesTest.java
@@ -0,0 +1,178 @@ +// 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. + +package org.chromium.chrome.browser.sync; + +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.v4.app.FragmentTransaction; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.preferences.ChromeSwitchPreferenceCompat; +import org.chromium.chrome.browser.preferences.Preferences; +import org.chromium.chrome.browser.preferences.sync.SyncAndServicesPreferences; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.util.browser.sync.SyncTestUtil; +import org.chromium.components.sync.AndroidSyncSettings; +import org.chromium.content_public.browser.test.util.TestThreadUtils; + +/** + * Tests for SyncAndServicesPreferences. + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class SyncAndServicesPreferencesTest { + private static final String TAG = "SyncAndServicesPreferencesTest"; + + @Rule + public SyncTestRule mSyncTestRule = new SyncTestRule(); + + private Preferences mPreferences; + + @After + public void tearDown() throws Exception { + TestThreadUtils.runOnUiThreadBlocking(() -> ProfileSyncService.resetForTests()); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testSyncSwitch() { + mSyncTestRule.setUpTestAccountAndSignIn(); + SyncTestUtil.waitForSyncActive(); + SyncAndServicesPreferences fragment = startSyncAndServicesPreferences(); + final ChromeSwitchPreferenceCompat syncSwitch = getSyncSwitch(fragment); + + Assert.assertTrue(syncSwitch.isChecked()); + Assert.assertTrue(AndroidSyncSettings.get().isChromeSyncEnabled()); + mSyncTestRule.togglePreference(syncSwitch); + Assert.assertFalse(syncSwitch.isChecked()); + Assert.assertFalse(AndroidSyncSettings.get().isChromeSyncEnabled()); + mSyncTestRule.togglePreference(syncSwitch); + Assert.assertTrue(syncSwitch.isChecked()); + Assert.assertTrue(AndroidSyncSettings.get().isChromeSyncEnabled()); + } + + /** + * This is a regression test for http://crbug.com/454939. + */ + @Test + @SmallTest + @Feature({"Sync"}) + public void testOpeningSettingsDoesntEnableSync() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.stopSync(); + SyncAndServicesPreferences fragment = startSyncAndServicesPreferences(); + closeFragment(fragment); + Assert.assertFalse(AndroidSyncSettings.get().isChromeSyncEnabled()); + } + + /** + * This is a regression test for http://crbug.com/467600. + */ + @Test + @SmallTest + @Feature({"Sync"}) + public void testOpeningSettingsDoesntStartEngine() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.stopSync(); + startSyncAndServicesPreferences(); + TestThreadUtils.runOnUiThreadBlocking(() -> { + Assert.assertFalse(mSyncTestRule.getProfileSyncService().isSyncRequested()); + }); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testDefaultControlStatesWithSyncOffThenOn() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.stopSync(); + SyncAndServicesPreferences fragment = startSyncAndServicesPreferences(); + assertSyncOffState(fragment); + mSyncTestRule.togglePreference(getSyncSwitch(fragment)); + SyncTestUtil.waitForEngineInitialized(); + assertSyncOnState(fragment); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testDefaultControlStatesWithSyncOnThenOff() { + mSyncTestRule.setUpTestAccountAndSignIn(); + SyncTestUtil.waitForSyncActive(); + SyncAndServicesPreferences fragment = startSyncAndServicesPreferences(); + assertSyncOnState(fragment); + mSyncTestRule.togglePreference(getSyncSwitch(fragment)); + assertSyncOffState(fragment); + } + + @Test + @SmallTest + @Feature({"Sync"}) + public void testSyncSwitchClearsServerAutofillCreditCards() { + mSyncTestRule.setUpTestAccountAndSignIn(); + mSyncTestRule.setPaymentsIntegrationEnabled(true); + + Assert.assertFalse( + "There should be no server cards", mSyncTestRule.hasServerAutofillCreditCards()); + mSyncTestRule.addServerAutofillCreditCard(); + Assert.assertTrue( + "There should be server cards", mSyncTestRule.hasServerAutofillCreditCards()); + + Assert.assertTrue(AndroidSyncSettings.get().isChromeSyncEnabled()); + SyncAndServicesPreferences fragment = startSyncAndServicesPreferences(); + assertSyncOnState(fragment); + ChromeSwitchPreferenceCompat syncSwitch = getSyncSwitch(fragment); + Assert.assertTrue(syncSwitch.isChecked()); + Assert.assertTrue(AndroidSyncSettings.get().isChromeSyncEnabled()); + mSyncTestRule.togglePreference(syncSwitch); + Assert.assertFalse(syncSwitch.isChecked()); + Assert.assertFalse(AndroidSyncSettings.get().isChromeSyncEnabled()); + + closeFragment(fragment); + + Assert.assertFalse("There should be no server cards remaining", + mSyncTestRule.hasServerAutofillCreditCards()); + } + + private SyncAndServicesPreferences startSyncAndServicesPreferences() { + mPreferences = mSyncTestRule.startPreferences(SyncAndServicesPreferences.class.getName()); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + return (SyncAndServicesPreferences) mPreferences.getMainFragmentCompat(); + } + + private void closeFragment(SyncAndServicesPreferences fragment) { + FragmentTransaction transaction = + mPreferences.getSupportFragmentManager().beginTransaction(); + transaction.remove(fragment); + transaction.commit(); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + } + + private ChromeSwitchPreferenceCompat getSyncSwitch(SyncAndServicesPreferences fragment) { + return (ChromeSwitchPreferenceCompat) fragment.findPreference( + SyncAndServicesPreferences.PREF_SYNC_REQUESTED); + } + + private void assertSyncOnState(SyncAndServicesPreferences fragment) { + Assert.assertTrue("The sync switch should be on.", getSyncSwitch(fragment).isChecked()); + Assert.assertTrue( + "The sync switch should be enabled.", getSyncSwitch(fragment).isEnabled()); + } + + private void assertSyncOffState(SyncAndServicesPreferences fragment) { + Assert.assertFalse("The sync switch should be off.", getSyncSwitch(fragment).isChecked()); + Assert.assertTrue( + "The sync switch should be enabled.", getSyncSwitch(fragment).isEnabled()); + } +} \ No newline at end of file
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java deleted file mode 100644 index fe7e226..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncCustomizationFragmentTest.java +++ /dev/null
@@ -1,844 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.sync; - -import android.annotation.SuppressLint; -import android.app.Dialog; -import android.os.Build; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.AlertDialog; -import android.support.v7.preference.CheckBoxPreference; -import android.support.v7.preference.Preference; -import android.support.v7.preference.SwitchPreferenceCompat; -import android.support.v7.preference.TwoStatePreference; -import android.widget.Button; -import android.widget.EditText; -import android.widget.TextView; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.test.util.CommandLineFlags; -import org.chromium.base.test.util.DisableIf; -import org.chromium.base.test.util.DisabledTest; -import org.chromium.base.test.util.Feature; -import org.chromium.chrome.R; -import org.chromium.chrome.browser.ChromeSwitches; -import org.chromium.chrome.browser.autofill.PersonalDataManager; -import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; -import org.chromium.chrome.browser.preferences.Preferences; -import org.chromium.chrome.browser.sync.ui.PassphraseCreationDialogFragment; -import org.chromium.chrome.browser.sync.ui.PassphraseDialogFragment; -import org.chromium.chrome.browser.sync.ui.PassphraseTypeDialogFragment; -import org.chromium.chrome.browser.sync.ui.SyncCustomizationFragment; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.chrome.test.util.ActivityUtils; -import org.chromium.chrome.test.util.browser.sync.SyncTestUtil; -import org.chromium.components.sync.AndroidSyncSettings; -import org.chromium.components.sync.ModelType; -import org.chromium.components.sync.Passphrase; -import org.chromium.components.sync.protocol.AutofillWalletSpecifics; -import org.chromium.components.sync.protocol.EntitySpecifics; -import org.chromium.components.sync.protocol.SyncEntity; -import org.chromium.components.sync.protocol.WalletMaskedCreditCard; -import org.chromium.content_public.browser.test.util.TestThreadUtils; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * Tests for SyncCustomizationFragment. - */ -@RunWith(ChromeJUnit4ClassRunner.class) -@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) -@SuppressLint("UseSparseArrays") -@Ignore("TODO(crbug.com/890847): Adapt these tests for SyncAndServicesPreferences.") -public class SyncCustomizationFragmentTest { - @Rule - public SyncTestRule mSyncTestRule = new SyncTestRule(); - - private static final String TAG = "SyncCustomizationFragmentTest"; - - /** - * Fake ProfileSyncService for test to control the value returned from - * isPassphraseRequiredForDecryption. - */ - private class FakeProfileSyncService extends ProfileSyncService { - private boolean mPassphraseRequiredForDecryption; - - FakeProfileSyncService() { - super(); - setMasterSyncEnabledProvider(() -> AndroidSyncSettings.get().isMasterSyncEnabled()); - } - - @Override - public boolean isPassphraseRequiredForDecryption() { - return mPassphraseRequiredForDecryption; - } - - void setPassphraseRequiredForDecryption(boolean passphraseRequiredForDecryption) { - mPassphraseRequiredForDecryption = passphraseRequiredForDecryption; - } - } - - /** - * Maps ModelTypes to their UI element IDs. - */ - private static final Map<Integer, String> UI_DATATYPES; - - static { - UI_DATATYPES = new HashMap<>(); - UI_DATATYPES.put(ModelType.AUTOFILL, SyncCustomizationFragment.PREFERENCE_SYNC_AUTOFILL); - UI_DATATYPES.put(ModelType.BOOKMARKS, SyncCustomizationFragment.PREFERENCE_SYNC_BOOKMARKS); - UI_DATATYPES.put(ModelType.TYPED_URLS, SyncCustomizationFragment.PREFERENCE_SYNC_OMNIBOX); - UI_DATATYPES.put(ModelType.PASSWORDS, SyncCustomizationFragment.PREFERENCE_SYNC_PASSWORDS); - UI_DATATYPES.put( - ModelType.PROXY_TABS, SyncCustomizationFragment.PREFERENCE_SYNC_RECENT_TABS); - UI_DATATYPES.put(ModelType.PREFERENCES, SyncCustomizationFragment.PREFERENCE_SYNC_SETTINGS); - } - - private Preferences mPreferences; - - @Before - public void setUp() throws Exception { - mPreferences = null; - } - - @After - public void tearDown() throws Exception { - TestThreadUtils.runOnUiThreadBlocking(() -> ProfileSyncService.resetForTests()); - } - - /** - * Minimal test fixture to debug flakiness in the actual tests. - * TODO(crbug.com/879246): Remove after investigation. - */ - @Test - @SmallTest - @Feature({"Sync"}) - public void testSetupOnly() { - mSyncTestRule.setUpTestAccountAndSignIn(); - } - - /** - * Minimal test fixture to debug flakiness in the actual tests. - * TODO(crbug.com/879246): Remove after investigation. - */ - @Test - @SmallTest - @Feature({"Sync"}) - public void testSetupAndWaitForSyncActive() { - mSyncTestRule.setUpTestAccountAndSignIn(); - SyncTestUtil.waitForSyncActive(); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testSyncSwitch() { - mSyncTestRule.setUpTestAccountAndSignIn(); - SyncTestUtil.waitForSyncActive(); - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - final SwitchPreferenceCompat syncSwitch = getSyncSwitch(fragment); - - Assert.assertTrue(syncSwitch.isChecked()); - Assert.assertTrue(AndroidSyncSettings.get().isChromeSyncEnabled()); - togglePreference(syncSwitch); - Assert.assertFalse(syncSwitch.isChecked()); - Assert.assertFalse(AndroidSyncSettings.get().isChromeSyncEnabled()); - togglePreference(syncSwitch); - Assert.assertTrue(syncSwitch.isChecked()); - Assert.assertTrue(AndroidSyncSettings.get().isChromeSyncEnabled()); - } - - /** - * This is a regression test for http://crbug.com/454939. - */ - @Test - @SmallTest - @Feature({"Sync"}) - public void testOpeningSettingsDoesntEnableSync() { - mSyncTestRule.setUpTestAccountAndSignIn(); - mSyncTestRule.stopSync(); - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - closeFragment(fragment); - Assert.assertFalse(AndroidSyncSettings.get().isChromeSyncEnabled()); - } - - /** - * This is a regression test for http://crbug.com/467600. - */ - @Test - @SmallTest - @Feature({"Sync"}) - @DisabledTest - public void testOpeningSettingsDoesntStartEngine() { - mSyncTestRule.setUpTestAccountAndSignIn(); - mSyncTestRule.stopSync(); - startSyncCustomizationFragment(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - Assert.assertFalse(mSyncTestRule.getProfileSyncService().isSyncRequested()); - Assert.assertFalse(mSyncTestRule.getProfileSyncService().isEngineInitialized()); - }); - } - - @Test - @SmallTest - @Feature({"Sync"}) - @DisabledTest - public void testDefaultControlStatesWithSyncOffThenOn() { - mSyncTestRule.setUpTestAccountAndSignIn(); - mSyncTestRule.stopSync(); - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOffState(fragment); - togglePreference(getSyncSwitch(fragment)); - SyncTestUtil.waitForEngineInitialized(); - assertDefaultSyncOnState(fragment); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testDefaultControlStatesWithSyncOnThenOff() { - mSyncTestRule.setUpTestAccountAndSignIn(); - SyncTestUtil.waitForSyncActive(); - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOnState(fragment); - togglePreference(getSyncSwitch(fragment)); - assertDefaultSyncOffState(fragment); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testSyncEverythingAndDataTypes() { - mSyncTestRule.setUpTestAccountAndSignIn(); - SyncTestUtil.waitForSyncActive(); - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - Collection<CheckBoxPreference> dataTypes = getDataTypes(fragment).values(); - - assertDefaultSyncOnState(fragment); - togglePreference(syncEverything); - for (CheckBoxPreference dataType : dataTypes) { - Assert.assertTrue(dataType.isChecked()); - Assert.assertTrue(dataType.isEnabled()); - } - - // If all data types are unchecked, sync should turn off. - for (CheckBoxPreference dataType : dataTypes) { - togglePreference(dataType); - } - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - assertDefaultSyncOffState(fragment); - Assert.assertFalse(AndroidSyncSettings.get().isChromeSyncEnabled()); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testSettingDataTypes() { - mSyncTestRule.setUpTestAccountAndSignIn(); - SyncTestUtil.waitForSyncActive(); - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - Map<Integer, CheckBoxPreference> dataTypes = getDataTypes(fragment); - - assertDefaultSyncOnState(fragment); - togglePreference(syncEverything); - for (CheckBoxPreference dataType : dataTypes.values()) { - Assert.assertTrue(dataType.isChecked()); - Assert.assertTrue(dataType.isEnabled()); - } - - Set<Integer> expectedTypes = new HashSet<>(dataTypes.keySet()); - expectedTypes.add(ModelType.PREFERENCES); - expectedTypes.add(ModelType.PRIORITY_PREFERENCES); - assertDataTypesAre(expectedTypes); - togglePreference(dataTypes.get(ModelType.AUTOFILL)); - togglePreference(dataTypes.get(ModelType.PASSWORDS)); - // Nothing should have changed before the fragment closes. - assertDataTypesAre(expectedTypes); - - closeFragment(fragment); - expectedTypes.remove(ModelType.AUTOFILL); - expectedTypes.remove(ModelType.PASSWORDS); - assertDataTypesAre(expectedTypes); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testPaymentsIntegrationChecked() { - mSyncTestRule.setUpTestAccountAndSignIn(); - - setPaymentsIntegrationEnabled(true); - - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOnState(fragment); - - CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_PAYMENTS_INTEGRATION); - - Assert.assertFalse(paymentsIntegration.isEnabled()); - Assert.assertTrue(paymentsIntegration.isChecked()); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testPaymentsIntegrationUnchecked() { - mSyncTestRule.setUpTestAccountAndSignIn(); - - setPaymentsIntegrationEnabled(false); - - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOnState(fragment); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - togglePreference(syncEverything); - - CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_PAYMENTS_INTEGRATION); - - Assert.assertTrue(paymentsIntegration.isEnabled()); - Assert.assertFalse(paymentsIntegration.isChecked()); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testPaymentsIntegrationCheckboxDisablesPaymentsIntegration() { - mSyncTestRule.setUpTestAccountAndSignIn(); - - setPaymentsIntegrationEnabled(true); - - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOnState(fragment); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - togglePreference(syncEverything); - - CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_PAYMENTS_INTEGRATION); - togglePreference(paymentsIntegration); - - closeFragment(fragment); - assertPaymentsIntegrationEnabled(false); - } - - @Test - @SmallTest - @Feature({"Sync"}) - @DisableIf.Build(message = "crbug.com/899989 ", sdk_is_less_than = Build.VERSION_CODES.M) - public void testPaymentsIntegrationCheckboxEnablesPaymentsIntegration() { - mSyncTestRule.setUpTestAccountAndSignIn(); - - setPaymentsIntegrationEnabled(false); - - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOnState(fragment); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - togglePreference(syncEverything); - - CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_PAYMENTS_INTEGRATION); - togglePreference(paymentsIntegration); - - closeFragment(fragment); - assertPaymentsIntegrationEnabled(true); - } - - @Test - @SmallTest - @Feature({"Sync"}) - @DisabledTest(message = "crbug.com/955490") - public void testPaymentsIntegrationCheckboxClearsServerAutofillCreditCards() { - mSyncTestRule.setUpTestAccountAndSignIn(); - - setPaymentsIntegrationEnabled(true); - - Assert.assertFalse("There should be no server cards", hasServerAutofillCreditCards()); - addServerAutofillCreditCard(); - Assert.assertTrue("There should be server cards", hasServerAutofillCreditCards()); - - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOnState(fragment); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - togglePreference(syncEverything); - - CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_PAYMENTS_INTEGRATION); - togglePreference(paymentsIntegration); - - closeFragment(fragment); - assertPaymentsIntegrationEnabled(false); - - Assert.assertFalse( - "There should be no server cards remaining", hasServerAutofillCreditCards()); - } - - @Test - @SmallTest - @Feature({"Sync"}) - @DisabledTest(message = "crbug.com/951141") - public void testSyncSwitchClearsServerAutofillCreditCards() { - mSyncTestRule.setUpTestAccountAndSignIn(); - - setPaymentsIntegrationEnabled(true); - - Assert.assertFalse("There should be no server cards", hasServerAutofillCreditCards()); - addServerAutofillCreditCard(); - Assert.assertTrue("There should be server cards", hasServerAutofillCreditCards()); - - Assert.assertTrue(AndroidSyncSettings.get().isChromeSyncEnabled()); - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOnState(fragment); - SwitchPreferenceCompat syncSwitch = getSyncSwitch(fragment); - Assert.assertTrue(syncSwitch.isChecked()); - Assert.assertTrue(AndroidSyncSettings.get().isChromeSyncEnabled()); - togglePreference(syncSwitch); - Assert.assertFalse(syncSwitch.isChecked()); - Assert.assertFalse(AndroidSyncSettings.get().isChromeSyncEnabled()); - - closeFragment(fragment); - - Assert.assertFalse( - "There should be no server cards remaining", hasServerAutofillCreditCards()); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testPaymentsIntegrationDisabledByAutofillSyncCheckbox() { - mSyncTestRule.setUpTestAccountAndSignIn(); - - setPaymentsIntegrationEnabled(true); - - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOnState(fragment); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - togglePreference(syncEverything); - - CheckBoxPreference syncAutofill = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_SYNC_AUTOFILL); - togglePreference(syncAutofill); - - CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_PAYMENTS_INTEGRATION); - Assert.assertFalse(paymentsIntegration.isEnabled()); - Assert.assertFalse(paymentsIntegration.isChecked()); - - closeFragment(fragment); - assertPaymentsIntegrationEnabled(false); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testPaymentsIntegrationEnabledByAutofillSyncCheckbox() { - mSyncTestRule.setUpTestAccountAndSignIn(); - - setPaymentsIntegrationEnabled(false); - - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - assertDefaultSyncOnState(fragment); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - togglePreference(syncEverything); - - CheckBoxPreference syncAutofill = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_SYNC_AUTOFILL); - togglePreference(syncAutofill); // Disable autofill sync. - togglePreference(syncAutofill); // Re-enable autofill sync again. - - CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_PAYMENTS_INTEGRATION); - Assert.assertTrue(paymentsIntegration.isEnabled()); - Assert.assertTrue(paymentsIntegration.isChecked()); - - closeFragment(fragment); - assertPaymentsIntegrationEnabled(true); - } - - @Test - @SmallTest - @Feature({"Sync"}) - public void testPaymentsIntegrationEnabledBySyncEverything() { - mSyncTestRule.setUpTestAccountAndSignIn(); - setPaymentsIntegrationEnabled(false); - mSyncTestRule.disableDataType(ModelType.AUTOFILL); - - // Get the UI elements. - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - CheckBoxPreference syncAutofill = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_SYNC_AUTOFILL); - CheckBoxPreference paymentsIntegration = (CheckBoxPreference) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_PAYMENTS_INTEGRATION); - - // All three are unchecked and payments is disabled. - Assert.assertFalse(syncEverything.isChecked()); - Assert.assertFalse(syncAutofill.isChecked()); - Assert.assertTrue(syncAutofill.isEnabled()); - Assert.assertFalse(paymentsIntegration.isChecked()); - Assert.assertFalse(paymentsIntegration.isEnabled()); - - // All three are checked after toggling sync everything. - togglePreference(syncEverything); - Assert.assertTrue(syncEverything.isChecked()); - Assert.assertTrue(syncAutofill.isChecked()); - Assert.assertFalse(syncAutofill.isEnabled()); - Assert.assertTrue(paymentsIntegration.isChecked()); - Assert.assertFalse(paymentsIntegration.isEnabled()); - - // Closing the fragment enabled payments integration. - closeFragment(fragment); - assertPaymentsIntegrationEnabled(true); - } - - /** - * Test that choosing a passphrase type while sync is off doesn't crash. - * - * This is a regression test for http://crbug.com/507557. - */ - @Test - @SmallTest - @Feature({"Sync"}) - public void testChoosePassphraseTypeWhenSyncIsOff() { - mSyncTestRule.setUpTestAccountAndSignIn(); - SyncTestUtil.waitForSyncActive(); - SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - Preference encryption = getEncryption(fragment); - clickPreference(encryption); - - final PassphraseTypeDialogFragment typeFragment = getPassphraseTypeDialogFragment(); - mSyncTestRule.stopSync(); - TestThreadUtils.runOnUiThreadBlocking( - () -> { typeFragment.onItemClick(null, null, 0, Passphrase.Type.CUSTOM); }); - // No crash means we passed. - } - - /** - * Test that entering a passphrase while sync is off doesn't crash. - */ - @Test - @SmallTest - @Feature({"Sync"}) - public void testEnterPassphraseWhenSyncIsOff() { - mSyncTestRule.setUpTestAccountAndSignIn(); - SyncTestUtil.waitForSyncActive(); - final SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - mSyncTestRule.stopSync(); - TestThreadUtils.runOnUiThreadBlockingNoException( - () -> fragment.onPassphraseEntered("passphrase")); - // No crash means we passed. - } - - /** - * Test that triggering OnPassphraseAccepted dismisses PassphraseDialogFragment. - */ - @Test - @SmallTest - @Feature({"Sync"}) - @DisabledTest - public void testPassphraseDialogDismissed() { - final FakeProfileSyncService pss = overrideProfileSyncService(); - - mSyncTestRule.setUpTestAccountAndSignIn(); - SyncTestUtil.waitForSyncActive(); - // Trigger PassphraseDialogFragment to be shown when taping on Encryption. - pss.setPassphraseRequiredForDecryption(true); - - final SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - Preference encryption = getEncryption(fragment); - clickPreference(encryption); - - final PassphraseDialogFragment passphraseFragment = getPassphraseDialogFragment(); - Assert.assertTrue(passphraseFragment.isAdded()); - - // Simulate OnPassphraseAccepted from external event by setting PassphraseRequired to false - // and triggering syncStateChanged(). - // PassphraseDialogFragment should be dismissed. - pss.setPassphraseRequiredForDecryption(false); - TestThreadUtils.runOnUiThreadBlocking(() -> { - pss.syncStateChanged(); - fragment.getFragmentManager().executePendingTransactions(); - Assert.assertNull("PassphraseDialogFragment should be dismissed.", - mPreferences.getFragmentManager().findFragmentByTag( - SyncCustomizationFragment.FRAGMENT_ENTER_PASSPHRASE)); - }); - } - - @Test - @SmallTest - @Feature({"Sync"}) - @DisableIf.Build(message = "crbug.com/899989 ", sdk_is_less_than = Build.VERSION_CODES.M) - public void testPassphraseCreation() { - mSyncTestRule.setUpTestAccountAndSignIn(); - SyncTestUtil.waitForSyncActive(); - final SyncCustomizationFragment fragment = startSyncCustomizationFragment(); - TestThreadUtils.runOnUiThreadBlocking( - () -> fragment.onPassphraseTypeSelected(Passphrase.Type.CUSTOM)); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - PassphraseCreationDialogFragment pcdf = getPassphraseCreationDialogFragment(); - AlertDialog dialog = (AlertDialog) pcdf.getDialog(); - Button okButton = dialog.getButton(Dialog.BUTTON_POSITIVE); - EditText enterPassphrase = (EditText) dialog.findViewById(R.id.passphrase); - EditText confirmPassphrase = (EditText) dialog.findViewById(R.id.confirm_passphrase); - - // Error if you try to submit empty passphrase. - Assert.assertNull(confirmPassphrase.getError()); - clickButton(okButton); - Assert.assertTrue(pcdf.isResumed()); - Assert.assertNotNull(enterPassphrase.getError()); - Assert.assertNull(confirmPassphrase.getError()); - - // Error if you try to submit with only the first box filled. - clearError(confirmPassphrase); - setText(enterPassphrase, "foo"); - clickButton(okButton); - Assert.assertTrue(pcdf.isResumed()); - Assert.assertNull(enterPassphrase.getError()); - Assert.assertNotNull(confirmPassphrase.getError()); - - // Remove first box should only show empty error message - setText(enterPassphrase, ""); - clickButton(okButton); - Assert.assertNotNull(enterPassphrase.getError()); - Assert.assertNull(confirmPassphrase.getError()); - - // Error if you try to submit with only the second box filled. - clearError(confirmPassphrase); - setText(confirmPassphrase, "foo"); - clickButton(okButton); - Assert.assertTrue(pcdf.isResumed()); - Assert.assertNull(enterPassphrase.getError()); - Assert.assertNotNull(confirmPassphrase.getError()); - - // No error if text doesn't match without button press. - setText(enterPassphrase, "foo"); - clearError(confirmPassphrase); - setText(confirmPassphrase, "bar"); - Assert.assertNull(enterPassphrase.getError()); - Assert.assertNull(confirmPassphrase.getError()); - - // Error if you try to submit unmatching text. - clearError(confirmPassphrase); - clickButton(okButton); - Assert.assertTrue(pcdf.isResumed()); - Assert.assertNull(enterPassphrase.getError()); - Assert.assertNotNull(confirmPassphrase.getError()); - - // Success if text matches. - setText(confirmPassphrase, "foo"); - clickButton(okButton); - Assert.assertFalse(pcdf.isResumed()); - } - - private FakeProfileSyncService overrideProfileSyncService() { - return TestThreadUtils.runOnUiThreadBlockingNoException(() -> { - // PSS has to be constructed on the UI thread. - FakeProfileSyncService fakeProfileSyncService = new FakeProfileSyncService(); - ProfileSyncService.overrideForTests(fakeProfileSyncService); - return fakeProfileSyncService; - }); - } - - private SyncCustomizationFragment startSyncCustomizationFragment() { - mPreferences = mSyncTestRule.startPreferences(SyncCustomizationFragment.class.getName()); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - return (SyncCustomizationFragment) mPreferences.getMainFragmentCompat(); - } - - private void closeFragment(SyncCustomizationFragment fragment) { - FragmentTransaction transaction = - mPreferences.getSupportFragmentManager().beginTransaction(); - transaction.remove(fragment); - transaction.commit(); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - } - - private SwitchPreferenceCompat getSyncSwitch(SyncCustomizationFragment fragment) { - return (SwitchPreferenceCompat) fragment.findPreference( - SyncCustomizationFragment.PREF_SYNC_SWITCH); - } - - private SwitchPreferenceCompat getSyncEverything(SyncCustomizationFragment fragment) { - return (SwitchPreferenceCompat) fragment.findPreference( - SyncCustomizationFragment.PREFERENCE_SYNC_EVERYTHING); - } - - private Map<Integer, CheckBoxPreference> getDataTypes(SyncCustomizationFragment fragment) { - Map<Integer, CheckBoxPreference> dataTypes = new HashMap<>(); - for (Map.Entry<Integer, String> uiDataType : UI_DATATYPES.entrySet()) { - Integer modelType = uiDataType.getKey(); - String prefId = uiDataType.getValue(); - dataTypes.put(modelType, (CheckBoxPreference) fragment.findPreference(prefId)); - } - return dataTypes; - } - - private Preference getEncryption(SyncCustomizationFragment fragment) { - return fragment.findPreference(SyncCustomizationFragment.PREFERENCE_ENCRYPTION); - } - - private Preference getManageData(SyncCustomizationFragment fragment) { - return fragment.findPreference(SyncCustomizationFragment.PREFERENCE_SYNC_MANAGE_DATA); - } - - private PassphraseDialogFragment getPassphraseDialogFragment() { - return ActivityUtils.waitForFragmentCompat( - mPreferences, SyncCustomizationFragment.FRAGMENT_ENTER_PASSPHRASE); - } - - private PassphraseTypeDialogFragment getPassphraseTypeDialogFragment() { - return ActivityUtils.waitForFragmentCompat( - mPreferences, SyncCustomizationFragment.FRAGMENT_PASSPHRASE_TYPE); - } - - private PassphraseCreationDialogFragment getPassphraseCreationDialogFragment() { - return ActivityUtils.waitForFragmentCompat( - mPreferences, SyncCustomizationFragment.FRAGMENT_CUSTOM_PASSPHRASE); - } - - private void assertDefaultSyncOnState(SyncCustomizationFragment fragment) { - Assert.assertTrue("The sync switch should be on.", getSyncSwitch(fragment).isChecked()); - Assert.assertTrue( - "The sync switch should be enabled.", getSyncSwitch(fragment).isEnabled()); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - Assert.assertTrue("The sync everything switch should be on.", syncEverything.isChecked()); - Assert.assertTrue( - "The sync everything switch should be enabled.", syncEverything.isEnabled()); - for (CheckBoxPreference dataType : getDataTypes(fragment).values()) { - String key = dataType.getKey(); - Assert.assertTrue("Data type " + key + " should be checked.", dataType.isChecked()); - Assert.assertFalse("Data type " + key + " should be disabled.", dataType.isEnabled()); - } - Assert.assertTrue( - "The encryption button should be enabled.", getEncryption(fragment).isEnabled()); - Assert.assertTrue("The manage sync data button should be always enabled.", - getManageData(fragment).isEnabled()); - } - - private void assertDefaultSyncOffState(SyncCustomizationFragment fragment) { - Assert.assertFalse("The sync switch should be off.", getSyncSwitch(fragment).isChecked()); - Assert.assertTrue( - "The sync switch should be enabled.", getSyncSwitch(fragment).isEnabled()); - SwitchPreferenceCompat syncEverything = getSyncEverything(fragment); - Assert.assertTrue("The sync everything switch should be on.", syncEverything.isChecked()); - Assert.assertFalse( - "The sync everything switch should be disabled.", syncEverything.isEnabled()); - for (CheckBoxPreference dataType : getDataTypes(fragment).values()) { - String key = dataType.getKey(); - Assert.assertTrue("Data type " + key + " should be checked.", dataType.isChecked()); - Assert.assertFalse("Data type " + key + " should be disabled.", dataType.isEnabled()); - } - Assert.assertFalse( - "The encryption button should be disabled.", getEncryption(fragment).isEnabled()); - Assert.assertTrue("The manage sync data button should be always enabled.", - getManageData(fragment).isEnabled()); - } - - private void assertDataTypesAre(final Set<Integer> enabledDataTypes) { - final Set<Integer> disabledDataTypes = new HashSet<>(UI_DATATYPES.keySet()); - disabledDataTypes.removeAll(enabledDataTypes); - TestThreadUtils.runOnUiThreadBlocking(() -> { - Set<Integer> actualDataTypes = - mSyncTestRule.getProfileSyncService().getPreferredDataTypes(); - Assert.assertTrue(actualDataTypes.containsAll(enabledDataTypes)); - Assert.assertTrue(Collections.disjoint(disabledDataTypes, actualDataTypes)); - }); - } - - private void setPaymentsIntegrationEnabled(final boolean enabled) { - TestThreadUtils.runOnUiThreadBlocking( - () -> PersonalDataManager.setPaymentsIntegrationEnabled(enabled)); - } - - private void assertPaymentsIntegrationEnabled(final boolean enabled) { - TestThreadUtils.runOnUiThreadBlocking(() -> { - Assert.assertEquals(enabled, PersonalDataManager.isPaymentsIntegrationEnabled()); - }); - } - - private void addServerAutofillCreditCard() { - final String serverId = "025eb937c022489eb8dc78cbaa969218"; - WalletMaskedCreditCard card = - WalletMaskedCreditCard.newBuilder() - .setId(serverId) - .setStatus(WalletMaskedCreditCard.WalletCardStatus.VALID) - .setNameOnCard("Jon Doe") - .setType(WalletMaskedCreditCard.WalletCardType.UNKNOWN) - .setLastFour("1111") - .setExpMonth(11) - .setExpYear(2020) - .build(); - AutofillWalletSpecifics wallet_specifics = - AutofillWalletSpecifics.newBuilder() - .setType(AutofillWalletSpecifics.WalletInfoType.MASKED_CREDIT_CARD) - .setMaskedCard(card) - .build(); - EntitySpecifics specifics = - EntitySpecifics.newBuilder().setAutofillWallet(wallet_specifics).build(); - SyncEntity entity = SyncEntity.newBuilder() - .setName(serverId) - .setIdString(serverId) - .setSpecifics(specifics) - .build(); - mSyncTestRule.getFakeServerHelper().setWalletData(entity); - SyncTestUtil.triggerSyncAndWaitForCompletion(); - } - - private boolean hasServerAutofillCreditCards() { - return TestThreadUtils.runOnUiThreadBlockingNoException(() -> { - List<CreditCard> cards = PersonalDataManager.getInstance().getCreditCardsForSettings(); - for (int i = 0; i < cards.size(); i++) { - if (!cards.get(i).getIsLocal()) return true; - } - return false; - }); - } - - // UI interaction convenience methods. - private void togglePreference(final TwoStatePreference pref) { - TestThreadUtils.runOnUiThreadBlocking(() -> { - boolean newValue = !pref.isChecked(); - pref.getOnPreferenceChangeListener().onPreferenceChange(pref, newValue); - pref.setChecked(newValue); - }); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - } - - private void clickPreference(final Preference pref) { - TestThreadUtils.runOnUiThreadBlockingNoException( - () -> pref.getOnPreferenceClickListener().onPreferenceClick(pref)); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - } - - private void clickButton(final Button button) { - TestThreadUtils.runOnUiThreadBlocking((Runnable) button::performClick); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - } - - private void setText(final TextView textView, final String text) { - TestThreadUtils.runOnUiThreadBlocking(() -> textView.setText(text)); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - } - - private void clearError(final TextView textView) { - TestThreadUtils.runOnUiThreadBlocking(() -> textView.setError(null)); - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java index d40503a0..062a79a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
@@ -7,12 +7,15 @@ import android.accounts.Account; import android.content.Context; import android.support.test.InstrumentationRegistry; +import android.support.v7.preference.TwoStatePreference; import org.junit.Assert; import org.junit.runner.Description; import org.junit.runners.model.Statement; import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.autofill.PersonalDataManager; +import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; import org.chromium.chrome.browser.identity.UniqueIdentificationGenerator; import org.chromium.chrome.browser.identity.UniqueIdentificationGeneratorFactory; import org.chromium.chrome.browser.identity.UuidBasedUniqueIdentificationGenerator; @@ -24,6 +27,10 @@ import org.chromium.chrome.test.util.browser.sync.SyncTestUtil; import org.chromium.components.sync.AndroidSyncSettings; import org.chromium.components.sync.ModelType; +import org.chromium.components.sync.protocol.AutofillWalletSpecifics; +import org.chromium.components.sync.protocol.EntitySpecifics; +import org.chromium.components.sync.protocol.SyncEntity; +import org.chromium.components.sync.protocol.WalletMaskedCreditCard; import org.chromium.components.sync.test.util.MockSyncContentResolverDelegate; import org.chromium.content_public.browser.test.util.Criteria; import org.chromium.content_public.browser.test.util.CriteriaHelper; @@ -74,6 +81,19 @@ private ProfileSyncService mProfileSyncService; private MockSyncContentResolverDelegate mSyncContentResolver; + private void ruleSetUp() throws Throwable { + // This must be called before super.setUp() in order for test authentication to work. + SigninTestUtil.setUpAuthForTest(); + } + + private void ruleTearDown() throws Exception { + TestThreadUtils.runOnUiThreadBlocking(() -> { + mProfileSyncService.requestStop(); + FakeServerHelper.deleteFakeServer(); + }); + SigninTestUtil.tearDownAuthForTest(); + } + public SyncTestRule() { super(ChromeActivity.class); } @@ -183,6 +203,22 @@ } /* + * Enables the |chosenDataTypes|, which must be in USER_SELECTABLE_TYPES. + */ + public void setChosenDataTypes(boolean syncEverything, Set<Integer> chosenDataTypes) { + TestThreadUtils.runOnUiThreadBlocking( + () -> { mProfileSyncService.setChosenDataTypes(syncEverything, chosenDataTypes); }); + } + + /* + * Sets payments integration to |enabled|. + */ + public void setPaymentsIntegrationEnabled(final boolean enabled) { + TestThreadUtils.runOnUiThreadBlocking( + () -> PersonalDataManager.setPaymentsIntegrationEnabled(enabled)); + } + + /* * Disables the |modelType| Sync data type, which must be in USER_SELECTABLE_TYPES. */ public void disableDataType(final int modelType) { @@ -239,16 +275,57 @@ }; } - private void ruleSetUp() throws Throwable { - // This must be called before super.setUp() in order for test authentication to work. - SigninTestUtil.setUpAuthForTest(); + /* + * Adds a credit card to server for autofill. + */ + public void addServerAutofillCreditCard() { + final String serverId = "025eb937c022489eb8dc78cbaa969218"; + WalletMaskedCreditCard card = + WalletMaskedCreditCard.newBuilder() + .setId(serverId) + .setStatus(WalletMaskedCreditCard.WalletCardStatus.VALID) + .setNameOnCard("Jon Doe") + .setType(WalletMaskedCreditCard.WalletCardType.UNKNOWN) + .setLastFour("1111") + .setExpMonth(11) + .setExpYear(2020) + .build(); + AutofillWalletSpecifics wallet_specifics = + AutofillWalletSpecifics.newBuilder() + .setType(AutofillWalletSpecifics.WalletInfoType.MASKED_CREDIT_CARD) + .setMaskedCard(card) + .build(); + EntitySpecifics specifics = + EntitySpecifics.newBuilder().setAutofillWallet(wallet_specifics).build(); + SyncEntity entity = SyncEntity.newBuilder() + .setName(serverId) + .setIdString(serverId) + .setSpecifics(specifics) + .build(); + getFakeServerHelper().setWalletData(entity); + SyncTestUtil.triggerSyncAndWaitForCompletion(); } - private void ruleTearDown() throws Exception { - TestThreadUtils.runOnUiThreadBlocking(() -> { - mProfileSyncService.requestStop(); - FakeServerHelper.deleteFakeServer(); + /* + * Checks if server has any credit card information to autofill. + */ + public boolean hasServerAutofillCreditCards() { + return TestThreadUtils.runOnUiThreadBlockingNoException(() -> { + List<CreditCard> cards = PersonalDataManager.getInstance().getCreditCardsForSettings(); + for (int i = 0; i < cards.size(); i++) { + if (!cards.get(i).getIsLocal()) return true; + } + return false; }); - SigninTestUtil.tearDownAuthForTest(); + } + + // UI interaction convenience methods. + public void togglePreference(final TwoStatePreference pref) { + TestThreadUtils.runOnUiThreadBlocking(() -> { + boolean newValue = !pref.isChecked(); + pref.getOnPreferenceChangeListener().onPreferenceChange(pref, newValue); + pref.setChecked(newValue); + }); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java index 1d0491b..7acf7f7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
@@ -413,7 +413,7 @@ VrShellDelegateUtils.getDelegateInstance().overrideDaydreamApiForTesting(mockApiWithDoff); TestThreadUtils.runOnUiThreadBlocking(() -> { - PreferencesLauncher.launchSettingsPage(context, null); + PreferencesLauncher.launchSettingsPageCompat(context, null); VrShellDelegateUtils.getDelegateInstance().acceptDoffPromptForTesting(); }); CriteriaHelper.pollUiThread(() -> {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java index 631ee76..ab669f8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenManagerTest.java
@@ -231,7 +231,9 @@ MANIFEST_TEST_PAGE_TITLE); addShortcutToTab(mTab, "", true); - Assert.assertTrue(mShortcutHelperDelegate.mRequestedShortcutAdaptable); + // TODO(crbug.com/977173): re-enable maskable icon support once server support + // is ready. + Assert.assertFalse(mShortcutHelperDelegate.mRequestedShortcutAdaptable); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java index a53b975..79f7016 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcherTest.java
@@ -103,10 +103,11 @@ final WebApkUpdateDataFetcher fetcher = new WebApkUpdateDataFetcher(); PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> { WebApkInfo oldInfo = WebApkInfo.create("", "", scopeUrl, null, null, null, null, null, - -1, -1, -1, -1, -1, -1, "random.package", -1, manifestUrl, "", + -1, -1, -1, -1, -1, -1, false, "random.package", -1, manifestUrl, "", WebApkInfo.WebApkDistributor.BROWSER, new HashMap<String, String>(), null, null /*shareTargetActivityName*/, false /* forceNavigation */, - false /* isSplashProvidedByWebApk */, null /* shareData */); + false /* isSplashProvidedByWebApk */, null /* shareData */, + 1 /* webApkVersionCode */); fetcher.start(mTab, oldInfo, observer); }); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java index 64b94bb..77df393 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerTest.java
@@ -154,12 +154,12 @@ WebApkInfo info = WebApkInfo.create( WEBAPK_ID, "", creationData.scope, null, null, null, creationData.name, creationData.shortName, creationData.displayMode, creationData.orientation, 0, - creationData.themeColor, creationData.backgroundColor, 0, "", + creationData.themeColor, creationData.backgroundColor, 0, false, "", WebApkVersion.REQUEST_UPDATE_FOR_SHELL_APK_VERSION, creationData.manifestUrl, creationData.startUrl, WebApkInfo.WebApkDistributor.BROWSER, creationData.iconUrlToMurmur2HashMap, null, null /*shareTargetActivityName*/, false /* forceNavigation */, false /* isSplashProvidedByWebApk */, - null /* shareData */ + null /* shareData */, 1 /* webApkVersionCode */ ); updateManager.updateIfNeeded(mTab, info);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java index e8df4cc..54c9d4a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
@@ -134,9 +134,10 @@ false /* isIconAdaptive */, false /* forceNavigation */) : WebApkInfo.create( "", "", webappStartUrlOrScopeUrl, null, null, null, null, null, displayMode, - 0, 0, 0, 0, 0, "", 0, null, "", WebApkInfo.WebApkDistributor.BROWSER, null, - null, null /*shareTargetActivityName*/, false /* forceNavigation */, - false /* isSplashProvidedByWebApk */, null /* shareData */ + 0, 0, 0, 0, 0, false, "", 0, null, "", WebApkInfo.WebApkDistributor.BROWSER, + null, null, null /*shareTargetActivityName*/, false /* forceNavigation */, + false /* isSplashProvidedByWebApk */, null /* shareData */, + 1 /* webApkVersionCode */ ); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiverTest.java index 3e32f5eb..5d472ca3 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiverTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiverTest.java
@@ -23,16 +23,10 @@ import org.chromium.components.signin.AccountManagerDelegate; import org.chromium.components.signin.AccountManagerDelegateException; import org.chromium.components.signin.AccountManagerFacade; -import org.chromium.components.signin.CoreAccountId; -import org.chromium.components.signin.CoreAccountInfo; -import java.util.Arrays; import java.util.HashSet; import java.util.Set; -/** - * Tests for {@link ToSAckedReceiver}. - */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) public class ToSAckedReceiverTest { @@ -64,11 +58,9 @@ Assert.assertThat(toSAckedAccounts, Matchers.contains(GOOGLE_ACCOUNT)); AccountManagerDelegate accountManagerDelegate = Mockito.mock(AccountManagerDelegate.class); - CoreAccountInfo accountInfo = new CoreAccountInfo( - new CoreAccountId("gaia-id"), new Account(GOOGLE_ACCOUNT, "LegitAccount")); - Mockito.doReturn(Arrays.asList(accountInfo)) - .when(accountManagerDelegate) - .getAccountInfosSync(); + Account[] accounts = new Account[1]; + accounts[0] = new Account(GOOGLE_ACCOUNT, "LegitAccount"); + Mockito.doReturn(accounts).when(accountManagerDelegate).getAccountsSync(); AccountManagerFacade.overrideAccountManagerFacadeForTests(accountManagerDelegate); Assert.assertTrue(ToSAckedReceiver.checkAnyUserHasSeenToS()); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorTest.java index 5db808a..8c041a3 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessorTest.java
@@ -24,7 +24,6 @@ import org.chromium.chrome.browser.omnibox.suggestions.OmniboxSuggestion; import org.chromium.chrome.browser.omnibox.suggestions.basic.SuggestionViewProperties.SuggestionIcon; import org.chromium.chrome.test.util.browser.Features; -import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.testing.local.LocalRobolectricTestRunner; import org.chromium.ui.modelutil.PropertyModel; @@ -61,13 +60,14 @@ sSuggestionTypes[OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE] = "SEARCH_SUGGEST_PROFILE"; sSuggestionTypes[OmniboxSuggestionType.SEARCH_OTHER_ENGINE] = "SEARCH_OTHER_ENGINE"; sSuggestionTypes[OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED] = "NAVSUGGEST_PERSONALIZED"; - sSuggestionTypes[OmniboxSuggestionType.CALCULATOR] = "CALCULATOR"; sSuggestionTypes[OmniboxSuggestionType.CLIPBOARD_URL] = "CLIPBOARD_URL"; sSuggestionTypes[OmniboxSuggestionType.VOICE_SUGGEST] = "VOICE_SUGGEST"; sSuggestionTypes[OmniboxSuggestionType.DOCUMENT_SUGGESTION] = "DOCUMENT_SUGGESTION"; sSuggestionTypes[OmniboxSuggestionType.PEDAL] = "PEDAL"; sSuggestionTypes[OmniboxSuggestionType.CLIPBOARD_TEXT] = "CLIPBOARD_TEXT"; sSuggestionTypes[OmniboxSuggestionType.CLIPBOARD_IMAGE] = "CLIPBOARD_IMAGE"; + // Note: CALCULATOR suggestions are not handled by basic suggestion processor. + // These suggestions are now processed by AnswerSuggestionProcessor instead. sIconTypes = new String[SuggestionIcon.TOTAL_COUNT]; sIconTypes[SuggestionIcon.UNSET] = "UNSET"; @@ -76,7 +76,6 @@ sIconTypes[SuggestionIcon.GLOBE] = "GLOBE"; sIconTypes[SuggestionIcon.MAGNIFIER] = "MAGNIFIER"; sIconTypes[SuggestionIcon.VOICE] = "VOICE"; - sIconTypes[SuggestionIcon.CALCULATOR] = "CALCULATOR"; sIconTypes[SuggestionIcon.FAVICON] = "FAVICON"; } @@ -143,42 +142,6 @@ {OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE, SuggestionIcon.MAGNIFIER}, {OmniboxSuggestionType.SEARCH_OTHER_ENGINE, SuggestionIcon.MAGNIFIER}, {OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.CALCULATOR, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.CLIPBOARD_URL, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.VOICE_SUGGEST, SuggestionIcon.VOICE}, - {OmniboxSuggestionType.DOCUMENT_SUGGESTION, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.PEDAL, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.CLIPBOARD_TEXT, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.CLIPBOARD_IMAGE, SuggestionIcon.MAGNIFIER}, - }; - - for (int[] test : testSuites) { - assertSuggestionIconTypeIs(createSearchSuggestion(test[0]), test[1]); - } - } - - @Test - @EnableFeatures(ChromeFeatureList.OMNIBOX_NEW_ANSWER_LAYOUT) - @DisableFeatures(ChromeFeatureList.OMNIBOX_SHOW_SUGGESTION_FAVICONS) - public void getSuggestionIconTypeForSearch_AnwersInSuggest() { - mProcessor.onNativeInitialized(); - int[][] testSuites = { - {OmniboxSuggestionType.URL_WHAT_YOU_TYPED, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.HISTORY_URL, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.HISTORY_TITLE, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.HISTORY_BODY, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.HISTORY_KEYWORD, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.NAVSUGGEST, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.SEARCH_WHAT_YOU_TYPED, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.SEARCH_HISTORY, SuggestionIcon.HISTORY}, - {OmniboxSuggestionType.SEARCH_SUGGEST, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.SEARCH_SUGGEST_ENTITY, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.SEARCH_SUGGEST_TAIL, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.SEARCH_SUGGEST_PERSONALIZED, SuggestionIcon.HISTORY}, - {OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.SEARCH_OTHER_ENGINE, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.CALCULATOR, SuggestionIcon.CALCULATOR}, {OmniboxSuggestionType.CLIPBOARD_URL, SuggestionIcon.MAGNIFIER}, {OmniboxSuggestionType.VOICE_SUGGEST, SuggestionIcon.VOICE}, {OmniboxSuggestionType.DOCUMENT_SUGGESTION, SuggestionIcon.MAGNIFIER}, @@ -194,7 +157,6 @@ @Test @EnableFeatures(ChromeFeatureList.OMNIBOX_SHOW_SUGGESTION_FAVICONS) - @DisableFeatures(ChromeFeatureList.OMNIBOX_NEW_ANSWER_LAYOUT) public void getSuggestionIconTypeForSearch_FavIcons() { mProcessor.onNativeInitialized(); int[][] testSuites = { @@ -213,7 +175,6 @@ {OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE, SuggestionIcon.MAGNIFIER}, {OmniboxSuggestionType.SEARCH_OTHER_ENGINE, SuggestionIcon.MAGNIFIER}, {OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED, SuggestionIcon.MAGNIFIER}, - {OmniboxSuggestionType.CALCULATOR, SuggestionIcon.MAGNIFIER}, {OmniboxSuggestionType.CLIPBOARD_URL, SuggestionIcon.MAGNIFIER}, {OmniboxSuggestionType.VOICE_SUGGEST, SuggestionIcon.VOICE}, {OmniboxSuggestionType.DOCUMENT_SUGGESTION, SuggestionIcon.MAGNIFIER}, @@ -245,7 +206,6 @@ {OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.SEARCH_OTHER_ENGINE, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED, SuggestionIcon.GLOBE}, - {OmniboxSuggestionType.CALCULATOR, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.CLIPBOARD_URL, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.VOICE_SUGGEST, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.DOCUMENT_SUGGESTION, SuggestionIcon.GLOBE}, @@ -261,7 +221,6 @@ @Test @EnableFeatures(ChromeFeatureList.OMNIBOX_SHOW_SUGGESTION_FAVICONS) - @DisableFeatures(ChromeFeatureList.OMNIBOX_NEW_ANSWER_LAYOUT) public void getSuggestionIconTypeForUrl_FavIcons() { mProcessor.onNativeInitialized(); int[][] testSuites = { @@ -280,7 +239,6 @@ {OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.SEARCH_OTHER_ENGINE, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED, SuggestionIcon.GLOBE}, - {OmniboxSuggestionType.CALCULATOR, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.CLIPBOARD_URL, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.VOICE_SUGGEST, SuggestionIcon.GLOBE}, {OmniboxSuggestionType.DOCUMENT_SUGGESTION, SuggestionIcon.GLOBE}, @@ -312,7 +270,6 @@ {OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.SEARCH_OTHER_ENGINE, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED, SuggestionIcon.BOOKMARK}, - {OmniboxSuggestionType.CALCULATOR, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.CLIPBOARD_URL, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.VOICE_SUGGEST, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.DOCUMENT_SUGGESTION, SuggestionIcon.BOOKMARK}, @@ -328,7 +285,6 @@ @Test @EnableFeatures(ChromeFeatureList.OMNIBOX_SHOW_SUGGESTION_FAVICONS) - @DisableFeatures(ChromeFeatureList.OMNIBOX_NEW_ANSWER_LAYOUT) public void getSuggestionIconTypeForBookmarks_FavIcons() { mProcessor.onNativeInitialized(); int[][] testSuites = { @@ -347,7 +303,6 @@ {OmniboxSuggestionType.SEARCH_SUGGEST_PROFILE, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.SEARCH_OTHER_ENGINE, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.NAVSUGGEST_PERSONALIZED, SuggestionIcon.BOOKMARK}, - {OmniboxSuggestionType.CALCULATOR, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.CLIPBOARD_URL, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.VOICE_SUGGEST, SuggestionIcon.BOOKMARK}, {OmniboxSuggestionType.DOCUMENT_SUGGESTION, SuggestionIcon.BOOKMARK},
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java index 18b9954..4438bc56 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebApkUpdateManagerUnitTest.java
@@ -127,14 +127,15 @@ @Override public void storeWebApkUpdateRequestToFile(String updateRequestPath, String startUrl, String scope, String name, String shortName, String primaryIconUrl, - Bitmap primaryIcon, String badgeIconUrl, Bitmap badgeIcon, String[] iconUrls, - String[] iconHashes, @WebDisplayMode int displayMode, int orientation, - long themeColor, long backgroundColor, String shareTargetAction, - String shareTargetParamTitle, String shareTargetParamText, - String shareTargetParamUrl, boolean shareTargetParamIsMethodPost, - boolean shareTargetParamIsEncTypeMultipart, String[] shareTargetParamFileNames, - Object[] shareTargetParamAccepts, String manifestUrl, String webApkPackage, - int webApkVersion, boolean isManifestStale, @WebApkUpdateReason int updateReason, + Bitmap primaryIcon, boolean isPrimaryIconMaskable, String badgeIconUrl, + Bitmap badgeIcon, String[] iconUrls, String[] iconHashes, + @WebDisplayMode int displayMode, int orientation, long themeColor, + long backgroundColor, String shareTargetAction, String shareTargetParamTitle, + String shareTargetParamText, String shareTargetParamUrl, + boolean shareTargetParamIsMethodPost, boolean shareTargetParamIsEncTypeMultipart, + String[] shareTargetParamFileNames, Object[] shareTargetParamAccepts, + String manifestUrl, String webApkPackage, int webApkVersion, + boolean isManifestStale, @WebApkUpdateReason int updateReason, Callback<Boolean> callback) {} @Override @@ -362,9 +363,9 @@ new WebApkInfo.Icon(manifestData.badgeIcon), null, manifestData.name, manifestData.shortName, manifestData.displayMode, manifestData.orientation, -1, manifestData.themeColor, manifestData.backgroundColor, - manifestData.defaultBackgroundColor, kPackageName, -1, WEB_MANIFEST_URL, - manifestData.startUrl, WebApkInfo.WebApkDistributor.BROWSER, - manifestData.iconUrlToMurmur2HashMap, + manifestData.defaultBackgroundColor, false /* isPrimaryIconMaskable */, + kPackageName, -1, WEB_MANIFEST_URL, manifestData.startUrl, + WebApkInfo.WebApkDistributor.BROWSER, manifestData.iconUrlToMurmur2HashMap, new WebApkInfo.ShareTarget(manifestData.shareTargetAction, manifestData.shareTargetParamTitle, null, null, manifestData.shareTargetMethod != null @@ -374,7 +375,8 @@ SHARE_TARGET_ENC_TYPE_MULTIPART), manifestData.shareTargetFileNames, manifestData.shareTargetFileAccepts), null /* shareTargetActivityName */, false /* forceNavigation */, - false /* isSplashProvidedByWebApk */, null /* shareData */); + false /* isSplashProvidedByWebApk */, null /* shareData */, + 1 /* webApkVersionCode */); } /**
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt index 2197c1bb..e18a782 100644 --- a/chrome/android/profiles/newest.txt +++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-77.0.3862.0_rc-r1-merged.afdo.bz2 \ No newline at end of file +chromeos-chrome-amd64-77.0.3864.0_rc-r1-merged.afdo.bz2 \ No newline at end of file
diff --git a/chrome/android/profiles/update_afdo_profile.py b/chrome/android/profiles/update_afdo_profile.py deleted file mode 100755 index 690521ca..0000000 --- a/chrome/android/profiles/update_afdo_profile.py +++ /dev/null
@@ -1,143 +0,0 @@ -#!/usr/bin/python -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""This script is used to update our local AFDO profiles. - -This uses profiles of Chrome provided by our friends from Chrome OS. Though the -profiles are available externally, the bucket they sit in is otherwise -unreadable by non-Googlers. Gsutil usage with this bucket is therefore quite -awkward: you can't do anything but `cp` certain files with an external account, -and you can't even do that if you're not yet authenticated. - -No authentication is necessary if you pull these profiles directly over -https.""" - -import argparse -import contextlib -import os -import subprocess -import sys -import urllib2 - -GS_HTTP_URL = 'https://storage.googleapis.com' -GS_BASE_URL = GS_HTTP_URL + '/chromeos-prebuilt/afdo-job/llvm' -PROFILE_DIRECTORY = os.path.abspath(os.path.dirname(__file__)) -LOCAL_PROFILE_PATH = os.path.join(PROFILE_DIRECTORY, 'afdo.prof') - -# We use these to track the local profile; newest.txt is owned by git and tracks -# the name of the newest profile we should pull, and local.txt is the most -# recent profile we've successfully pulled. -NEWEST_PROFILE_NAME_PATH = os.path.join(PROFILE_DIRECTORY, 'newest.txt') -LOCAL_PROFILE_NAME_PATH = os.path.join(PROFILE_DIRECTORY, 'local.txt') - - -def ReadUpToDateProfileName(): - with open(NEWEST_PROFILE_NAME_PATH) as f: - return f.read().strip() - - -def ReadLocalProfileName(): - try: - with open(LOCAL_PROFILE_NAME_PATH) as f: - return f.read().strip() - except IOError: - # Assume it either didn't exist, or we couldn't read it. In either case, we - # should probably grab a new profile (and, in doing so, make this file sane - # again) - return None - - -def WriteLocalProfileName(name): - with open(LOCAL_PROFILE_NAME_PATH, 'w') as f: - f.write(name) - - -def CheckCallOrExit(cmd): - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = proc.communicate() - exit_code = proc.wait() - if not exit_code: - return - - complaint_lines = [ - '## %s failed with exit code %d' % (cmd[0], exit_code), - '## Full command: %s' % cmd, - '## Stdout:\n' + stdout, - '## Stderr:\n' + stderr, - ] - print >>sys.stderr, '\n'.join(complaint_lines) - sys.exit(1) - - -def RetrieveProfile(desired_profile_name, out_path): - # vpython is > python 2.7.9, so we can expect urllib to validate HTTPS certs - # properly. - ext = os.path.splitext(desired_profile_name)[1] - compressed_path = out_path + ext - gs_prefix = 'gs://' - if not desired_profile_name.startswith(gs_prefix): - gs_url = GS_BASE_URL + '/' + desired_profile_name - else: - gs_url = GS_HTTP_URL + '/' + desired_profile_name[len(gs_prefix):] - - with contextlib.closing(urllib2.urlopen(gs_url)) as u: - with open(compressed_path, 'wb') as f: - while True: - buf = u.read(4096) - if not buf: - break - f.write(buf) - - if ext == '.bz2': - # NOTE: we can't use Python's bzip module, since it doesn't support - # multi-stream bzip files. It will silently succeed and give us a garbage - # profile. - # bzip2 removes the compressed file on success. - CheckCallOrExit(['bzip2', '-d', compressed_path]) - elif ext == '.xz': - # ...And we can't use the `lzma` module, since it was introduced in python3. - # xz removes the compressed file on success. - CheckCallOrExit(['xz', '-d', compressed_path]) - else: - # Wait until after downloading the file to check the file extension, so the - # user has something usable locally if the file extension is unrecognized. - raise ValueError( - 'Only bz2 and xz extensions are supported; "%s" is not' % ext) - - -def CleanProfilesDirectory(): - # Start with a clean slate, removing old profiles/downloads/etc. - old_artifacts = (p for p in os.listdir(PROFILE_DIRECTORY) if - p.startswith('chromeos-chrome-')) - for artifact in old_artifacts: - os.remove(os.path.join(PROFILE_DIRECTORY, artifact)) - - -def main(): - parser = argparse.ArgumentParser('Downloads profiles provided by Chrome OS') - parser.add_argument('-f', '--force', action='store_true', - help='Fetch a profile even if the local one is current') - args = parser.parse_args() - - up_to_date_profile = ReadUpToDateProfileName() - if not args.force: - local_profile_name = ReadLocalProfileName() - # In a perfect world, the local profile should always exist if we - # successfully read local_profile_name. If it's gone, though, the user - # probably removed it as a way to get us to download it again. - if local_profile_name == up_to_date_profile \ - and os.path.exists(LOCAL_PROFILE_PATH): - return 0 - - CleanProfilesDirectory() - - new_tmpfile = LOCAL_PROFILE_PATH + '.new' - RetrieveProfile(up_to_date_profile, new_tmpfile) - os.rename(new_tmpfile, LOCAL_PROFILE_PATH) - WriteLocalProfileName(up_to_date_profile) - - -if __name__ == '__main__': - sys.exit(main())
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessPreferences.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessPreferences.java index e2f0df1f1..45844c3 100644 --- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessPreferences.java +++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/TouchlessPreferences.java
@@ -8,7 +8,6 @@ import android.support.v4.app.Fragment; import android.support.v7.widget.RecyclerView; import android.view.Menu; -import android.widget.ListView; import org.chromium.chrome.R; import org.chromium.chrome.browser.AppHooks; @@ -36,33 +35,11 @@ } /** - * Adds paddings for the main list in the current android.app.Fragment. - * Support library fragments are handled in {@link #onAttachedToWindowCompat()}. - * TODO(crbug.com/967022): Once all fragments are migrated to the support library, this should - * be deleted. + * Adds paddings for the main list in the current support library Fragment. */ @Override public void onAttachedToWindow() { super.onAttachedToWindow(); - android.app.Fragment fragment = getMainFragment(); - if (fragment == null || fragment.getView() == null - || fragment.getView().findViewById(android.R.id.list) == null) { - return; - } - - int padding = getResources().getDimensionPixelSize( - org.chromium.chrome.touchless.R.dimen.touchless_preferences_highlight_padding); - ListView listView = fragment.getView().findViewById(android.R.id.list); - listView.setPadding(padding, 0, padding, 0); - listView.setDividerHeight(padding); - } - - /** - * Adds paddings for the main list in the current support library Fragment. - */ - @Override - public void onAttachedToWindowCompat() { - super.onAttachedToWindowCompat(); Fragment fragment = getMainFragmentCompat(); if (fragment == null || fragment.getView() == null || fragment.getView().findViewById(R.id.list) == null) {
diff --git a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java index 190c027..d7dc991 100644 --- a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java +++ b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkMetaDataKeys.java
@@ -25,6 +25,7 @@ public static final String DEFAULT_BACKGROUND_COLOR_ID = "org.chromium.webapk.shell_apk.defaultBackgroundColorId"; public static final String ICON_ID = "org.chromium.webapk.shell_apk.iconId"; + public static final String IS_ICON_MASKABLE = "org.chromium.webapk.shell_apk.isIconMaskable"; public static final String SPLASH_ID = "org.chromium.webapk.shell_apk.splashId"; public static final String ICON_URLS_AND_ICON_MURMUR2_HASHES =
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index fb15fc8..d83f3c64 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -213,8 +213,14 @@ <message name="IDS_CELLULAR_SETUP_TRY_AGAIN_LABEL" desc="Label for button to retry a step during cellular setup"> Try again </message> - <message name="IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_TITLE" desc="Title for first screen of cellular setup during which ChromeOS is preparing the cellular device for setup." translateable="false"> - Sim Detect Page + <message name="IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_TITLE" desc="Title for first screen of cellular setup during which ChromeOS is preparing the cellular device for setup."> + Preparing to setup your cellular device... + </message> + <message name="IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_ERROR_TITLE" desc="Title for cellular setup when Chrome OS encounters an error preparing the cellular device for setup."> + We couldn't detect your SIM card + </message> + <message name="IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_ERROR_MESSAGE" desc="Message displayed under title in cellular setup when Chrome OS encounters an error preparing the cellular device for setup. Prompts user to insert SIM and try again."> + Please insert your SIM and try again </message> <message name="IDS_CELLULAR_SETUP_PROVISIONING_PAGE_TITLE" desc="Title for cellular setup step in which the user uses the embedded carrier provisioning portal to make payment and activate the device." translateable="false"> Provisioning Page
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index 7b14104..4083803 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -33,7 +33,10 @@ <!-- Search and Assistant section. --> <message name="IDS_OS_SETTINGS_SEARCH_ENGINE_LABEL" desc="Label in OS settings describing search engine behavior."> - Searches from the app launcher use your browser <ph name="BEGIN_LINK"><a target="_blank" href="$1"></ph>search engine setting<ph name="END_LINK"></a></ph>. + Preferred search engine + </message> + <message name="IDS_OS_SETTINGS_SEARCH_ENGINE_TOOLTIP" desc="Tooltip in OS settings explaining that search engine is used in both the Chrome browser and the Chrome OS app launcher."> + Used by Chrome browser and <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> launcher </message> <!-- Files Page (OS settings) -->
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 335df5f4..301e642 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -685,7 +685,7 @@ Google Play Store </message> <message name="IDS_SETTINGS_ANDROID_APPS_SUBTEXT" desc="Description for the section for enabling and managing Google Play Store (Android) apps."> - Install apps and games from Google Play on your Chromebook. <a target="_blank" href="<ph name="URL">$1<ex>https://google.com/</ex></ph>">Learn more</a> + Install apps and games from Google Play on your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. <a target="_blank" href="<ph name="URL">$2<ex>https://google.com/</ex></ph>">Learn more</a> </message> <message name="IDS_SETTINGS_ANDROID_APPS_MANAGE_APPS" desc="Label for launching Android apps settings."> Manage Android preferences @@ -697,6 +697,8 @@ <message name="IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_TITLE" desc="Title of the confirmation dialog for disabling android apps."> Remove Android apps? </message> + <!-- TODO(jamescook): Use device type instead of "Chromebook", which may + require changing ArcPlayTermsOfServiceConsent resource id handling. --> <message name="IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_MESSAGE" desc="Describes what will happen if the user opts out of android apps."> Apps you’ve downloaded from Google Play will be deleted from this Chromebook. <ph name="LINE_BREAKS1"><br><br></ph> @@ -4843,7 +4845,7 @@ Android phone </message> <message name="IDS_SETTINGS_MULTIDEVICE_SETUP_SUMMARY" desc="Tells the user to connect their Chromebook to their phone."> - Connect your Chromebook with your phone. <ph name="LINK_BEGIN"><a target="_blank" href="$1<ex>https://google.com/</ex>"></ph>Learn more<ph name="LINK_END"></a></ph> + Connect your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> with your phone. <ph name="LINK_BEGIN"><a target="_blank" href="$2<ex>https://google.com/</ex>"></ph>Learn more<ph name="LINK_END"></a></ph> </message> <message name="IDS_SETTINGS_MULTIDEVICE_NO_ELIGIBLE_HOSTS" desc="Tells the user that there is no phone with their account on it that can connect to their Chromebook."> No eligible devices. <ph name="LINK_BEGIN"><a target="_blank" href="$1<ex>https://google.com/</ex>"></ph>Learn more<ph name="LINK_END"></a></ph> @@ -4864,7 +4866,7 @@ Disabled </message> <message name="IDS_SETTINGS_MULTIDEVICE_SMART_LOCK_SUMMARY" desc="Description of for the 'Smart Lock' setting. This feature automatically unlocks the user's Chromebook if their phone is nearby and unlocked."> - Unlock your Chromebook with your phone. <ph name="LINK_BEGIN"><a target="_blank" href="$1<ex>https://google.com/</ex>"></ph>Learn more<ph name="LINK_END"></a></ph> + Unlock your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> with your phone. <ph name="LINK_BEGIN"><a target="_blank" href="$2<ex>https://google.com/</ex>"></ph>Learn more<ph name="LINK_END"></a></ph> </message> <message name="IDS_SETTINGS_MULTIDEVICE_INSTANT_TETHERING" desc="Name of a feature. This feature automatically offers the user to tether to their phone if their Chromebook is offline and their phone supports tethering."> Instant Tethering @@ -4876,16 +4878,16 @@ Messages </message> <message name="IDS_SETTINGS_MULTIDEVICE_ANDROID_MESSAGES_SUMMARY" desc="Description of for the 'Android Messages' setting. This feature lets the user read and reply to text messages from their Chromebook. New text messages will appear as notifications."> - Send and receive text messages from your Chromebook. <ph name="LINK_BEGIN"><a target="_blank" href="$1<ex>https://google.com/</ex>"></ph>Learn more<ph name="LINK_END"></a></ph> + Send and receive text messages from your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. <ph name="LINK_BEGIN"><a target="_blank" href="$2<ex>https://google.com/</ex>"></ph>Learn more<ph name="LINK_END"></a></ph> </message> <message name="IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE" desc="Header to tell the user an action will make their Chromebook forget their phone. This means they will no longer have access to multidevice features."> Forget phone </message> <message name="IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_EXPLANATION" desc="Explanation on a clickable menu item that makes the Chromebook forget the user's phone. It tells the user that the menu item will cause their phone to stop acting as a partner for their Chromebook for multidevice features."> - Disconnect your phone from your Chromebook + Disconnect your phone from your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> </message> <message name="IDS_SETTINGS_MULTIDEVICE_FORGET_DEVICE_DIALOG_MESSAGE" desc="Text of a dialog that lets the user choose if their Chromebook should forget their phone. This means they will no longer have access to multidevice features."> - Disconnect your phone from your Chromebook. They will no longer connect automatically. + Disconnect your phone from your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>. They will no longer connect automatically. </message> </if>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 540fba3..b4f55f0 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -133,6 +133,8 @@ "autofill/strike_database_factory.h", "autofill/validation_rules_storage_factory.cc", "autofill/validation_rules_storage_factory.h", + "availability/availability_prober.cc", + "availability/availability_prober.h", "background_fetch/background_fetch_delegate_factory.cc", "background_fetch/background_fetch_delegate_factory.h", "background_fetch/background_fetch_delegate_impl.cc", @@ -325,12 +327,12 @@ "component_updater/recovery_component_installer.h", "component_updater/recovery_improved_component_installer.cc", "component_updater/recovery_improved_component_installer.h", + "component_updater/safety_tips_component_installer.cc", + "component_updater/safety_tips_component_installer.h", "component_updater/sth_set_component_remover.cc", "component_updater/sth_set_component_remover.h", "component_updater/subresource_filter_component_installer.cc", "component_updater/subresource_filter_component_installer.h", - "component_updater/supervised_user_whitelist_installer.cc", - "component_updater/supervised_user_whitelist_installer.h", "component_updater/sw_reporter_installer_win.cc", "component_updater/sw_reporter_installer_win.h", "consent_auditor/consent_auditor_factory.cc", @@ -629,6 +631,8 @@ "lookalikes/lookalike_url_service.cc", "lookalikes/lookalike_url_service.h", "lookalikes/safety_tips/safety_tip_ui.h", + "lookalikes/safety_tips/safety_tips_config.cc", + "lookalikes/safety_tips/safety_tips_config.h", "mac/bluetooth_utility.h", "mac/bluetooth_utility.mm", "mac/dock.h", @@ -1340,8 +1344,6 @@ "previews/previews_lite_page_url_loader_interceptor.h", "previews/previews_offline_helper.cc", "previews/previews_offline_helper.h", - "previews/previews_prober.cc", - "previews/previews_prober.h", "previews/previews_service.cc", "previews/previews_service.h", "previews/previews_service_factory.cc", @@ -1879,12 +1881,13 @@ ] deps = [ ":active_use_util", + ":availability_protos", ":ntp_background_proto", - ":previews_protos", ":resource_prefetch_predictor_proto", "//base:i18n", "//base/allocator:buildflags", "//base/util/values:values_util", + "//build:branding_buildflags", "//cc", "//chrome:extra_resources", "//chrome:resources", @@ -1963,7 +1966,6 @@ "//components/history/content/browser", "//components/history/core/browser", "//components/history/core/common", - "//components/image_fetcher/core", "//components/infobars/core", "//components/invalidation/impl", "//components/keyed_service/content", @@ -1990,7 +1992,6 @@ "//components/network_hints/common", "//components/network_session_configurator/browser", "//components/network_time", - "//components/ntp_snippets", "//components/ntp_tiles", "//components/offline_items_collection/core", "//components/offline_pages/buildflags", @@ -2668,6 +2669,8 @@ "android/webapps/add_to_homescreen_manager.h", "android/webapps/single_tab_mode_tab_helper.cc", "android/webapps/single_tab_mode_tab_helper.h", + "android/webapps/webapk_ukm_recorder.cc", + "android/webapps/webapk_ukm_recorder.h", "android/webapps/webapp_registry.cc", "android/webapps/webapp_registry.h", "android/widget/thumbnail_generator.cc", @@ -2825,6 +2828,10 @@ "sync/profile_sync_service_android.h", "translate/android/translate_bridge.cc", ] + public_deps += [ + "//components/image_fetcher/core", + "//components/ntp_snippets", + ] deps += [ ":client_discourse_context_proto", ":delta_file_proto", @@ -2883,10 +2890,10 @@ "apps/app_service/app_icon_source.h", "apps/app_service/app_launch_params.cc", "apps/app_service/app_launch_params.h", + "apps/app_service/app_service_proxy.cc", + "apps/app_service/app_service_proxy.h", "apps/app_service/app_service_proxy_factory.cc", "apps/app_service/app_service_proxy_factory.h", - "apps/app_service/app_service_proxy_impl.cc", - "apps/app_service/app_service_proxy_impl.h", "apps/app_service/dip_px_util.cc", "apps/app_service/dip_px_util.h", "apps/intent_helper/apps_navigation_throttle.cc", @@ -3327,6 +3334,8 @@ "search/promos/promo_service_observer.h", "search/search_engine_base_url_tracker.cc", "search/search_engine_base_url_tracker.h", + "search/search_provider_observer.cc", + "search/search_provider_observer.h", "search/search_suggest/search_suggest_data.cc", "search/search_suggest/search_suggest_data.h", "search/search_suggest/search_suggest_loader.h", @@ -3484,11 +3493,12 @@ "//chrome/common/search:generate_chrome_colors_info", "//chrome/common/themes:autogenerated_theme_util", "//chrome/services/app_service:lib", - "//chrome/services/app_service/public/cpp:app_service_proxy", "//chrome/services/app_service/public/cpp:app_update", "//chrome/services/app_service/public/cpp:icon_loader", "//components/feedback", + "//components/image_fetcher/core", "//components/keep_alive_registry", + "//components/ntp_snippets", "//components/vector_icons", "//components/web_modal", "//components/zoom", @@ -3841,8 +3851,6 @@ "first_run/upgrade_util_linux.cc", "first_run/upgrade_util_linux.h", "icon_loader_auralinux.cc", - "password_manager/native_backend_kwallet_x.cc", - "password_manager/native_backend_kwallet_x.h", "platform_util_linux.cc", "shell_integration_linux.cc", "shell_integration_linux.h", @@ -3874,16 +3882,6 @@ ] } - # libsecret hard depends on GLib. - if (use_glib) { - sources += [ - "password_manager/native_backend_libsecret.cc", - "password_manager/native_backend_libsecret.h", - ] - defines += [ "USE_LIBSECRET" ] - deps += [ "//third_party/libsecret" ] - } - if (use_ozone) { sources += [ "fullscreen_ozone.cc", @@ -4683,14 +4681,18 @@ "offline_pages/android/request_coordinator_factory.cc", ] } + + public_deps += [ + "//components/offline_pages/core", + "//components/offline_pages/core/background:background_offliner", + "//components/offline_pages/core/prefetch", + ] + deps += [ "//chrome/common:offline_page_auto_fetcher_mojom", "//components/offline_pages/content/background_loader", "//components/offline_pages/content/renovations", - "//components/offline_pages/core", - "//components/offline_pages/core/background:background_offliner", "//components/offline_pages/core/downloads:offline_pages_ui_adapter", - "//components/offline_pages/core/prefetch", "//components/offline_pages/core/renovations", "//components/offline_pages/core/request_header:request_header", ] @@ -4957,6 +4959,8 @@ if (enable_supervised_users) { sources += [ + "component_updater/supervised_user_whitelist_installer.cc", + "component_updater/supervised_user_whitelist_installer.h", "content_settings/content_settings_supervised_provider.cc", "content_settings/content_settings_supervised_provider.h", "supervised_user/child_accounts/child_account_service.cc", @@ -5031,7 +5035,7 @@ if (enable_vr) { if (enable_gvr_services) { - deps += [ "android/vr:vr_android" ] + public_deps += [ "android/vr:vr_android" ] configs += [ "//third_party/gvr-android-sdk:libgvr_config" ] allow_circular_includes_from += [ "android/vr:vr_android" ] } @@ -5070,14 +5074,6 @@ configs += [ "//printing:cups" ] } - if (use_gnome_keyring) { - sources += [ - "password_manager/native_backend_gnome_x.cc", - "password_manager/native_backend_gnome_x.h", - ] - configs += [ "//components/os_crypt:gnome_keyring" ] - } - if (use_nss_certs) { sources += [ "certificate_manager_model.cc", @@ -5180,9 +5176,9 @@ ] } -proto_library("previews_protos") { +proto_library("availability_protos") { sources = [ - "previews/proto/previews_prober_cache_entry.proto", + "availability/proto/availability_prober_cache_entry.proto", ] }
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 8763ce2..e6f84a4 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -143,6 +143,7 @@ #include "ui/display/display_features.h" #include "ui/display/display_switches.h" #include "ui/events/blink/blink_features.h" +#include "ui/events/blink/prediction/filter_factory.h" #include "ui/events/blink/prediction/predictor_factory.h" #include "ui/events/event_switches.h" #include "ui/gfx/switches.h" @@ -1062,6 +1063,14 @@ kResamplingInputEventsLinearSecondEnabled, base::size(kResamplingInputEventsLinearSecondEnabled), nullptr}}; +const FeatureEntry::FeatureParam kFilteringPredictionEmptyFilterEnabled[] = { + {"filter", ui::input_prediction::kFilterNameEmpty}}; + +const FeatureEntry::FeatureVariation kFilteringPredictionFeatureVariations[] = { + {ui::input_prediction::kFilterNameEmpty, + kFilteringPredictionEmptyFilterEnabled, + base::size(kFilteringPredictionEmptyFilterEnabled), nullptr}}; + #if defined(OS_ANDROID) const FeatureEntry::FeatureParam kBottomOfflineIndicatorEnabled[] = { {"bottom_offline_indicator", "true"}}; @@ -1819,6 +1828,11 @@ {"enable-site-per-process", flag_descriptions::kStrictSiteIsolationName, flag_descriptions::kStrictSiteIsolationDescription, kOsAndroid, SINGLE_VALUE_TYPE(switches::kSitePerProcess)}, + {"enable-process-sharing-with-default-site-instances", + flag_descriptions::kProcessSharingWithDefaultSiteInstancesName, + flag_descriptions::kProcessSharingWithDefaultSiteInstancesDescription, + kOsAndroid, + FEATURE_VALUE_TYPE(features::kProcessSharingWithDefaultSiteInstances)}, {"enable-process-sharing-with-strict-site-instances", flag_descriptions::kProcessSharingWithStrictSiteInstancesName, flag_descriptions::kProcessSharingWithStrictSiteInstancesDescription, @@ -2556,11 +2570,6 @@ #endif // defined(OS_WIN) #if defined(OS_ANDROID) - {"omnibox-new-answer-layout", - flag_descriptions::kOmniboxNewAnswerLayoutName, - flag_descriptions::kOmniboxNewAnswerLayoutDescription, kOsAndroid, - FEATURE_VALUE_TYPE(omnibox::kOmniboxNewAnswerLayout)}, - {"omnibox-on-device-head-suggestions", flag_descriptions::kOmniboxOnDeviceHeadSuggestionsName, flag_descriptions::kOmniboxOnDeviceHeadSuggestionsDescription, kOsAndroid, @@ -3414,6 +3423,13 @@ kResamplingInputEventsFeatureVariations, "ResamplingScrollEvents")}, + {"enable-filtering-scroll-events", + flag_descriptions::kFilteringScrollPredictionName, + flag_descriptions::kFilteringScrollPredictionDescription, kOsAll, + FEATURE_WITH_PARAMS_VALUE_TYPE(features::kFilteringScrollPrediction, + kFilteringPredictionFeatureVariations, + "FilteringScrollPrediction")}, + {"compositor-threaded-scrollbar-scrolling", flag_descriptions::kCompositorThreadedScrollbarScrollingName, flag_descriptions::kCompositorThreadedScrollbarScrollingDescription, @@ -3762,8 +3778,7 @@ SINGLE_VALUE_TYPE(switches::kDisableBestEffortTasks)}, {"enable-sync-uss-passwords", flag_descriptions::kEnableSyncUSSPasswordsName, - flag_descriptions::kEnableSyncUSSPasswordsDescription, - kOsMac | kOsWin | kOsCrOS | kOsAndroid, + flag_descriptions::kEnableSyncUSSPasswordsDescription, kOsAll, FEATURE_VALUE_TYPE(switches::kSyncUSSPasswords)}, #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS) @@ -4192,6 +4207,11 @@ flag_descriptions::kNotificationSchedulerDebugOptionDescription, kOsAndroid, MULTI_VALUE_TYPE(kNotificationSchedulerChoices)}, + {"update-hover-at-begin-frame", + flag_descriptions::kUpdateHoverAtBeginFrameName, + flag_descriptions::kUpdateHoverAtBeginFrameDescription, kOsAll, + FEATURE_VALUE_TYPE(features::kUpdateHoverAtBeginFrame)}, + // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.cc b/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.cc index 100b9f28..e7fd6356 100644 --- a/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.cc +++ b/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.cc
@@ -109,6 +109,13 @@ static_cast<TermsAndConditionsState>(state)); } +void AssistantPaymentRequestDelegate::OnTermsAndConditionsLinkClicked( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + jint link) { + ui_controller_->OnTermsAndConditionsLinkClicked(link); +} + base::android::ScopedJavaGlobalRef<jobject> AssistantPaymentRequestDelegate::GetJavaObject() { return java_assistant_payment_request_delegate_;
diff --git a/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.h b/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.h index 87545be..1b605847 100644 --- a/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.h +++ b/chrome/browser/android/autofill_assistant/assistant_payment_request_delegate.h
@@ -36,6 +36,11 @@ const base::android::JavaParamRef<jobject>& jcaller, jint state); + void OnTermsAndConditionsLinkClicked( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& jcaller, + jint link); + base::android::ScopedJavaGlobalRef<jobject> GetJavaObject(); private:
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc index 979488d8..16225f9 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc +++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -695,6 +695,10 @@ ui_delegate_->SetTermsAndConditions(state); } +void UiControllerAndroid::OnTermsAndConditionsLinkClicked(int link) { + ui_delegate_->OnTermsAndConditionsLinkClicked(link); +} + void UiControllerAndroid::OnPaymentRequestOptionsChanged( const PaymentRequestOptions* payment_options) { JNIEnv* env = AttachCurrentThread(); @@ -714,8 +718,13 @@ env, jmodel, payment_options->request_shipping); Java_AssistantPaymentRequestModel_setRequestPayment( env, jmodel, payment_options->request_payment_method); - Java_AssistantPaymentRequestModel_setRequestTermsAndConditions( - env, jmodel, payment_options->request_terms_and_conditions); + Java_AssistantPaymentRequestModel_setAcceptTermsAndConditionsText( + env, jmodel, + base::android::ConvertUTF8ToJavaString( + env, payment_options->accept_terms_and_conditions_text)); + Java_AssistantPaymentRequestModel_setShowTermsAsCheckbox( + env, jmodel, payment_options->show_terms_as_checkbox); + Java_AssistantPaymentRequestModel_setSupportedBasicCardNetworks( env, jmodel, base::android::ToJavaArrayOfStrings(
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h index a2b319f..68c3a3a 100644 --- a/chrome/browser/android/autofill_assistant/ui_controller_android.h +++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -119,6 +119,7 @@ std::string email); void OnCreditCardChanged(std::unique_ptr<autofill::CreditCard> card); void OnTermsAndConditionsChanged(TermsAndConditionsState state); + void OnTermsAndConditionsLinkClicked(int link); // Called by AssistantFormDelegate: void OnCounterChanged(int input_index, int counter_index, int value);
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index a155ba3a..569aae2 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -205,7 +205,6 @@ &offline_pages::kPrefetchingOfflinePagesFeature, &omnibox::kHideSteadyStateUrlScheme, &omnibox::kHideSteadyStateUrlTrivialSubdomains, - &omnibox::kOmniboxNewAnswerLayout, &omnibox::kOmniboxRichEntitySuggestions, &omnibox::kQueryInOmnibox, &omnibox::kUIExperimentShowSuggestionFavicons,
diff --git a/chrome/browser/android/digital_asset_links/digital_asset_links_handler.cc b/chrome/browser/android/digital_asset_links/digital_asset_links_handler.cc index 095e5d481..d925f53 100644 --- a/chrome/browser/android/digital_asset_links/digital_asset_links_handler.cc +++ b/chrome/browser/android/digital_asset_links/digital_asset_links_handler.cc
@@ -27,6 +27,10 @@ namespace { +// In some cases we get a network change while fetching the digital asset +// links file. See https://crbug.com/987329. +const int kNumNetworkRetries = 1; + // Location on a website where the asset links file can be found, see // https://developers.google.com/digital-asset-links/v1/getting-started. const char kAssetLinksAbsolutePath[] = ".well-known/assetlinks.json"; @@ -246,6 +250,9 @@ request->url = request_url; url_loader_ = network::SimpleURLLoader::Create(std::move(request), traffic_annotation); + url_loader_->SetRetryOptions( + kNumNetworkRetries, + network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE); url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( shared_url_loader_factory_.get(), base::BindOnce(&DigitalAssetLinksHandler::OnURLLoadComplete,
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc index f5571be..5aca12b 100644 --- a/chrome/browser/android/download/download_manager_service.cc +++ b/chrome/browser/android/download/download_manager_service.cc
@@ -220,8 +220,14 @@ void DownloadManagerService::OnFullBrowserStarted(JNIEnv* env, jobject obj) { registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, content::NotificationService::AllSources()); - Profile* profile = ProfileManager::GetActiveUserProfile(); + // Register coordinator for each available profile. + Profile* profile = + ProfileManager::GetActiveUserProfile()->GetOriginalProfile(); ResetCoordinatorIfNeeded(profile->GetProfileKey()); + if (profile->HasOffTheRecordProfile()) { + ResetCoordinatorIfNeeded( + profile->GetOffTheRecordProfile()->GetProfileKey()); + } } void DownloadManagerService::Observe(
diff --git a/chrome/browser/android/vr/gvr_input_delegate.cc b/chrome/browser/android/vr/gvr_input_delegate.cc index fcb5c45..644b125 100644 --- a/chrome/browser/android/vr/gvr_input_delegate.cc +++ b/chrome/browser/android/vr/gvr_input_delegate.cc
@@ -47,7 +47,6 @@ // [0.0, 1.0], with (0, 0) corresponding to the top-left of the touchpad. // Normalize the values to use X axis range -1 (left) to 1 (right) and Y // axis range -1 (top) to 1 (bottom). - // TODO(https://crbug.com/966060): Revisit this if the convention changes. gamepad.axes[0] = (data.touch_pos.x() * 2.0) - 1.0; gamepad.axes[1] = (data.touch_pos.y() * 2.0) - 1.0; } else {
diff --git a/chrome/browser/android/webapk/webapk.proto b/chrome/browser/android/webapk/webapk.proto index e75cc63..7b84ad9f 100644 --- a/chrome/browser/android/webapk/webapk.proto +++ b/chrome/browser/android/webapk/webapk.proto
@@ -47,6 +47,7 @@ DISPLAY_MODE_DIFFERS = 12; WEB_SHARE_TARGET_DIFFERS = 13; MANUALLY_TRIGGERED = 14; + PRIMARY_ICON_MASKABLE_DIFFERS = 15; } // Package name of the WebAPK. @@ -116,6 +117,8 @@ // Specifies Chrome's intended usages for the image. repeated Usage usages = 8; + optional bool is_primay_icon_maskable = 9; + reserved 2, 3, 4, 7; }
diff --git a/chrome/browser/android/webapk/webapk_install_service.cc b/chrome/browser/android/webapk/webapk_install_service.cc index 9c4134c..79116e3 100644 --- a/chrome/browser/android/webapk/webapk_install_service.cc +++ b/chrome/browser/android/webapk/webapk_install_service.cc
@@ -37,6 +37,7 @@ void WebApkInstallService::InstallAsync(content::WebContents* web_contents, const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, WebappInstallSource install_source) { if (IsInstallInProgress(shortcut_info.manifest_url)) { @@ -54,7 +55,8 @@ // WebContents has been destroyed before the install is finished. auto observer = std::make_unique<LifetimeObserver>(web_contents); WebApkInstaller::InstallAsync( - browser_context_, shortcut_info, primary_icon, badge_icon, + browser_context_, shortcut_info, primary_icon, is_primary_icon_maskable, + badge_icon, base::Bind(&WebApkInstallService::OnFinishedInstall, weak_ptr_factory_.GetWeakPtr(), base::Passed(&observer), shortcut_info, primary_icon));
diff --git a/chrome/browser/android/webapk/webapk_install_service.h b/chrome/browser/android/webapk/webapk_install_service.h index 5f66f384..eee6ada 100644 --- a/chrome/browser/android/webapk/webapk_install_service.h +++ b/chrome/browser/android/webapk/webapk_install_service.h
@@ -70,6 +70,7 @@ void InstallAsync(content::WebContents* web_contents, const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, WebappInstallSource install_source);
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc index f27f3e5..d978586 100644 --- a/chrome/browser/android/webapk/webapk_installer.cc +++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -120,6 +120,8 @@ return webapk::WebApk::OLD_SHELL_APK; case WebApkUpdateReason::PRIMARY_ICON_HASH_DIFFERS: return webapk::WebApk::PRIMARY_ICON_HASH_DIFFERS; + case WebApkUpdateReason::PRIMARY_ICON_MASKABLE_DIFFERS: + return webapk::WebApk::PRIMARY_ICON_MASKABLE_DIFFERS; case WebApkUpdateReason::BADGE_ICON_HASH_DIFFERS: return webapk::WebApk::BADGE_ICON_HASH_DIFFERS; case WebApkUpdateReason::SCOPE_DIFFERS: @@ -178,6 +180,7 @@ std::unique_ptr<std::string> BuildProtoInBackground( const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, const std::string& package_name, const std::string& version, @@ -264,6 +267,7 @@ if (entry.first == shortcut_info.best_primary_icon_url.spec()) { SetImageData(image, primary_icon); image->add_usages(webapk::Image::PRIMARY_ICON); + image->set_is_primay_icon_maskable(is_primary_icon_maskable); } if (entry.first == shortcut_info.best_badge_icon_url.spec()) { if (shortcut_info.best_badge_icon_url != @@ -289,6 +293,7 @@ const base::FilePath& update_request_path, const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, const std::string& package_name, const std::string& version, @@ -299,8 +304,9 @@ base::BlockingType::MAY_BLOCK); std::unique_ptr<std::string> proto = BuildProtoInBackground( - shortcut_info, primary_icon, badge_icon, package_name, version, - icon_url_to_murmur2_hash, is_manifest_stale, update_reason); + shortcut_info, primary_icon, is_primary_icon_maskable, badge_icon, + package_name, version, icon_url_to_murmur2_hash, is_manifest_stale, + update_reason); // Create directory if it does not exist. base::CreateDirectory(update_request_path.DirName()); @@ -339,12 +345,13 @@ void WebApkInstaller::InstallAsync(content::BrowserContext* context, const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, FinishCallback finish_callback) { // The installer will delete itself when it is done. WebApkInstaller* installer = new WebApkInstaller(context); - installer->InstallAsync(shortcut_info, primary_icon, badge_icon, - std::move(finish_callback)); + installer->InstallAsync(shortcut_info, primary_icon, is_primary_icon_maskable, + badge_icon, std::move(finish_callback)); } // static @@ -360,10 +367,11 @@ void WebApkInstaller::InstallAsyncForTesting(WebApkInstaller* installer, const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, FinishCallback callback) { - installer->InstallAsync(shortcut_info, primary_icon, badge_icon, - std::move(callback)); + installer->InstallAsync(shortcut_info, primary_icon, is_primary_icon_maskable, + badge_icon, std::move(callback)); } // static @@ -389,6 +397,7 @@ void WebApkInstaller::BuildProto( const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, const std::string& package_name, const std::string& version, @@ -398,8 +407,8 @@ base::PostTaskAndReplyWithResult( GetBackgroundTaskRunner().get(), FROM_HERE, base::BindOnce(&BuildProtoInBackground, shortcut_info, primary_icon, - badge_icon, package_name, version, - icon_url_to_murmur2_hash, is_manifest_stale, + is_primary_icon_maskable, badge_icon, package_name, + version, icon_url_to_murmur2_hash, is_manifest_stale, WebApkUpdateReason::NONE), std::move(callback)); } @@ -409,6 +418,7 @@ const base::FilePath& update_request_path, const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, const std::string& package_name, const std::string& version, @@ -419,8 +429,9 @@ base::PostTaskAndReplyWithResult( GetBackgroundTaskRunner().get(), FROM_HERE, base::BindOnce(&StoreUpdateRequestToFileInBackground, update_request_path, - shortcut_info, primary_icon, badge_icon, package_name, - version, icon_url_to_murmur2_hash, is_manifest_stale, + shortcut_info, primary_icon, is_primary_icon_maskable, + badge_icon, package_name, version, + icon_url_to_murmur2_hash, is_manifest_stale, update_reason), std::move(callback)); } @@ -486,6 +497,7 @@ void WebApkInstaller::InstallAsync(const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, FinishCallback finish_callback) { install_duration_timer_.reset(new base::ElapsedTimer()); @@ -493,6 +505,7 @@ install_shortcut_info_.reset(new ShortcutInfo(shortcut_info)); install_primary_icon_ = primary_icon; install_badge_icon_ = badge_icon; + is_primary_icon_maskable_ = is_primary_icon_maskable; short_name_ = shortcut_info.short_name; finish_callback_ = std::move(finish_callback); task_type_ = INSTALL; @@ -664,8 +677,9 @@ } BuildProto(*install_shortcut_info_, install_primary_icon_, - install_badge_icon_, "" /* package_name */, "" /* version */, - icon_url_to_murmur2_hash, false /* is_manifest_stale */, + is_primary_icon_maskable_, install_badge_icon_, + "" /* package_name */, "" /* version */, icon_url_to_murmur2_hash, + false /* is_manifest_stale */, base::BindOnce(&WebApkInstaller::SendRequest, weak_ptr_factory_.GetWeakPtr())); }
diff --git a/chrome/browser/android/webapk/webapk_installer.h b/chrome/browser/android/webapk/webapk_installer.h index 3739d6e..a888075 100644 --- a/chrome/browser/android/webapk/webapk_installer.h +++ b/chrome/browser/android/webapk/webapk_installer.h
@@ -60,6 +60,7 @@ static void InstallAsync(content::BrowserContext* context, const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, FinishCallback finish_callback); @@ -76,6 +77,7 @@ static void InstallAsyncForTesting(WebApkInstaller* installer, const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, FinishCallback callback); @@ -106,6 +108,8 @@ static void BuildProto( const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, + const SkBitmap& badge_icon, const std::string& package_name, const std::string& version, @@ -120,6 +124,7 @@ const base::FilePath& update_request_path, const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, const std::string& package_name, const std::string& version, @@ -158,6 +163,7 @@ // install completed or failed. void InstallAsync(const ShortcutInfo& shortcut_info, const SkBitmap& primary_icon, + bool is_primary_icon_maskable, const SkBitmap& badge_icon, FinishCallback finish_callback); @@ -214,6 +220,8 @@ SkBitmap install_primary_icon_; SkBitmap install_badge_icon_; + bool is_primary_icon_maskable_; + base::string16 short_name_; // WebAPK server URL.
diff --git a/chrome/browser/android/webapk/webapk_installer_unittest.cc b/chrome/browser/android/webapk/webapk_installer_unittest.cc index 2d91b23f..8f88933 100644 --- a/chrome/browser/android/webapk/webapk_installer_unittest.cc +++ b/chrome/browser/android/webapk/webapk_installer_unittest.cc
@@ -114,7 +114,7 @@ // WebApkInstaller owns itself. WebApkInstaller::InstallAsyncForTesting( - installer.release(), info, SkBitmap(), SkBitmap(), + installer.release(), info, SkBitmap(), false, SkBitmap(), base::BindOnce(&WebApkInstallerRunner::OnCompleted, base::Unretained(this))); @@ -164,8 +164,8 @@ base::RunLoop run_loop; quit_closure_ = run_loop.QuitClosure(); WebApkInstaller::StoreUpdateRequestToFile( - update_request_path, ShortcutInfo((GURL())), SkBitmap(), SkBitmap(), "", - "", std::map<std::string, std::string>(), false, + update_request_path, ShortcutInfo((GURL())), SkBitmap(), false, + SkBitmap(), "", "", std::map<std::string, std::string>(), false, WebApkUpdateReason::PRIMARY_ICON_HASH_DIFFERS, base::BindOnce(&UpdateRequestStorer::OnComplete, base::Unretained(this))); @@ -216,8 +216,9 @@ SkBitmap primary_icon(gfx::test::CreateBitmap(144, 144)); SkBitmap badge_icon(gfx::test::CreateBitmap(72, 72)); WebApkInstaller::BuildProto( - info, primary_icon, badge_icon, "" /* package_name */, "" /* version */, - icon_url_to_murmur2_hash, is_manifest_stale, + info, primary_icon, false /* is_primary_icon_maskable */, badge_icon, + "" /* package_name */, "" /* version */, icon_url_to_murmur2_hash, + is_manifest_stale, base::BindOnce(&BuildProtoRunner::OnBuiltWebApkProto, base::Unretained(this)));
diff --git a/chrome/browser/android/webapk/webapk_types.h b/chrome/browser/android/webapk/webapk_types.h index 73d202f9..197e527 100644 --- a/chrome/browser/android/webapk/webapk_types.h +++ b/chrome/browser/android/webapk/webapk_types.h
@@ -13,6 +13,7 @@ NONE, OLD_SHELL_APK, PRIMARY_ICON_HASH_DIFFERS, + PRIMARY_ICON_MASKABLE_DIFFERS, BADGE_ICON_HASH_DIFFERS, SCOPE_DIFFERS, START_URL_DIFFERS,
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc index 040376e..a8e8c7b7 100644 --- a/chrome/browser/android/webapk/webapk_update_data_fetcher.cc +++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.cc
@@ -7,6 +7,7 @@ #include <jni.h> #include <vector> +#include "base/android/build_info.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/bind.h" @@ -34,6 +35,12 @@ namespace { +bool DoesAndroidSupportMaskableIcons() { + // TODO(crbug.com/977173): re-enable maskable icon support once server support + // is ready. + return false; +} + // Returns whether the given |url| is within the scope of the |scope| url. bool IsInScope(const GURL& url, const GURL& scope) { return base::StartsWith(url.spec(), scope.spec(), @@ -63,6 +70,7 @@ scope_(scope), web_manifest_url_(web_manifest_url), info_(GURL()), + is_primary_icon_maskable_(false), weak_ptr_factory_(this) { java_ref_.Reset(env, obj); } @@ -111,6 +119,7 @@ InstallableParams params; params.valid_manifest = true; + params.prefer_maskable_icon = DoesAndroidSupportMaskableIcons(); params.has_worker = true; params.valid_primary_icon = true; params.valid_badge_icon = true; @@ -148,6 +157,7 @@ info_.manifest_url = data.manifest_url; info_.best_primary_icon_url = data.primary_icon_url; primary_icon_ = *data.primary_icon; + is_primary_icon_maskable_ = data.has_maskable_primary_icon; if (data.badge_icon && !data.badge_icon->drawsNothing()) { info_.best_badge_icon_url = data.badge_icon_url; @@ -213,6 +223,7 @@ base::android::ConvertUTF8ToJavaString(env, primary_icon_murmur2_hash); ScopedJavaLocalRef<jobject> java_primary_icon = gfx::ConvertToJavaBitmap(&primary_icon_); + jboolean java_is_primary_icon_maskable = is_primary_icon_maskable_; ScopedJavaLocalRef<jstring> java_badge_icon_url = base::android::ConvertUTF8ToJavaString(env, info_.best_badge_icon_url.spec()); @@ -264,8 +275,9 @@ Java_WebApkUpdateDataFetcher_onDataAvailable( env, java_ref_, java_url, java_scope, java_name, java_short_name, java_primary_icon_url, java_primary_icon_murmur2_hash, java_primary_icon, - java_badge_icon_url, java_badge_icon_murmur2_hash, java_badge_icon, - java_icon_urls, info_.display, info_.orientation, + java_is_primary_icon_maskable, java_badge_icon_url, + java_badge_icon_murmur2_hash, java_badge_icon, java_icon_urls, + info_.display, info_.orientation, OptionalSkColorToJavaColor(info_.theme_color), OptionalSkColorToJavaColor(info_.background_color), java_share_action, java_share_params_title, java_share_params_text, java_share_params_url,
diff --git a/chrome/browser/android/webapk/webapk_update_data_fetcher.h b/chrome/browser/android/webapk/webapk_update_data_fetcher.h index c69ec782..f11ab18 100644 --- a/chrome/browser/android/webapk/webapk_update_data_fetcher.h +++ b/chrome/browser/android/webapk/webapk_update_data_fetcher.h
@@ -82,6 +82,8 @@ // Downloaded data for |web_manifest_url_|. ShortcutInfo info_; SkBitmap primary_icon_; + bool is_primary_icon_maskable_; + SkBitmap badge_icon_; base::WeakPtrFactory<WebApkUpdateDataFetcher> weak_ptr_factory_;
diff --git a/chrome/browser/android/webapk/webapk_update_manager.cc b/chrome/browser/android/webapk/webapk_update_manager.cc index d9986a5b0..332434f 100644 --- a/chrome/browser/android/webapk/webapk_update_manager.cc +++ b/chrome/browser/android/webapk/webapk_update_manager.cc
@@ -54,6 +54,7 @@ const JavaParamRef<jstring>& java_short_name, const JavaParamRef<jstring>& java_primary_icon_url, const JavaParamRef<jobject>& java_primary_icon_bitmap, + jboolean java_is_primary_icon_maskable, const JavaParamRef<jstring>& java_badge_icon_url, const JavaParamRef<jobject>& java_badge_icon_bitmap, const JavaParamRef<jobjectArray>& java_icon_urls, @@ -166,9 +167,10 @@ static_cast<WebApkUpdateReason>(java_update_reason); WebApkInstaller::StoreUpdateRequestToFile( - base::FilePath(update_request_path), info, primary_icon, badge_icon, - webapk_package, std::to_string(java_webapk_version), - icon_url_to_murmur2_hash, java_is_manifest_stale, update_reason, + base::FilePath(update_request_path), info, primary_icon, + java_is_primary_icon_maskable, badge_icon, webapk_package, + std::to_string(java_webapk_version), icon_url_to_murmur2_hash, + java_is_manifest_stale, update_reason, base::BindOnce(&base::android::RunBooleanCallbackAndroid, ScopedJavaGlobalRef<jobject>(java_callback))); }
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc index e2626c4..411ff3f7 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -46,8 +46,9 @@ } bool DoesAndroidSupportMaskableIcons() { - return base::android::BuildInfo::GetInstance()->sdk_int() >= - base::android::SDK_VERSION_OREO; + // TODO(crbug.com/977173): re-enable maskable icon support once server support + // is ready. + return false; } InstallableParams ParamsToPerformManifestAndIconFetch() {
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc index 48384ab..4acdcae3 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
@@ -140,7 +140,8 @@ is_installable = false; } else if (params.valid_manifest && params.has_worker) { if (!IsManifestValidForWebApp(manifest_, - true /* check_webapp_manifest_display */)) { + true /* check_webapp_manifest_display */, + false /* prefer_maskable_icon */)) { code = valid_manifest_->errors.at(0); is_installable = false; } else if (!is_installable_) {
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.cc b/chrome/browser/android/webapps/add_to_homescreen_manager.cc index b882493..22e3aa0 100644 --- a/chrome/browser/android/webapps/add_to_homescreen_manager.cc +++ b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
@@ -70,6 +70,7 @@ WebApkInstallService::Get(web_contents->GetBrowserContext()) ->InstallAsync(web_contents, data_fetcher_->shortcut_info(), data_fetcher_->primary_icon(), + data_fetcher_->has_maskable_primary_icon(), data_fetcher_->badge_icon(), InstallableMetrics::GetInstallSource( web_contents, InstallTrigger::MENU));
diff --git a/chrome/browser/android/webapps/webapk_ukm_recorder.cc b/chrome/browser/android/webapps/webapk_ukm_recorder.cc new file mode 100644 index 0000000..3cdaabb --- /dev/null +++ b/chrome/browser/android/webapps/webapk_ukm_recorder.cc
@@ -0,0 +1,45 @@ +// 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. + +#include "chrome/browser/android/webapps/webapk_ukm_recorder.h" + +#include <jni.h> + +#include "base/android/jni_string.h" +#include "chrome/android/chrome_jni_headers/WebApkUkmRecorder_jni.h" +#include "services/metrics/public/cpp/metrics_utils.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "url/gurl.h" + +using base::android::JavaParamRef; + +// static +void WebApkUkmRecorder::RecordSessionDuration(const GURL& manifest_url, + int64_t distributor, + int64_t version_code, + int64_t duration) { + if (!manifest_url.is_valid()) + return; + + ukm::SourceId source_id = ukm::UkmRecorder::GetNewSourceID(); + ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get(); + ukm_recorder->UpdateSourceURL(source_id, manifest_url); + ukm::builders::WebAPK_SessionEnd(source_id) + .SetDistributor(distributor) + .SetAppVersion(version_code) + .SetSessionDuration(ukm::GetExponentialBucketMinForUserTiming(duration)) + .Record(ukm_recorder); +} + +// Called by the Java counterpart to record the Session Duration UKM metric. +void JNI_WebApkUkmRecorder_RecordSessionDuration( + JNIEnv* env, + const JavaParamRef<jstring>& manifest_url, + jint distributor, + jint version_code, + jlong duration) { + WebApkUkmRecorder::RecordSessionDuration( + GURL(base::android::ConvertJavaStringToUTF8(env, manifest_url)), + distributor, version_code, duration); +}
diff --git a/chrome/browser/android/webapps/webapk_ukm_recorder.h b/chrome/browser/android/webapps/webapk_ukm_recorder.h new file mode 100644 index 0000000..2c5b3c2b --- /dev/null +++ b/chrome/browser/android/webapps/webapk_ukm_recorder.h
@@ -0,0 +1,31 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ANDROID_WEBAPPS_WEBAPK_UKM_RECORDER_H_ +#define CHROME_BROWSER_ANDROID_WEBAPPS_WEBAPK_UKM_RECORDER_H_ + +#include <stdint.h> + +#include "base/macros.h" + +class GURL; + +// WebApkUkmRecorder is the C++ counterpart of +// org.chromium.chrome.browser.webapps's WebApkUkmRecorder in Java. +// It contains static WebAPK UKM metrics-recording logic, and only +// needs to be in a class so that it can be a friend of ukm::UkmRecorder. +// All of the actual JNI goes through raw functions in webapk_ukm_recorder.cc to +// avoid having to instantiate this class and deal with object lifetimes. +class WebApkUkmRecorder { + public: + static void RecordSessionDuration(const GURL& manifest_url, + int64_t distributor, + int64_t version_code, + int64_t duration); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(WebApkUkmRecorder); +}; + +#endif // CHROME_BROWSER_ANDROID_WEBAPPS_WEBAPK_UKM_RECORDER_H_
diff --git a/chrome/browser/apps/app_service/app_icon_source.cc b/chrome/browser/apps/app_service/app_icon_source.cc index a919a8e6..d8d517e 100644 --- a/chrome/browser/apps/app_service/app_icon_source.cc +++ b/chrome/browser/apps/app_service/app_icon_source.cc
@@ -11,11 +11,11 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/dip_px_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/url_constants.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" #include "extensions/grit/extensions_browser_resources.h" #include "ui/base/resource/resource_bundle.h" #include "url/gurl.h"
diff --git a/chrome/browser/apps/app_service/app_service_proxy_impl.cc b/chrome/browser/apps/app_service/app_service_proxy.cc similarity index 73% rename from chrome/browser/apps/app_service/app_service_proxy_impl.cc rename to chrome/browser/apps/app_service/app_service_proxy.cc index c8f17d5..f904890b 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_impl.cc +++ b/chrome/browser/apps/app_service/app_service_proxy.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/apps/app_service/app_service_proxy_impl.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include <utility> @@ -16,10 +16,10 @@ namespace apps { -AppServiceProxyImpl::InnerIconLoader::InnerIconLoader(AppServiceProxyImpl* host) +AppServiceProxy::InnerIconLoader::InnerIconLoader(AppServiceProxy* host) : host_(host), overriding_icon_loader_for_testing_(nullptr) {} -apps::mojom::IconKeyPtr AppServiceProxyImpl::InnerIconLoader::GetIconKey( +apps::mojom::IconKeyPtr AppServiceProxy::InnerIconLoader::GetIconKey( const std::string& app_id) { if (overriding_icon_loader_for_testing_) { return overriding_icon_loader_for_testing_->GetIconKey(app_id); @@ -35,7 +35,7 @@ } std::unique_ptr<IconLoader::Releaser> -AppServiceProxyImpl::InnerIconLoader::LoadIconFromIconKey( +AppServiceProxy::InnerIconLoader::LoadIconFromIconKey( apps::mojom::AppType app_type, const std::string& app_id, apps::mojom::IconKeyPtr icon_key, @@ -66,23 +66,17 @@ } // static -AppServiceProxyImpl* AppServiceProxyImpl::GetImplForTesting(Profile* profile) { - return static_cast<AppServiceProxyImpl*>( - AppServiceProxyFactory::GetForProfile(profile)); -} - -// static -AppServiceProxyImpl* AppServiceProxyImpl::CreateForTesting( +AppServiceProxy* AppServiceProxy::CreateForTesting( Profile* profile, service_manager::Connector* connector) { - return new AppServiceProxyImpl(profile, connector); + return new AppServiceProxy(profile, connector); } -AppServiceProxyImpl::AppServiceProxyImpl(Profile* profile) - : AppServiceProxyImpl(profile, nullptr) {} +AppServiceProxy::AppServiceProxy(Profile* profile) + : AppServiceProxy(profile, nullptr) {} -AppServiceProxyImpl::AppServiceProxyImpl(Profile* profile, - service_manager::Connector* connector) +AppServiceProxy::AppServiceProxy(Profile* profile, + service_manager::Connector* connector) : inner_icon_loader_(this), icon_coalescer_(&inner_icon_loader_), outer_icon_loader_(&icon_coalescer_, @@ -100,15 +94,15 @@ mojo::MakeRequest(&app_service_)); if (app_service_.is_bound()) { - // The AppServiceProxyImpl is a subscriber: something that wants to be able + // The AppServiceProxy is a subscriber: something that wants to be able // to list all known apps. apps::mojom::SubscriberPtr subscriber; bindings_.AddBinding(this, mojo::MakeRequest(&subscriber)); app_service_->RegisterSubscriber(std::move(subscriber), nullptr); #if defined(OS_CHROMEOS) - // The AppServiceProxyImpl is also a publisher, of a variety of app types. - // That responsibility isn't intrinsically part of the AppServiceProxyImpl, + // The AppServiceProxy is also a publisher, of a variety of app types. + // That responsibility isn't intrinsically part of the AppServiceProxy, // but doing that here, for each such app type, is as good a place as any. built_in_chrome_os_apps_.Initialize(app_service_, profile); crostini_apps_.Initialize(app_service_, profile); @@ -120,15 +114,22 @@ } } -AppServiceProxyImpl::~AppServiceProxyImpl() = default; +AppServiceProxy::~AppServiceProxy() = default; -apps::mojom::IconKeyPtr AppServiceProxyImpl::GetIconKey( - const std::string& app_id) { +apps::mojom::AppServicePtr& AppServiceProxy::AppService() { + return app_service_; +} + +apps::AppRegistryCache& AppServiceProxy::AppRegistryCache() { + return cache_; +} + +apps::mojom::IconKeyPtr AppServiceProxy::GetIconKey(const std::string& app_id) { return outer_icon_loader_.GetIconKey(app_id); } std::unique_ptr<apps::IconLoader::Releaser> -AppServiceProxyImpl::LoadIconFromIconKey( +AppServiceProxy::LoadIconFromIconKey( apps::mojom::AppType app_type, const std::string& app_id, apps::mojom::IconKeyPtr icon_key, @@ -141,10 +142,10 @@ allow_placeholder_icon, std::move(callback)); } -void AppServiceProxyImpl::Launch(const std::string& app_id, - int32_t event_flags, - apps::mojom::LaunchSource launch_source, - int64_t display_id) { +void AppServiceProxy::Launch(const std::string& app_id, + int32_t event_flags, + apps::mojom::LaunchSource launch_source, + int64_t display_id) { if (app_service_.is_bound()) { cache_.ForOneApp(app_id, [this, event_flags, launch_source, display_id](const apps::AppUpdate& update) { @@ -154,8 +155,8 @@ } } -void AppServiceProxyImpl::SetPermission(const std::string& app_id, - apps::mojom::PermissionPtr permission) { +void AppServiceProxy::SetPermission(const std::string& app_id, + apps::mojom::PermissionPtr permission) { if (app_service_.is_bound()) { cache_.ForOneApp( app_id, [this, &permission](const apps::AppUpdate& update) { @@ -165,7 +166,7 @@ } } -void AppServiceProxyImpl::Uninstall(const std::string& app_id) { +void AppServiceProxy::Uninstall(const std::string& app_id) { if (app_service_.is_bound()) { cache_.ForOneApp(app_id, [this](const apps::AppUpdate& update) { app_service_->Uninstall(update.AppType(), update.AppId()); @@ -173,7 +174,7 @@ } } -void AppServiceProxyImpl::OpenNativeSettings(const std::string& app_id) { +void AppServiceProxy::OpenNativeSettings(const std::string& app_id) { if (app_service_.is_bound()) { cache_.ForOneApp(app_id, [this](const apps::AppUpdate& update) { app_service_->OpenNativeSettings(update.AppType(), update.AppId()); @@ -181,11 +182,11 @@ } } -void AppServiceProxyImpl::FlushMojoCallsForTesting() { +void AppServiceProxy::FlushMojoCallsForTesting() { bindings_.FlushForTesting(); } -apps::IconLoader* AppServiceProxyImpl::OverrideInnerIconLoaderForTesting( +apps::IconLoader* AppServiceProxy::OverrideInnerIconLoaderForTesting( apps::IconLoader* icon_loader) { apps::IconLoader* old = inner_icon_loader_.overriding_icon_loader_for_testing_; @@ -193,7 +194,7 @@ return old; } -void AppServiceProxyImpl::ReInitializeCrostiniForTesting(Profile* profile) { +void AppServiceProxy::ReInitializeCrostiniForTesting(Profile* profile) { #if defined(OS_CHROMEOS) if (app_service_.is_bound()) { crostini_apps_.ReInitializeForTesting(app_service_, profile); @@ -201,7 +202,7 @@ #endif } -void AppServiceProxyImpl::Shutdown() { +void AppServiceProxy::Shutdown() { #if defined(OS_CHROMEOS) if (app_service_.is_bound()) { extension_apps_.Shutdown(); @@ -210,11 +211,11 @@ #endif // OS_CHROMEOS } -void AppServiceProxyImpl::OnApps(std::vector<apps::mojom::AppPtr> deltas) { +void AppServiceProxy::OnApps(std::vector<apps::mojom::AppPtr> deltas) { cache_.OnApps(std::move(deltas)); } -void AppServiceProxyImpl::Clone(apps::mojom::SubscriberRequest request) { +void AppServiceProxy::Clone(apps::mojom::SubscriberRequest request) { bindings_.AddBinding(this, std::move(request)); }
diff --git a/chrome/browser/apps/app_service/app_service_proxy_impl.h b/chrome/browser/apps/app_service/app_service_proxy.h similarity index 77% rename from chrome/browser/apps/app_service/app_service_proxy_impl.h rename to chrome/browser/apps/app_service/app_service_proxy.h index 3cbfc30..d74151c 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_impl.h +++ b/chrome/browser/apps/app_service/app_service_proxy.h
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_IMPL_H_ -#define CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_IMPL_H_ +#ifndef CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_ +#define CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_ #include <memory> #include "base/macros.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" +#include "chrome/services/app_service/public/cpp/app_registry_cache.h" #include "chrome/services/app_service/public/cpp/icon_cache.h" #include "chrome/services/app_service/public/cpp/icon_coalescer.h" #include "components/keyed_service/core/keyed_service.h" @@ -34,27 +34,22 @@ // proxy for a given Profile, and therefore share its caches. // // See chrome/services/app_service/README.md. -class AppServiceProxyImpl : public KeyedService, - public apps::AppServiceProxy, - public apps::mojom::Subscriber { +class AppServiceProxy : public KeyedService, + public apps::IconLoader, + public apps::mojom::Subscriber { public: - // This method returns an AppServiceProxyImpl, not just an AppServiceProxy, so - // that callers (which are presumably in test code) can then call other - // XxxForTesting methods. - // - // For regular (non-test) code, use AppServiceProxyFactory::GetForProfile - // instead. - static AppServiceProxyImpl* GetImplForTesting(Profile* profile); - - static AppServiceProxyImpl* CreateForTesting( + static AppServiceProxy* CreateForTesting( Profile* profile, service_manager::Connector* connector); - explicit AppServiceProxyImpl(Profile* profile); + explicit AppServiceProxy(Profile* profile); - ~AppServiceProxyImpl() override; + ~AppServiceProxy() override; - // apps::AppServiceProxy (including apps::IconLoader) overrides. + apps::mojom::AppServicePtr& AppService(); + apps::AppRegistryCache& AppRegistryCache(); + + // apps::IconLoader overrides. apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override; std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey( apps::mojom::AppType app_type, @@ -64,14 +59,16 @@ int32_t size_hint_in_dip, bool allow_placeholder_icon, apps::mojom::Publisher::LoadIconCallback callback) override; + + // TODO: Provide comments for public API methods. void Launch(const std::string& app_id, int32_t event_flags, apps::mojom::LaunchSource launch_source, - int64_t display_id) override; + int64_t display_id); void SetPermission(const std::string& app_id, - apps::mojom::PermissionPtr permission) override; - void Uninstall(const std::string& app_id) override; - void OpenNativeSettings(const std::string& app_id) override; + apps::mojom::PermissionPtr permission); + void Uninstall(const std::string& app_id); + void OpenNativeSettings(const std::string& app_id); void FlushMojoCallsForTesting(); apps::IconLoader* OverrideInnerIconLoaderForTesting( @@ -82,7 +79,7 @@ // An adapter, presenting an IconLoader interface based on the underlying // Mojo service (or on a fake implementation for testing). // - // Conceptually, the ASP (the AppServiceProxyImpl) is itself such an adapter: + // Conceptually, the ASP (the AppServiceProxy) is itself such an adapter: // UI clients call the IconLoader::LoadIconFromIconKey method (which the ASP // implements) and the ASP translates (i.e. adapts) these to Mojo calls (or // C++ calls to the Fake). This diagram shows control flow going left to @@ -112,7 +109,7 @@ // component: the one that ultimately talks to the Mojo service. // // The outer_icon_loader_ field (of type IconCache) is the "Outer" component: - // the entry point for calls into the AppServiceProxyImpl. + // the entry point for calls into the AppServiceProxy. // // Note that even if the ASP provides some icon caching, upstream UI clients // may want to introduce further icon caching. See the commentary where @@ -121,7 +118,7 @@ // IPC coalescing would be one of the "MoreDecorators". class InnerIconLoader : public apps::IconLoader { public: - explicit InnerIconLoader(AppServiceProxyImpl* host); + explicit InnerIconLoader(AppServiceProxy* host); // apps::IconLoader overrides. apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override; @@ -134,14 +131,14 @@ bool allow_placeholder_icon, apps::mojom::Publisher::LoadIconCallback callback) override; - // |host_| owns |this|, as the InnerIconLoader is an AppServiceProxyImpl + // |host_| owns |this|, as the InnerIconLoader is an AppServiceProxy // field. - AppServiceProxyImpl* host_; + AppServiceProxy* host_; apps::IconLoader* overriding_icon_loader_for_testing_; }; - AppServiceProxyImpl(Profile* profile, service_manager::Connector* connector); + AppServiceProxy(Profile* profile, service_manager::Connector* connector); // KeyedService overrides. void Shutdown() override; @@ -150,6 +147,9 @@ void OnApps(std::vector<apps::mojom::AppPtr> deltas) override; void Clone(apps::mojom::SubscriberRequest request) override; + apps::mojom::AppServicePtr app_service_; + apps::AppRegistryCache cache_; + mojo::BindingSet<apps::mojom::Subscriber> bindings_; // The LoadIconFromIconKey implementation sends a chained series of requests @@ -168,9 +168,9 @@ ExtensionApps extension_web_apps_; #endif // OS_CHROMEOS - DISALLOW_COPY_AND_ASSIGN(AppServiceProxyImpl); + DISALLOW_COPY_AND_ASSIGN(AppServiceProxy); }; } // namespace apps -#endif // CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_IMPL_H_ +#endif // CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_
diff --git a/chrome/browser/apps/app_service/app_service_proxy_factory.cc b/chrome/browser/apps/app_service/app_service_proxy_factory.cc index d744503..c576d416 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_factory.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_factory.cc
@@ -5,7 +5,7 @@ #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "base/feature_list.h" -#include "chrome/browser/apps/app_service/app_service_proxy_impl.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_features.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" @@ -27,7 +27,7 @@ // is branched from (i.e. "inherit" the parent service), // - return a temporary service just for the incognito session (probably // the least sensible option). - return static_cast<AppServiceProxyImpl*>( + return static_cast<AppServiceProxy*>( AppServiceProxyFactory::GetInstance()->GetServiceForBrowserContext( profile, true /* create */)); } @@ -59,7 +59,7 @@ KeyedService* AppServiceProxyFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - return new AppServiceProxyImpl(Profile::FromBrowserContext(context)); + return new AppServiceProxy(Profile::FromBrowserContext(context)); } bool AppServiceProxyFactory::ServiceIsCreatedWithBrowserContext() const {
diff --git a/chrome/browser/apps/app_service/app_service_proxy_impl_unittest.cc b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc similarity index 92% rename from chrome/browser/apps/app_service/app_service_proxy_impl_unittest.cc rename to chrome/browser/apps/app_service/app_service_proxy_unittest.cc index 57ab4c49..09f986c 100644 --- a/chrome/browser/apps/app_service/app_service_proxy_impl_unittest.cc +++ b/chrome/browser/apps/app_service/app_service_proxy_unittest.cc
@@ -6,12 +6,12 @@ #include <vector> #include "base/callback.h" -#include "chrome/browser/apps/app_service/app_service_proxy_impl.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/image/image_skia_rep.h" -class AppServiceProxyImplTest : public testing::Test { +class AppServiceProxyTest : public testing::Test { protected: using UniqueReleaser = std::unique_ptr<apps::IconLoader::Releaser>; @@ -66,11 +66,11 @@ return loader->LoadIcon(app_type, app_id, icon_compression, size_hint_in_dip, allow_placeholder_icon, - base::BindOnce(&AppServiceProxyImplTest::OnLoadIcon, + base::BindOnce(&AppServiceProxyTest::OnLoadIcon, base::Unretained(this))); } - void OverrideAppServiceProxyInnerIconLoader(apps::AppServiceProxyImpl* proxy, + void OverrideAppServiceProxyInnerIconLoader(apps::AppServiceProxy* proxy, apps::IconLoader* icon_loader) { proxy->OverrideInnerIconLoaderForTesting(icon_loader); } @@ -84,14 +84,14 @@ int num_outer_finished_callbacks_ = 0; }; -TEST_F(AppServiceProxyImplTest, IconCache) { +TEST_F(AppServiceProxyTest, IconCache) { // This is mostly a sanity check. For an isolated, comprehensive unit test of // the IconCache code, see icon_cache_unittest.cc. // - // This tests an AppServiceProxyImpl as a 'black box', which uses an + // This tests an AppServiceProxy as a 'black box', which uses an // IconCache but also other IconLoader filters, such as an IconCoalescer. - apps::AppServiceProxyImpl proxy(nullptr); + apps::AppServiceProxy proxy(nullptr); FakeIconLoader fake; OverrideAppServiceProxyInnerIconLoader(&proxy, &fake); @@ -130,14 +130,14 @@ EXPECT_EQ(3, NumOuterFinishedCallbacks()); } -TEST_F(AppServiceProxyImplTest, IconCoalescer) { +TEST_F(AppServiceProxyTest, IconCoalescer) { // This is mostly a sanity check. For an isolated, comprehensive unit test of // the IconCoalescer code, see icon_coalescer_unittest.cc. // - // This tests an AppServiceProxyImpl as a 'black box', which uses an + // This tests an AppServiceProxy as a 'black box', which uses an // IconCoalescer but also other IconLoader filters, such as an IconCache. - apps::AppServiceProxyImpl proxy(nullptr); + apps::AppServiceProxy proxy(nullptr); FakeIconLoader fake; OverrideAppServiceProxyInnerIconLoader(&proxy, &fake);
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc index 02f978e..90e3ac0 100644 --- a/chrome/browser/apps/app_service/arc_apps.cc +++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/callback.h" #include "base/containers/flat_map.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/arc_apps_factory.h" #include "chrome/browser/apps/app_service/dip_px_util.h" @@ -19,7 +20,6 @@ #include "chrome/browser/ui/app_list/arc/arc_app_icon_descriptor.h" #include "chrome/browser/ui/app_list/arc/arc_app_utils.h" #include "chrome/grit/component_extension_resources.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" #include "components/arc/app_permissions/arc_app_permissions_bridge.h" #include "components/arc/arc_service_manager.h" #include "components/arc/common/app.mojom.h"
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc index d2365135..f2c8bba7 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc +++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.cc
@@ -119,7 +119,9 @@ bool show_persistence_options = ShouldShowPersistenceOptions(apps); ShowIntentPickerBubbleForApps( - web_contents, std::move(apps), show_persistence_options, + web_contents, std::move(apps), + /*show_stay_in_chrome=*/show_persistence_options, + /*show_remember_selection=*/show_persistence_options, base::BindOnce(&OnIntentPickerClosed, web_contents, ui_auto_display_service, url)); } @@ -203,7 +205,8 @@ void AppsNavigationThrottle::ShowIntentPickerBubbleForApps( content::WebContents* web_contents, std::vector<IntentPickerAppInfo> apps, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse callback) { if (apps.empty()) return; @@ -214,10 +217,9 @@ Browser* browser = chrome::FindBrowserWithWebContents(web_contents); if (!browser) return; - browser->window()->ShowIntentPickerBubble(std::move(apps), - /*enable_stay_in_chrome=*/true, - show_persistence_options, - std::move(callback)); + browser->window()->ShowIntentPickerBubble( + std::move(apps), show_stay_in_chrome, show_remember_selection, + std::move(callback)); } AppsNavigationThrottle::AppsNavigationThrottle( @@ -359,6 +361,9 @@ // if only PWAs are present. // TODO(crbug.com/826982): Provide the "Remember my choice" option when the // app registry can support persistence for PWAs. + // This function is also used to hide the "Stay In Chrome" button when the + // "Remember my choice" option is hidden such that the bubble is easy to + // understand. return !ContainsOnlyPwas(apps); } @@ -390,9 +395,11 @@ break; case PickerShowState::kPopOut: { bool show_persistence_options = ShouldShowPersistenceOptions(apps); - ShowIntentPickerBubbleForApps(web_contents, std::move(apps), - show_persistence_options, - std::move(callback)); + ShowIntentPickerBubbleForApps( + web_contents, std::move(apps), + /*show_stay_in_chrome=*/show_persistence_options, + /*show_remember_selection=*/show_persistence_options, + std::move(callback)); break; } default:
diff --git a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h index 62c1576..ef14b2f7 100644 --- a/chrome/browser/apps/intent_helper/apps_navigation_throttle.h +++ b/chrome/browser/apps/intent_helper/apps_navigation_throttle.h
@@ -83,7 +83,8 @@ static void ShowIntentPickerBubbleForApps( content::WebContents* web_contents, std::vector<IntentPickerAppInfo> apps, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse callback); explicit AppsNavigationThrottle(content::NavigationHandle* navigation_handle);
diff --git a/chrome/browser/apps/launch_service/README.md b/chrome/browser/apps/launch_service/README.md index ea7bb257..7fa3261c 100644 --- a/chrome/browser/apps/launch_service/README.md +++ b/chrome/browser/apps/launch_service/README.md
@@ -5,7 +5,7 @@ and BMO-based Desktop PWAs can be launched using this service. The intent is to merge LaunchService into the AppService, -specifically AppServiceProxyImpl. +specifically AppServiceProxy. See `//chrome/services/app_service/README.md` for a description of the App Service.
diff --git a/chrome/browser/apps/user_type_filter_unittest.cc b/chrome/browser/apps/user_type_filter_unittest.cc index 5d7d0f8..652c69e 100644 --- a/chrome/browser/apps/user_type_filter_unittest.cc +++ b/chrome/browser/apps/user_type_filter_unittest.cc
@@ -74,6 +74,7 @@ DISALLOW_COPY_AND_ASSIGN(UserTypeFilterTest); }; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) TEST_F(UserTypeFilterTest, ChildUser) { const auto profile = CreateProfile(); profile->SetSupervisedUserId(supervised_users::kChildAccountSUID); @@ -82,6 +83,7 @@ EXPECT_TRUE(Match( profile, CreateJsonWithFilter({kUserTypeUnmanaged, kUserTypeChild}))); } +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) TEST_F(UserTypeFilterTest, GuestUser) { auto profile = CreateGuestProfile(); @@ -128,12 +130,16 @@ EXPECT_TRUE(MatchDefault(profile, default_filter)); // Guest user. EXPECT_TRUE(MatchDefault(CreateGuestProfile(), default_filter)); +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) // Child user. profile->SetSupervisedUserId(supervised_users::kChildAccountSUID); EXPECT_FALSE(MatchDefault(profile, default_filter)); // Supervised user. + // TODO(crbug.com/971311): Remove the next assert test once legacy supervised + // user code has been fully removed. profile->SetSupervisedUserId("asdf"); EXPECT_FALSE(MatchDefault(profile, default_filter)); +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) // Managed user. profile = CreateProfile(); profile->GetProfilePolicyConnector()->OverrideIsManagedForTesting(true);
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc index 805faf52..5f6724e5 100644 --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -425,6 +425,11 @@ content::WebContents* active_tab = nullptr; if (active_browser) active_tab = active_browser->tab_strip_model()->GetActiveWebContents(); + const AutocompleteInput empty_input; + if (!input) + input = &empty_input; + const GURL stripped_url = AutocompleteMatch::GURLToStrippedGURL( + url, *input, GetTemplateURLService(), base::string16()); for (auto* browser : *BrowserList::GetInstance()) { // Only look at same profile (and anonymity level). if (browser->profile()->IsSameProfileAndType(profile_)) { @@ -432,8 +437,8 @@ content::WebContents* web_contents = browser->tab_strip_model()->GetWebContentsAt(i); if (web_contents != active_tab && - StrippedURLsAreEqual(web_contents->GetLastCommittedURL(), url, - input)) + IsURLEqualToStrippedURL(web_contents->GetLastCommittedURL(), + stripped_url, *input)) return true; } } @@ -463,3 +468,13 @@ AutocompleteMatch::GURLToStrippedGURL( url2, *input, template_url_service, base::string16()); } + +bool ChromeAutocompleteProviderClient::IsURLEqualToStrippedURL( + const GURL& url1, + const GURL& stripped_url2, + const AutocompleteInput& input) const { + const TemplateURLService* template_url_service = GetTemplateURLService(); + return AutocompleteMatch::GURLToStrippedGURL( + url1, input, template_url_service, base::string16()) == + stripped_url2; +}
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h index 043cd0a5..69052fe 100644 --- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h +++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.h
@@ -87,6 +87,13 @@ const AutocompleteInput* input) const; private: + // Like StrippedURLsAreEqual(), but second URL is already stripped. The + // input corresponds to this second URL. This is a small optimization when + // comparing lots of URLs to a single one. + bool IsURLEqualToStrippedURL(const GURL& url1, + const GURL& stripped_url2, + const AutocompleteInput& input) const; + Profile* profile_; ChromeAutocompleteSchemeClassifier scheme_classifier_; std::unique_ptr<OmniboxPedalProvider> pedal_provider_;
diff --git a/chrome/browser/availability/OWNERS b/chrome/browser/availability/OWNERS new file mode 100644 index 0000000..fd70f95 --- /dev/null +++ b/chrome/browser/availability/OWNERS
@@ -0,0 +1,3 @@ +file://components/previews/OWNERS + +# COMPONENT: Blink>Previews
diff --git a/chrome/browser/previews/previews_prober.cc b/chrome/browser/availability/availability_prober.cc similarity index 77% rename from chrome/browser/previews/previews_prober.cc rename to chrome/browser/availability/availability_prober.cc index 8662587..c960231 100644 --- a/chrome/browser/previews/previews_prober.cc +++ b/chrome/browser/availability/availability_prober.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/previews/previews_prober.h" +#include "chrome/browser/availability/availability_prober.h" #include <math.h> #include <cmath> @@ -17,7 +17,7 @@ #include "base/time/default_clock.h" #include "base/time/default_tick_clock.h" #include "build/build_config.h" -#include "chrome/browser/previews/proto/previews_prober_cache_entry.pb.h" +#include "chrome/browser/availability/proto/availability_prober_cache_entry.pb.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" @@ -37,24 +37,24 @@ namespace { -const char kCachePrefKeyPrefix[] = "previews.prober.cache"; +const char kCachePrefKeyPrefix[] = "Availability.Prober.cache"; -const char kSuccessHistogram[] = "Previews.Prober.DidSucceed"; -const char kTimeUntilSuccess[] = "Previews.Prober.TimeUntilSuccess"; -const char kTimeUntilFailure[] = "Previews.Prober.TimeUntilFailure"; +const char kSuccessHistogram[] = "Availability.Prober.DidSucceed"; +const char kTimeUntilSuccess[] = "Availability.Prober.TimeUntilSuccess"; +const char kTimeUntilFailure[] = "Availability.Prober.TimeUntilFailure"; const char kAttemptsBeforeSuccessHistogram[] = - "Previews.Prober.NumAttemptsBeforeSuccess"; -const char kHttpRespCodeHistogram[] = "Previews.Prober.ResponseCode"; -const char kNetErrorHistogram[] = "Previews.Prober.NetError"; -const char kCacheEntryAgeHistogram[] = "Previews.Prober.CacheEntryAge"; + "Availability.Prober.NumAttemptsBeforeSuccess"; +const char kHttpRespCodeHistogram[] = "Availability.Prober.ResponseCode"; +const char kNetErrorHistogram[] = "Availability.Prober.NetError"; +const char kCacheEntryAgeHistogram[] = "Availability.Prober.CacheEntryAge"; // Please keep this up to date with logged histogram suffix -// |Previews.Prober.Clients| in tools/metrics/histograms/histograms.xml. +// |Availability.Prober.Clients| in tools/metrics/histograms/histograms.xml. // These names are also used in prefs so they should not be changed without // consideration for removing the old value. -std::string NameForClient(PreviewsProber::ClientName name) { +std::string NameForClient(AvailabilityProber::ClientName name) { switch (name) { - case PreviewsProber::ClientName::kLitepages: + case AvailabilityProber::ClientName::kLitepages: return "Litepages"; } NOTREACHED(); @@ -65,24 +65,25 @@ return base::StringPrintf("%s.%s", kCachePrefKeyPrefix, name.c_str()); } -std::string HttpMethodToString(PreviewsProber::HttpMethod http_method) { +std::string HttpMethodToString(AvailabilityProber::HttpMethod http_method) { switch (http_method) { - case PreviewsProber::HttpMethod::kGet: + case AvailabilityProber::HttpMethod::kGet: return "GET"; - case PreviewsProber::HttpMethod::kHead: + case AvailabilityProber::HttpMethod::kHead: return "HEAD"; } } // Computes the time delta for a given Backoff algorithm, a base interval, and // the count of how many attempts have been made thus far. -base::TimeDelta ComputeNextTimeDeltaForBackoff(PreviewsProber::Backoff backoff, - base::TimeDelta base_interval, - size_t attempts_so_far) { +base::TimeDelta ComputeNextTimeDeltaForBackoff( + AvailabilityProber::Backoff backoff, + base::TimeDelta base_interval, + size_t attempts_so_far) { switch (backoff) { - case PreviewsProber::Backoff::kLinear: + case AvailabilityProber::Backoff::kLinear: return base_interval; - case PreviewsProber::Backoff::kExponential: + case AvailabilityProber::Backoff::kExponential: return base_interval * pow(2, attempts_so_far); } } @@ -122,7 +123,7 @@ } base::Optional<base::Value> EncodeCacheEntryValue( - const PreviewsProberCacheEntry& entry) { + const AvailabilityProberCacheEntry& entry) { std::string serialized_entry; bool serialize_to_string_ok = entry.SerializeToString(&serialized_entry); if (!serialize_to_string_ok) @@ -133,7 +134,7 @@ return base::Value(base64_encoded); } -base::Optional<PreviewsProberCacheEntry> DecodeCacheEntryValue( +base::Optional<AvailabilityProberCacheEntry> DecodeCacheEntryValue( const base::Value& value) { if (!value.is_string()) return base::nullopt; @@ -142,7 +143,7 @@ if (!base::Base64Decode(value.GetString(), &base64_decoded)) return base::nullopt; - PreviewsProberCacheEntry entry; + AvailabilityProberCacheEntry entry; if (!entry.ParseFromString(base64_decoded)) return base::nullopt; @@ -150,7 +151,7 @@ } base::Time LastModifiedTimeFromCacheEntry( - const PreviewsProberCacheEntry& entry) { + const AvailabilityProberCacheEntry& entry) { return base::Time::FromDeltaSinceWindowsEpoch( base::TimeDelta::FromMicroseconds(entry.last_modified())); } @@ -161,7 +162,7 @@ std::string oldest_key; base::Time oldest_mod_time = base::Time::Max(); for (const auto& iter : dict->DictItems()) { - base::Optional<PreviewsProberCacheEntry> entry = + base::Optional<AvailabilityProberCacheEntry> entry = DecodeCacheEntryValue(iter.second); if (!entry.has_value()) { // Also remove anything that can't be decoded. @@ -201,16 +202,16 @@ } // namespace -PreviewsProber::RetryPolicy::RetryPolicy() = default; -PreviewsProber::RetryPolicy::~RetryPolicy() = default; -PreviewsProber::RetryPolicy::RetryPolicy(PreviewsProber::RetryPolicy const&) = - default; -PreviewsProber::TimeoutPolicy::TimeoutPolicy() = default; -PreviewsProber::TimeoutPolicy::~TimeoutPolicy() = default; -PreviewsProber::TimeoutPolicy::TimeoutPolicy( - PreviewsProber::TimeoutPolicy const&) = default; +AvailabilityProber::RetryPolicy::RetryPolicy() = default; +AvailabilityProber::RetryPolicy::~RetryPolicy() = default; +AvailabilityProber::RetryPolicy::RetryPolicy( + AvailabilityProber::RetryPolicy const&) = default; +AvailabilityProber::TimeoutPolicy::TimeoutPolicy() = default; +AvailabilityProber::TimeoutPolicy::~TimeoutPolicy() = default; +AvailabilityProber::TimeoutPolicy::TimeoutPolicy( + AvailabilityProber::TimeoutPolicy const&) = default; -PreviewsProber::PreviewsProber( +AvailabilityProber::AvailabilityProber( Delegate* delegate, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, PrefService* pref_service, @@ -223,22 +224,22 @@ const net::NetworkTrafficAnnotationTag& traffic_annotation, const size_t max_cache_entries, base::TimeDelta revalidate_cache_after) - : PreviewsProber(delegate, - url_loader_factory, - pref_service, - name, - url, - http_method, - headers, - retry_policy, - timeout_policy, - traffic_annotation, - max_cache_entries, - revalidate_cache_after, - base::DefaultTickClock::GetInstance(), - base::DefaultClock::GetInstance()) {} + : AvailabilityProber(delegate, + url_loader_factory, + pref_service, + name, + url, + http_method, + headers, + retry_policy, + timeout_policy, + traffic_annotation, + max_cache_entries, + revalidate_cache_after, + base::DefaultTickClock::GetInstance(), + base::DefaultClock::GetInstance()) {} -PreviewsProber::PreviewsProber( +AvailabilityProber::AvailabilityProber( Delegate* delegate, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, PrefService* pref_service, @@ -283,36 +284,36 @@ AddSelfAsNetworkConnectionObserver(content::GetNetworkConnectionTracker()); } else { content::GetNetworkConnectionTrackerFromUIThread( - base::BindOnce(&PreviewsProber::AddSelfAsNetworkConnectionObserver, + base::BindOnce(&AvailabilityProber::AddSelfAsNetworkConnectionObserver, weak_factory_.GetWeakPtr())); } cached_probe_results_ = pref_service_->GetDictionary(pref_key_)->CreateDeepCopy(); } -PreviewsProber::~PreviewsProber() { +AvailabilityProber::~AvailabilityProber() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (network_connection_tracker_) network_connection_tracker_->RemoveNetworkConnectionObserver(this); } // static -void PreviewsProber::RegisterProfilePrefs(PrefRegistrySimple* registry) { - for (int i = 0; i <= static_cast<int>(PreviewsProber::ClientName::kMaxValue); - i++) { +void AvailabilityProber::RegisterProfilePrefs(PrefRegistrySimple* registry) { + for (int i = 0; + i <= static_cast<int>(AvailabilityProber::ClientName::kMaxValue); i++) { registry->RegisterDictionaryPref(PrefKeyForName( - NameForClient(static_cast<PreviewsProber::ClientName>(i)))); + NameForClient(static_cast<AvailabilityProber::ClientName>(i)))); } } -void PreviewsProber::AddSelfAsNetworkConnectionObserver( +void AvailabilityProber::AddSelfAsNetworkConnectionObserver( network::NetworkConnectionTracker* network_connection_tracker) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); network_connection_tracker_ = network_connection_tracker; network_connection_tracker_->AddNetworkConnectionObserver(this); } -void PreviewsProber::ResetState() { +void AvailabilityProber::ResetState() { time_when_set_active_ = base::nullopt; successive_retry_count_ = 0; successive_timeout_count_ = 0; @@ -324,7 +325,7 @@ #endif } -void PreviewsProber::SendNowIfInactive(bool send_only_in_foreground) { +void AvailabilityProber::SendNowIfInactive(bool send_only_in_foreground) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (time_when_set_active_.has_value()) @@ -336,8 +337,9 @@ // base::Unretained is safe here because the callback is owned by // |application_status_listener_| which is owned by |this|. application_status_listener_ = - base::android::ApplicationStatusListener::New(base::BindRepeating( - &PreviewsProber::OnApplicationStateChange, base::Unretained(this))); + base::android::ApplicationStatusListener::New( + base::BindRepeating(&AvailabilityProber::OnApplicationStateChange, + base::Unretained(this))); return; } #endif @@ -346,7 +348,7 @@ } #if defined(OS_ANDROID) -void PreviewsProber::OnApplicationStateChange( +void AvailabilityProber::OnApplicationStateChange( base::android::ApplicationState new_state) { DCHECK(application_status_listener_); @@ -358,7 +360,8 @@ } #endif -void PreviewsProber::OnConnectionChanged(network::mojom::ConnectionType type) { +void AvailabilityProber::OnConnectionChanged( + network::mojom::ConnectionType type) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // If a probe is already in flight we don't want to continue to use it since @@ -367,7 +370,7 @@ CreateAndStartURLLoader(); } -void PreviewsProber::CreateAndStartURLLoader() { +void AvailabilityProber::CreateAndStartURLLoader() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!time_when_set_active_.has_value() || successive_retry_count_ > 0); DCHECK(!retry_timer_ || !retry_timer_->IsRunning()); @@ -401,23 +404,23 @@ url_loader_->DownloadToString( url_loader_factory_.get(), - base::BindOnce(&PreviewsProber::OnURLLoadComplete, + base::BindOnce(&AvailabilityProber::OnURLLoadComplete, base::Unretained(this)), 1024); // We don't use SimpleURLLoader's timeout functionality because it is not - // possible to test by PreviewsProberTest. + // possible to test by AvailabilityProberTest. base::TimeDelta ttl = ComputeNextTimeDeltaForBackoff( timeout_policy_.backoff, timeout_policy_.base_timeout, successive_timeout_count_); timeout_timer_ = std::make_unique<base::OneShotTimer>(tick_clock_); // base::Unretained is safe because |timeout_timer_| is owned by this. timeout_timer_->Start(FROM_HERE, ttl, - base::BindOnce(&PreviewsProber::ProcessProbeTimeout, + base::BindOnce(&AvailabilityProber::ProcessProbeTimeout, base::Unretained(this))); } -void PreviewsProber::OnURLLoadComplete( +void AvailabilityProber::OnURLLoadComplete( std::unique_ptr<std::string> response_body) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -434,7 +437,7 @@ bool was_successful = delegate_->IsResponseSuccess( static_cast<net::Error>(url_loader_->NetError()), - *url_loader_->ResponseInfo(), std::move(response_body)); + url_loader_->ResponseInfo(), std::move(response_body)); timeout_timer_.reset(); url_loader_.reset(); @@ -447,7 +450,7 @@ ProcessProbeFailure(); } -void PreviewsProber::ProcessProbeTimeout() { +void AvailabilityProber::ProcessProbeTimeout() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(url_loader_); @@ -461,7 +464,7 @@ ProcessProbeFailure(); } -void PreviewsProber::ProcessProbeFailure() { +void AvailabilityProber::ProcessProbeFailure() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!retry_timer_ || !retry_timer_->IsRunning()); DCHECK(!timeout_timer_ || !timeout_timer_->IsRunning()); @@ -488,9 +491,10 @@ retry_timer_ = std::make_unique<base::OneShotTimer>(tick_clock_); // base::Unretained is safe because |retry_timer_| is owned by this. - retry_timer_->Start(FROM_HERE, interval, - base::BindOnce(&PreviewsProber::CreateAndStartURLLoader, - base::Unretained(this))); + retry_timer_->Start( + FROM_HERE, interval, + base::BindOnce(&AvailabilityProber::CreateAndStartURLLoader, + base::Unretained(this))); successive_retry_count_++; return; @@ -499,7 +503,7 @@ ResetState(); } -void PreviewsProber::ProcessProbeSuccess() { +void AvailabilityProber::ProcessProbeSuccess() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!retry_timer_ || !retry_timer_->IsRunning()); DCHECK(!timeout_timer_ || !timeout_timer_->IsRunning()); @@ -529,7 +533,7 @@ ResetState(); } -base::Optional<bool> PreviewsProber::LastProbeWasSuccessful() { +base::Optional<bool> AvailabilityProber::LastProbeWasSuccessful() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::Value* cache_entry = @@ -537,7 +541,7 @@ if (!cache_entry) return base::nullopt; - base::Optional<PreviewsProberCacheEntry> entry = + base::Optional<AvailabilityProberCacheEntry> entry = DecodeCacheEntryValue(*cache_entry); if (!entry.has_value()) return base::nullopt; @@ -562,13 +566,13 @@ return entry.value().is_success(); } -void PreviewsProber::SetOnCompleteCallback( - PreviewsProberOnCompleteCallback callback) { +void AvailabilityProber::SetOnCompleteCallback( + AvailabilityProberOnCompleteCallback callback) { on_complete_callback_ = std::move(callback); } -void PreviewsProber::RecordProbeResult(bool success) { - PreviewsProberCacheEntry entry; +void AvailabilityProber::RecordProbeResult(bool success) { + AvailabilityProberCacheEntry entry; entry.set_is_success(success); entry.set_last_modified( clock_->Now().ToDeltaSinceWindowsEpoch().InMicroseconds()); @@ -596,14 +600,14 @@ ->Add(success); } -std::string PreviewsProber::GetCacheKeyForCurrentNetwork() const { +std::string AvailabilityProber::GetCacheKeyForCurrentNetwork() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return base::StringPrintf( "%s;%s:%d", GenerateNetworkID(network_connection_tracker_).c_str(), url_.host().c_str(), url_.EffectiveIntPort()); } -std::string PreviewsProber::AppendNameToHistogram( +std::string AvailabilityProber::AppendNameToHistogram( const std::string& histogram) const { return base::StringPrintf("%s.%s", histogram.c_str(), name_.c_str()); }
diff --git a/chrome/browser/previews/previews_prober.h b/chrome/browser/availability/availability_prober.h similarity index 93% rename from chrome/browser/previews/previews_prober.h rename to chrome/browser/availability/availability_prober.h index c118278..43706f06 100644 --- a/chrome/browser/previews/previews_prober.h +++ b/chrome/browser/availability/availability_prober.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_PREVIEWS_PREVIEWS_PROBER_H_ -#define CHROME_BROWSER_PREVIEWS_PREVIEWS_PROBER_H_ +#ifndef CHROME_BROWSER_AVAILABILITY_AVAILABILITY_PROBER_H_ +#define CHROME_BROWSER_AVAILABILITY_AVAILABILITY_PROBER_H_ #include <stdint.h> #include <memory> @@ -41,14 +41,15 @@ class SharedURLLoaderFactory; } // namespace network -typedef base::RepeatingCallback<void(bool)> PreviewsProberOnCompleteCallback; +typedef base::RepeatingCallback<void(bool)> + AvailabilityProberOnCompleteCallback; // This class is a utility to probe a given URL with a given set of behaviors. // This can be used for determining whether a specific network resource is // available or accessible by Chrome. // This class may live on either UI or IO thread but should remain on the thread // that it was created on. -class PreviewsProber +class AvailabilityProber : public network::NetworkConnectionTracker::NetworkConnectionObserver { public: class Delegate { @@ -63,7 +64,7 @@ // delegate returns true, no more probes would be attempted until there is a // change in the network or |SendNowIfInactive| is called. virtual bool IsResponseSuccess(net::Error net_error, - const network::ResourceResponseHead& head, + const network::ResourceResponseHead* head, std::unique_ptr<std::string> body) = 0; }; @@ -131,7 +132,7 @@ kHead, }; - PreviewsProber( + AvailabilityProber( Delegate* delegate, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, PrefService* pref_service, @@ -144,7 +145,7 @@ const net::NetworkTrafficAnnotationTag& traffic_annotation, const size_t max_cache_entries, base::TimeDelta revalidate_cache_after); - ~PreviewsProber() override; + ~AvailabilityProber() override; // Registers the prefs used in this class. static void RegisterProfilePrefs(PrefRegistrySimple* registry); @@ -168,11 +169,11 @@ // Sets a repeating callback to notify the completion of a probe and whether // it was successful. - void SetOnCompleteCallback(PreviewsProberOnCompleteCallback callback); + void SetOnCompleteCallback(AvailabilityProberOnCompleteCallback callback); protected: // Exposes |tick_clock| and |clock| for testing. - PreviewsProber( + AvailabilityProber( Delegate* delegate, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, PrefService* pref_service, @@ -290,13 +291,13 @@ // An optional callback to notify of a completed probe. This callback passes a // bool to indicate success of the completed probe. - PreviewsProberOnCompleteCallback on_complete_callback_; + AvailabilityProberOnCompleteCallback on_complete_callback_; SEQUENCE_CHECKER(sequence_checker_); - base::WeakPtrFactory<PreviewsProber> weak_factory_{this}; + base::WeakPtrFactory<AvailabilityProber> weak_factory_{this}; - DISALLOW_COPY_AND_ASSIGN(PreviewsProber); + DISALLOW_COPY_AND_ASSIGN(AvailabilityProber); }; -#endif // CHROME_BROWSER_PREVIEWS_PREVIEWS_PROBER_H_ +#endif // CHROME_BROWSER_AVAILABILITY_AVAILABILITY_PROBER_H_
diff --git a/chrome/browser/availability/availability_prober_browsertest.cc b/chrome/browser/availability/availability_prober_browsertest.cc new file mode 100644 index 0000000..57e35db --- /dev/null +++ b/chrome/browser/availability/availability_prober_browsertest.cc
@@ -0,0 +1,205 @@ +// 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. + +#include <string> + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/run_loop.h" +#include "build/build_config.h" +#include "chrome/browser/availability/availability_prober.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "content/public/browser/network_service_instance.h" +#include "content/public/browser/system_connector.h" +#include "content/public/common/network_service_util.h" +#include "content/public/common/service_names.mojom.h" +#include "content/public/test/network_connection_change_simulator.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "services/network/public/mojom/network_service_test.mojom.h" +#include "services/service_manager/public/cpp/connector.h" + +namespace { + +void WaitForCompletedProbe(AvailabilityProber* prober) { + while (true) { + if (prober->LastProbeWasSuccessful().has_value()) + return; + base::RunLoop().RunUntilIdle(); + } +} + +} // namespace + +class TestDelegate : public AvailabilityProber::Delegate { + public: + TestDelegate() = default; + ~TestDelegate() = default; + + bool ShouldSendNextProbe() override { return should_send_next_probe_; } + + bool IsResponseSuccess(net::Error net_error, + const network::ResourceResponseHead* head, + std::unique_ptr<std::string> body) override { + got_head_ = head; + return net_error == net::OK && head && + head->headers->response_code() == net::HTTP_OK; + } + + void set_should_send_next_probe(bool should_send_next_probe) { + should_send_next_probe_ = should_send_next_probe; + } + + bool got_head() const { return got_head_; } + + private: + bool should_send_next_probe_ = true; + bool got_head_ = false; +}; + +class AvailabilityProberBrowserTest : public InProcessBrowserTest { + public: + AvailabilityProberBrowserTest() = default; + ~AvailabilityProberBrowserTest() override = default; + + void SetUpOnMainThread() override { + https_server_.reset( + new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS)); + https_server_->RegisterRequestHandler(base::BindRepeating( + &AvailabilityProberBrowserTest::HandleRequest, base::Unretained(this))); + ASSERT_TRUE(https_server_->Start()); + } + + void SetUpCommandLine(base::CommandLine* cmd) override { + cmd->AppendSwitchASCII("host-rules", "MAP test.com 127.0.0.1"); + } + + void TearDownOnMainThread() override { + EXPECT_TRUE(https_server_->ShutdownAndWaitUntilComplete()); + InProcessBrowserTest::TearDownOnMainThread(); + } + + GURL TestURLWithPath(const std::string& path) const { + return https_server_->GetURL("test.com", path); + } + + private: + std::unique_ptr<net::test_server::HttpResponse> HandleRequest( + const net::test_server::HttpRequest& request) { + std::string path = request.GetURL().path(); + if (path == "/ok") { + std::unique_ptr<net::test_server::BasicHttpResponse> response = + std::make_unique<net::test_server::BasicHttpResponse>(); + response->set_code(net::HTTP_OK); + return response; + } + + if (path == "/timeout") { + std::unique_ptr<net::test_server::HungResponse> response = + std::make_unique<net::test_server::HungResponse>(); + return response; + } + + NOTREACHED() << path << " is not handled"; + return nullptr; + } + + std::unique_ptr<net::EmbeddedTestServer> https_server_; + + DISALLOW_COPY_AND_ASSIGN(AvailabilityProberBrowserTest); +}; + +IN_PROC_BROWSER_TEST_F(AvailabilityProberBrowserTest, OK) { + GURL url = TestURLWithPath("/ok"); + TestDelegate delegate; + net::HttpRequestHeaders headers; + AvailabilityProber::RetryPolicy retry_policy; + AvailabilityProber::TimeoutPolicy timeout_policy; + + AvailabilityProber prober( + &delegate, browser()->profile()->GetURLLoaderFactory(), + browser()->profile()->GetPrefs(), + AvailabilityProber::ClientName::kLitepages, url, + AvailabilityProber::HttpMethod::kGet, headers, retry_policy, + timeout_policy, TRAFFIC_ANNOTATION_FOR_TESTS, 1, + base::TimeDelta::FromDays(1)); + prober.SendNowIfInactive(false); + WaitForCompletedProbe(&prober); + + EXPECT_TRUE(prober.LastProbeWasSuccessful().value()); +} + +IN_PROC_BROWSER_TEST_F(AvailabilityProberBrowserTest, Timeout) { + GURL url = TestURLWithPath("/timeout"); + TestDelegate delegate; + net::HttpRequestHeaders headers; + + AvailabilityProber::RetryPolicy retry_policy; + retry_policy.max_retries = 0; + + AvailabilityProber::TimeoutPolicy timeout_policy; + timeout_policy.base_timeout = base::TimeDelta::FromMilliseconds(1); + + AvailabilityProber prober( + &delegate, browser()->profile()->GetURLLoaderFactory(), + browser()->profile()->GetPrefs(), + AvailabilityProber::ClientName::kLitepages, url, + AvailabilityProber::HttpMethod::kGet, headers, retry_policy, + timeout_policy, TRAFFIC_ANNOTATION_FOR_TESTS, 1, + base::TimeDelta::FromDays(1)); + prober.SendNowIfInactive(false); + WaitForCompletedProbe(&prober); + + EXPECT_FALSE(prober.LastProbeWasSuccessful().value()); +} + +IN_PROC_BROWSER_TEST_F(AvailabilityProberBrowserTest, NetworkChange) { + content::NetworkConnectionChangeSimulator().SetConnectionType( + network::mojom::ConnectionType::CONNECTION_2G); + + GURL url = TestURLWithPath("/ok"); + TestDelegate delegate; + net::HttpRequestHeaders headers; + AvailabilityProber::RetryPolicy retry_policy; + AvailabilityProber::TimeoutPolicy timeout_policy; + + AvailabilityProber prober( + &delegate, browser()->profile()->GetURLLoaderFactory(), + browser()->profile()->GetPrefs(), + AvailabilityProber::ClientName::kLitepages, url, + AvailabilityProber::HttpMethod::kGet, headers, retry_policy, + timeout_policy, TRAFFIC_ANNOTATION_FOR_TESTS, 1, + base::TimeDelta::FromDays(1)); + + content::NetworkConnectionChangeSimulator().SetConnectionType( + network::mojom::ConnectionType::CONNECTION_4G); + WaitForCompletedProbe(&prober); + + EXPECT_TRUE(prober.LastProbeWasSuccessful().value()); +} + +IN_PROC_BROWSER_TEST_F(AvailabilityProberBrowserTest, BadServer) { + GURL url("https://invalid.com"); + TestDelegate delegate; + net::HttpRequestHeaders headers; + AvailabilityProber::RetryPolicy retry_policy; + AvailabilityProber::TimeoutPolicy timeout_policy; + + AvailabilityProber prober( + &delegate, browser()->profile()->GetURLLoaderFactory(), + browser()->profile()->GetPrefs(), + AvailabilityProber::ClientName::kLitepages, url, + AvailabilityProber::HttpMethod::kGet, headers, retry_policy, + timeout_policy, TRAFFIC_ANNOTATION_FOR_TESTS, 1, + base::TimeDelta::FromDays(1)); + prober.SendNowIfInactive(false); + WaitForCompletedProbe(&prober); + + EXPECT_FALSE(delegate.got_head()); + EXPECT_FALSE(prober.LastProbeWasSuccessful().value()); +}
diff --git a/chrome/browser/previews/previews_prober_unittest.cc b/chrome/browser/availability/availability_prober_unittest.cc similarity index 67% rename from chrome/browser/previews/previews_prober_unittest.cc rename to chrome/browser/availability/availability_prober_unittest.cc index 3b0653e..45229d69 100644 --- a/chrome/browser/previews/previews_prober_unittest.cc +++ b/chrome/browser/availability/availability_prober_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/previews/previews_prober.h" +#include "chrome/browser/availability/availability_prober.h" #include <cmath> @@ -30,7 +30,7 @@ const base::TimeDelta kCacheRevalidateAfter(base::TimeDelta::FromDays(1)); } // namespace -class TestDelegate : public PreviewsProber::Delegate { +class TestDelegate : public AvailabilityProber::Delegate { public: TestDelegate() = default; ~TestDelegate() = default; @@ -38,10 +38,10 @@ bool ShouldSendNextProbe() override { return should_send_next_probe_; } bool IsResponseSuccess(net::Error net_error, - const network::ResourceResponseHead& head, + const network::ResourceResponseHead* head, std::unique_ptr<std::string> body) override { - return net_error == net::OK && - head.headers->response_code() == net::HTTP_OK; + return net_error == net::OK && head && + head->headers->response_code() == net::HTTP_OK; } void set_should_send_next_probe(bool should_send_next_probe) { @@ -52,13 +52,13 @@ bool should_send_next_probe_ = true; }; -class TestPreviewsProber : public PreviewsProber { +class TestAvailabilityProber : public AvailabilityProber { public: - TestPreviewsProber( - PreviewsProber::Delegate* delegate, + TestAvailabilityProber( + AvailabilityProber::Delegate* delegate, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, PrefService* pref_service, - const PreviewsProber::ClientName name, + const AvailabilityProber::ClientName name, const GURL& url, const HttpMethod http_method, const net::HttpRequestHeaders headers, @@ -69,25 +69,25 @@ base::TimeDelta revalidate_cache_after, const base::TickClock* tick_clock, const base::Clock* clock) - : PreviewsProber(delegate, - url_loader_factory, - pref_service, - name, - url, - http_method, - headers, - retry_policy, - timeout_policy, - traffic_annotation, - max_cache_entries, - revalidate_cache_after, - tick_clock, - clock) {} + : AvailabilityProber(delegate, + url_loader_factory, + pref_service, + name, + url, + http_method, + headers, + retry_policy, + timeout_policy, + traffic_annotation, + max_cache_entries, + revalidate_cache_after, + tick_clock, + clock) {} }; -class PreviewsProberTest : public testing::Test { +class AvailabilityProberTest : public testing::Test { public: - PreviewsProberTest() + AvailabilityProberTest() : thread_bundle_( base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME), test_shared_loader_factory_( @@ -97,42 +97,43 @@ test_prefs_() {} void SetUp() override { - PreviewsProber::RegisterProfilePrefs(test_prefs_.registry()); + AvailabilityProber::RegisterProfilePrefs(test_prefs_.registry()); } - std::unique_ptr<PreviewsProber> NewProber() { - return NewProberWithPolicies(PreviewsProber::RetryPolicy(), - PreviewsProber::TimeoutPolicy()); + std::unique_ptr<AvailabilityProber> NewProber() { + return NewProberWithPolicies(AvailabilityProber::RetryPolicy(), + AvailabilityProber::TimeoutPolicy()); } - std::unique_ptr<PreviewsProber> NewProberWithRetryPolicy( - const PreviewsProber::RetryPolicy& retry_policy) { - return NewProberWithPolicies(retry_policy, PreviewsProber::TimeoutPolicy()); + std::unique_ptr<AvailabilityProber> NewProberWithRetryPolicy( + const AvailabilityProber::RetryPolicy& retry_policy) { + return NewProberWithPolicies(retry_policy, + AvailabilityProber::TimeoutPolicy()); } - std::unique_ptr<PreviewsProber> NewProberWithPolicies( - const PreviewsProber::RetryPolicy& retry_policy, - const PreviewsProber::TimeoutPolicy& timeout_policy) { + std::unique_ptr<AvailabilityProber> NewProberWithPolicies( + const AvailabilityProber::RetryPolicy& retry_policy, + const AvailabilityProber::TimeoutPolicy& timeout_policy) { return NewProberWithPoliciesAndDelegate(&test_delegate_, retry_policy, timeout_policy); } - std::unique_ptr<PreviewsProber> NewProberWithPoliciesAndDelegate( - PreviewsProber::Delegate* delegate, - const PreviewsProber::RetryPolicy& retry_policy, - const PreviewsProber::TimeoutPolicy& timeout_policy) { + std::unique_ptr<AvailabilityProber> NewProberWithPoliciesAndDelegate( + AvailabilityProber::Delegate* delegate, + const AvailabilityProber::RetryPolicy& retry_policy, + const AvailabilityProber::TimeoutPolicy& timeout_policy) { net::HttpRequestHeaders headers; headers.SetHeader("X-Testing", "Hello world"); - std::unique_ptr<TestPreviewsProber> prober = - std::make_unique<TestPreviewsProber>( + std::unique_ptr<TestAvailabilityProber> prober = + std::make_unique<TestAvailabilityProber>( delegate, test_shared_loader_factory_, &test_prefs_, - PreviewsProber::ClientName::kLitepages, kTestUrl, - PreviewsProber::HttpMethod::kGet, headers, retry_policy, + AvailabilityProber::ClientName::kLitepages, kTestUrl, + AvailabilityProber::HttpMethod::kGet, headers, retry_policy, timeout_policy, TRAFFIC_ANNOTATION_FOR_TESTS, 1, kCacheRevalidateAfter, thread_bundle_.GetMockTickClock(), thread_bundle_.GetMockClock()); prober->SetOnCompleteCallback(base::BindRepeating( - &PreviewsProberTest::OnProbeComplete, base::Unretained(this))); + &AvailabilityProberTest::OnProbeComplete, base::Unretained(this))); return prober; } @@ -205,9 +206,9 @@ base::Optional<bool> callback_result_; }; -TEST_F(PreviewsProberTest, OK) { +TEST_F(AvailabilityProberTest, OK) { base::HistogramTester histogram_tester; - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -217,19 +218,19 @@ EXPECT_TRUE(prober->LastProbeWasSuccessful().value()); EXPECT_FALSE(prober->is_active()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - true, 1); histogram_tester.ExpectUniqueSample( - "Previews.Prober.NumAttemptsBeforeSuccess.Litepages", 1, 1); - histogram_tester.ExpectUniqueSample("Previews.Prober.ResponseCode.Litepages", - net::HTTP_OK, 1); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + "Availability.Prober.DidSucceed.Litepages", true, 1); + histogram_tester.ExpectUniqueSample( + "Availability.Prober.NumAttemptsBeforeSuccess.Litepages", 1, 1); + histogram_tester.ExpectUniqueSample( + "Availability.Prober.ResponseCode.Litepages", net::HTTP_OK, 1); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::OK), 1); } -TEST_F(PreviewsProberTest, OK_Callback) { +TEST_F(AvailabilityProberTest, OK_Callback) { base::HistogramTester histogram_tester; - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -242,16 +243,16 @@ EXPECT_TRUE(callback_result().has_value()); EXPECT_TRUE(callback_result().value()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - true, 1); - histogram_tester.ExpectUniqueSample("Previews.Prober.ResponseCode.Litepages", - net::HTTP_OK, 1); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectUniqueSample( + "Availability.Prober.DidSucceed.Litepages", true, 1); + histogram_tester.ExpectUniqueSample( + "Availability.Prober.ResponseCode.Litepages", net::HTTP_OK, 1); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::OK), 1); } -TEST_F(PreviewsProberTest, MultipleStart) { - std::unique_ptr<PreviewsProber> prober = NewProber(); +TEST_F(AvailabilityProberTest, MultipleStart) { + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); // Calling |SendNowIfInactive| many times should result in only one url @@ -262,8 +263,8 @@ VerifyRequest(); } -TEST_F(PreviewsProberTest, NetworkChangeStartsProber) { - std::unique_ptr<PreviewsProber> prober = NewProber(); +TEST_F(AvailabilityProberTest, NetworkChangeStartsProber) { + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); EXPECT_FALSE(prober->is_active()); @@ -274,12 +275,12 @@ EXPECT_TRUE(prober->is_active()); } -TEST_F(PreviewsProberTest, NetworkConnectionShardsCache) { +TEST_F(AvailabilityProberTest, NetworkConnectionShardsCache) { network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( network::mojom::ConnectionType::CONNECTION_3G); RunUntilIdle(); - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -306,12 +307,12 @@ EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); } -TEST_F(PreviewsProberTest, CacheMaxSize) { +TEST_F(AvailabilityProberTest, CacheMaxSize) { network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType( network::mojom::ConnectionType::CONNECTION_3G); RunUntilIdle(); - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -346,8 +347,8 @@ EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); } -TEST_F(PreviewsProberTest, CacheAutoRevalidation) { - std::unique_ptr<PreviewsProber> prober = NewProber(); +TEST_F(AvailabilityProberTest, CacheAutoRevalidation) { + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -368,9 +369,9 @@ EXPECT_TRUE(prober->is_active()); } -TEST_F(PreviewsProberTest, PersistentCache) { +TEST_F(AvailabilityProberTest, PersistentCache) { base::HistogramTester histogram_tester; - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -391,17 +392,17 @@ EXPECT_TRUE(prober->LastProbeWasSuccessful().value()); EXPECT_TRUE(prober->is_active()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - true, 1); - histogram_tester.ExpectUniqueSample("Previews.Prober.ResponseCode.Litepages", - net::HTTP_OK, 1); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectUniqueSample( + "Availability.Prober.DidSucceed.Litepages", true, 1); + histogram_tester.ExpectUniqueSample( + "Availability.Prober.ResponseCode.Litepages", net::HTTP_OK, 1); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::OK), 1); } #if defined(OS_ANDROID) -TEST_F(PreviewsProberTest, StartInForeground) { - std::unique_ptr<PreviewsProber> prober = NewProber(); +TEST_F(AvailabilityProberTest, StartInForeground) { + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); EXPECT_FALSE(prober->is_active()); @@ -409,8 +410,8 @@ EXPECT_TRUE(prober->is_active()); } -TEST_F(PreviewsProberTest, DoesntCallSendInForegroundIfInactive) { - std::unique_ptr<PreviewsProber> prober = NewProber(); +TEST_F(AvailabilityProberTest, DoesntCallSendInForegroundIfInactive) { + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); EXPECT_FALSE(prober->is_active()); @@ -420,9 +421,9 @@ } #endif -TEST_F(PreviewsProberTest, NetError) { +TEST_F(AvailabilityProberTest, NetError) { base::HistogramTester histogram_tester; - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -432,17 +433,17 @@ EXPECT_FALSE(prober->LastProbeWasSuccessful().value()); EXPECT_FALSE(prober->is_active()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - false, 4); - histogram_tester.ExpectTotalCount("Previews.Prober.ResponseCode.Litepages", - 0); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectUniqueSample( + "Availability.Prober.DidSucceed.Litepages", false, 4); + histogram_tester.ExpectTotalCount( + "Availability.Prober.ResponseCode.Litepages", 0); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::ERR_FAILED), 4); } -TEST_F(PreviewsProberTest, NetError_Callback) { +TEST_F(AvailabilityProberTest, NetError_Callback) { base::HistogramTester histogram_tester; - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -455,17 +456,17 @@ EXPECT_TRUE(callback_result().has_value()); EXPECT_FALSE(callback_result().value()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - false, 4); - histogram_tester.ExpectTotalCount("Previews.Prober.ResponseCode.Litepages", - 0); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectUniqueSample( + "Availability.Prober.DidSucceed.Litepages", false, 4); + histogram_tester.ExpectTotalCount( + "Availability.Prober.ResponseCode.Litepages", 0); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::ERR_FAILED), 4); } -TEST_F(PreviewsProberTest, HttpError) { +TEST_F(AvailabilityProberTest, HttpError) { base::HistogramTester histogram_tester; - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -475,17 +476,17 @@ EXPECT_FALSE(prober->LastProbeWasSuccessful().value()); EXPECT_FALSE(prober->is_active()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - false, 4); - histogram_tester.ExpectUniqueSample("Previews.Prober.ResponseCode.Litepages", - net::HTTP_NOT_FOUND, 4); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectUniqueSample( + "Availability.Prober.DidSucceed.Litepages", false, 4); + histogram_tester.ExpectUniqueSample( + "Availability.Prober.ResponseCode.Litepages", net::HTTP_NOT_FOUND, 4); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::OK), 4); } -TEST_F(PreviewsProberTest, TimeUntilSuccess) { +TEST_F(AvailabilityProberTest, TimeUntilSuccess) { base::HistogramTester histogram_tester; - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -498,18 +499,18 @@ EXPECT_FALSE(prober->is_active()); histogram_tester.ExpectTotalCount( - "Previews.Prober.TimeUntilFailure.Litepages", 0); + "Availability.Prober.TimeUntilFailure.Litepages", 0); histogram_tester.ExpectUniqueSample( - "Previews.Prober.TimeUntilSuccess.Litepages", 11000, 1); + "Availability.Prober.TimeUntilSuccess.Litepages", 11000, 1); } -TEST_F(PreviewsProberTest, TimeUntilFailure) { +TEST_F(AvailabilityProberTest, TimeUntilFailure) { base::HistogramTester histogram_tester; - PreviewsProber::RetryPolicy retry_policy; + AvailabilityProber::RetryPolicy retry_policy; retry_policy.max_retries = 0; - std::unique_ptr<PreviewsProber> prober = + std::unique_ptr<AvailabilityProber> prober = NewProberWithRetryPolicy(retry_policy); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); @@ -523,17 +524,17 @@ EXPECT_FALSE(prober->is_active()); histogram_tester.ExpectTotalCount( - "Previews.Prober.TimeUntilSuccess.Litepages", 0); + "Availability.Prober.TimeUntilSuccess.Litepages", 0); histogram_tester.ExpectUniqueSample( - "Previews.Prober.TimeUntilFailure.Litepages", 11000, 1); + "Availability.Prober.TimeUntilFailure.Litepages", 11000, 1); } -TEST_F(PreviewsProberTest, RandomGUID) { - PreviewsProber::RetryPolicy retry_policy; +TEST_F(AvailabilityProberTest, RandomGUID) { + AvailabilityProber::RetryPolicy retry_policy; retry_policy.use_random_urls = true; retry_policy.max_retries = 0; - std::unique_ptr<PreviewsProber> prober = + std::unique_ptr<AvailabilityProber> prober = NewProberWithRetryPolicy(retry_policy); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); @@ -545,14 +546,14 @@ EXPECT_FALSE(prober->is_active()); } -TEST_F(PreviewsProberTest, RetryLinear) { +TEST_F(AvailabilityProberTest, RetryLinear) { base::HistogramTester histogram_tester; - PreviewsProber::RetryPolicy retry_policy; + AvailabilityProber::RetryPolicy retry_policy; retry_policy.max_retries = 2; - retry_policy.backoff = PreviewsProber::Backoff::kLinear; + retry_policy.backoff = AvailabilityProber::Backoff::kLinear; retry_policy.base_interval = base::TimeDelta::FromMilliseconds(1000); - std::unique_ptr<PreviewsProber> prober = + std::unique_ptr<AvailabilityProber> prober = NewProberWithRetryPolicy(retry_policy); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); @@ -580,24 +581,24 @@ EXPECT_FALSE(prober->LastProbeWasSuccessful().value()); EXPECT_FALSE(prober->is_active()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - false, 3); - histogram_tester.ExpectTotalCount("Previews.Prober.ResponseCode.Litepages", - 0); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectUniqueSample( + "Availability.Prober.DidSucceed.Litepages", false, 3); + histogram_tester.ExpectTotalCount( + "Availability.Prober.ResponseCode.Litepages", 0); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::ERR_FAILED), 3); histogram_tester.ExpectTotalCount( - "Previews.Prober.NumAttemptsBeforeSuccess.Litepages", 0); + "Availability.Prober.NumAttemptsBeforeSuccess.Litepages", 0); } -TEST_F(PreviewsProberTest, RetryThenSucceed) { +TEST_F(AvailabilityProberTest, RetryThenSucceed) { base::HistogramTester histogram_tester; - PreviewsProber::RetryPolicy retry_policy; + AvailabilityProber::RetryPolicy retry_policy; retry_policy.max_retries = 2; - retry_policy.backoff = PreviewsProber::Backoff::kLinear; + retry_policy.backoff = AvailabilityProber::Backoff::kLinear; retry_policy.base_interval = base::TimeDelta::FromMilliseconds(1000); - std::unique_ptr<PreviewsProber> prober = + std::unique_ptr<AvailabilityProber> prober = NewProberWithRetryPolicy(retry_policy); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); @@ -625,29 +626,30 @@ EXPECT_TRUE(prober->LastProbeWasSuccessful().value()); EXPECT_FALSE(prober->is_active()); - histogram_tester.ExpectBucketCount("Previews.Prober.DidSucceed.Litepages", + histogram_tester.ExpectBucketCount("Availability.Prober.DidSucceed.Litepages", false, 2); - histogram_tester.ExpectBucketCount("Previews.Prober.DidSucceed.Litepages", + histogram_tester.ExpectBucketCount("Availability.Prober.DidSucceed.Litepages", true, 1); histogram_tester.ExpectUniqueSample( - "Previews.Prober.NumAttemptsBeforeSuccess.Litepages", 3, 1); - histogram_tester.ExpectUniqueSample("Previews.Prober.ResponseCode.Litepages", - net::HTTP_OK, 1); - histogram_tester.ExpectBucketCount("Previews.Prober.NetError.Litepages", + "Availability.Prober.NumAttemptsBeforeSuccess.Litepages", 3, 1); + histogram_tester.ExpectUniqueSample( + "Availability.Prober.ResponseCode.Litepages", net::HTTP_OK, 1); + histogram_tester.ExpectBucketCount("Availability.Prober.NetError.Litepages", std::abs(net::ERR_FAILED), 2); - histogram_tester.ExpectBucketCount("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectBucketCount("Availability.Prober.NetError.Litepages", std::abs(net::OK), 1); - histogram_tester.ExpectTotalCount("Previews.Prober.NetError.Litepages", 3); + histogram_tester.ExpectTotalCount("Availability.Prober.NetError.Litepages", + 3); } -TEST_F(PreviewsProberTest, RetryExponential) { +TEST_F(AvailabilityProberTest, RetryExponential) { base::HistogramTester histogram_tester; - PreviewsProber::RetryPolicy retry_policy; + AvailabilityProber::RetryPolicy retry_policy; retry_policy.max_retries = 2; - retry_policy.backoff = PreviewsProber::Backoff::kExponential; + retry_policy.backoff = AvailabilityProber::Backoff::kExponential; retry_policy.base_interval = base::TimeDelta::FromMilliseconds(1000); - std::unique_ptr<PreviewsProber> prober = + std::unique_ptr<AvailabilityProber> prober = NewProberWithRetryPolicy(retry_policy); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); @@ -675,25 +677,25 @@ EXPECT_FALSE(prober->LastProbeWasSuccessful().value()); EXPECT_FALSE(prober->is_active()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - false, 3); - histogram_tester.ExpectTotalCount("Previews.Prober.ResponseCode.Litepages", - 0); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectUniqueSample( + "Availability.Prober.DidSucceed.Litepages", false, 3); + histogram_tester.ExpectTotalCount( + "Availability.Prober.ResponseCode.Litepages", 0); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::ERR_FAILED), 3); } -TEST_F(PreviewsProberTest, TimeoutLinear) { +TEST_F(AvailabilityProberTest, TimeoutLinear) { base::HistogramTester histogram_tester; - PreviewsProber::RetryPolicy retry_policy; + AvailabilityProber::RetryPolicy retry_policy; retry_policy.max_retries = 1; retry_policy.base_interval = base::TimeDelta::FromMilliseconds(10); - PreviewsProber::TimeoutPolicy timeout_policy; - timeout_policy.backoff = PreviewsProber::Backoff::kLinear; + AvailabilityProber::TimeoutPolicy timeout_policy; + timeout_policy.backoff = AvailabilityProber::Backoff::kLinear; timeout_policy.base_timeout = base::TimeDelta::FromMilliseconds(1000); - std::unique_ptr<PreviewsProber> prober = + std::unique_ptr<AvailabilityProber> prober = NewProberWithPolicies(retry_policy, timeout_policy); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); @@ -719,25 +721,25 @@ EXPECT_FALSE(prober->LastProbeWasSuccessful().value()); EXPECT_FALSE(prober->is_active()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - false, 2); - histogram_tester.ExpectTotalCount("Previews.Prober.ResponseCode.Litepages", - 0); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectUniqueSample( + "Availability.Prober.DidSucceed.Litepages", false, 2); + histogram_tester.ExpectTotalCount( + "Availability.Prober.ResponseCode.Litepages", 0); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::ERR_TIMED_OUT), 2); } -TEST_F(PreviewsProberTest, TimeoutExponential) { +TEST_F(AvailabilityProberTest, TimeoutExponential) { base::HistogramTester histogram_tester; - PreviewsProber::RetryPolicy retry_policy; + AvailabilityProber::RetryPolicy retry_policy; retry_policy.max_retries = 1; retry_policy.base_interval = base::TimeDelta::FromMilliseconds(10); - PreviewsProber::TimeoutPolicy timeout_policy; - timeout_policy.backoff = PreviewsProber::Backoff::kExponential; + AvailabilityProber::TimeoutPolicy timeout_policy; + timeout_policy.backoff = AvailabilityProber::Backoff::kExponential; timeout_policy.base_timeout = base::TimeDelta::FromMilliseconds(1000); - std::unique_ptr<PreviewsProber> prober = + std::unique_ptr<AvailabilityProber> prober = NewProberWithPolicies(retry_policy, timeout_policy); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); @@ -763,26 +765,26 @@ EXPECT_FALSE(prober->LastProbeWasSuccessful().value()); EXPECT_FALSE(prober->is_active()); - histogram_tester.ExpectUniqueSample("Previews.Prober.DidSucceed.Litepages", - false, 2); - histogram_tester.ExpectTotalCount("Previews.Prober.ResponseCode.Litepages", - 0); - histogram_tester.ExpectUniqueSample("Previews.Prober.NetError.Litepages", + histogram_tester.ExpectUniqueSample( + "Availability.Prober.DidSucceed.Litepages", false, 2); + histogram_tester.ExpectTotalCount( + "Availability.Prober.ResponseCode.Litepages", 0); + histogram_tester.ExpectUniqueSample("Availability.Prober.NetError.Litepages", std::abs(net::ERR_TIMED_OUT), 2); } -TEST_F(PreviewsProberTest, DelegateStopsFirstProbe) { +TEST_F(AvailabilityProberTest, DelegateStopsFirstProbe) { base::HistogramTester histogram_tester; TestDelegate delegate; delegate.set_should_send_next_probe(false); - PreviewsProber::RetryPolicy retry_policy; + AvailabilityProber::RetryPolicy retry_policy; retry_policy.max_retries = 2; - retry_policy.backoff = PreviewsProber::Backoff::kLinear; + retry_policy.backoff = AvailabilityProber::Backoff::kLinear; retry_policy.base_interval = base::TimeDelta::FromMilliseconds(1000); - std::unique_ptr<PreviewsProber> prober = NewProberWithPoliciesAndDelegate( - &delegate, retry_policy, PreviewsProber::TimeoutPolicy()); + std::unique_ptr<AvailabilityProber> prober = NewProberWithPoliciesAndDelegate( + &delegate, retry_policy, AvailabilityProber::TimeoutPolicy()); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -790,19 +792,20 @@ EXPECT_FALSE(prober->is_active()); VerifyNoRequests(); - histogram_tester.ExpectTotalCount("Previews.Prober.DidSucceed.Litepages", 0); + histogram_tester.ExpectTotalCount("Availability.Prober.DidSucceed.Litepages", + 0); } -TEST_F(PreviewsProberTest, DelegateStopsRetries) { +TEST_F(AvailabilityProberTest, DelegateStopsRetries) { TestDelegate delegate; - PreviewsProber::RetryPolicy retry_policy; + AvailabilityProber::RetryPolicy retry_policy; retry_policy.max_retries = 2; - retry_policy.backoff = PreviewsProber::Backoff::kLinear; + retry_policy.backoff = AvailabilityProber::Backoff::kLinear; retry_policy.base_interval = base::TimeDelta::FromMilliseconds(1000); - std::unique_ptr<PreviewsProber> prober = NewProberWithPoliciesAndDelegate( - &delegate, retry_policy, PreviewsProber::TimeoutPolicy()); + std::unique_ptr<AvailabilityProber> prober = NewProberWithPoliciesAndDelegate( + &delegate, retry_policy, AvailabilityProber::TimeoutPolicy()); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -822,10 +825,10 @@ VerifyNoRequests(); } -TEST_F(PreviewsProberTest, CacheEntryAge) { +TEST_F(AvailabilityProberTest, CacheEntryAge) { base::HistogramTester histogram_tester; - std::unique_ptr<PreviewsProber> prober = NewProber(); + std::unique_ptr<AvailabilityProber> prober = NewProber(); EXPECT_EQ(prober->LastProbeWasSuccessful(), base::nullopt); prober->SendNowIfInactive(false); @@ -834,16 +837,16 @@ EXPECT_TRUE(prober->LastProbeWasSuccessful().value()); EXPECT_FALSE(prober->is_active()); - histogram_tester.ExpectUniqueSample("Previews.Prober.CacheEntryAge.Litepages", - 0, 1); + histogram_tester.ExpectUniqueSample( + "Availability.Prober.CacheEntryAge.Litepages", 0, 1); FastForward(base::TimeDelta::FromHours(24)); EXPECT_TRUE(prober->LastProbeWasSuccessful().value()); - histogram_tester.ExpectBucketCount("Previews.Prober.CacheEntryAge.Litepages", - 0, 1); - histogram_tester.ExpectBucketCount("Previews.Prober.CacheEntryAge.Litepages", - 24, 1); - histogram_tester.ExpectTotalCount("Previews.Prober.CacheEntryAge.Litepages", - 2); + histogram_tester.ExpectBucketCount( + "Availability.Prober.CacheEntryAge.Litepages", 0, 1); + histogram_tester.ExpectBucketCount( + "Availability.Prober.CacheEntryAge.Litepages", 24, 1); + histogram_tester.ExpectTotalCount( + "Availability.Prober.CacheEntryAge.Litepages", 2); }
diff --git a/chrome/browser/previews/proto/previews_prober_cache_entry.proto b/chrome/browser/availability/proto/availability_prober_cache_entry.proto similarity index 90% rename from chrome/browser/previews/proto/previews_prober_cache_entry.proto rename to chrome/browser/availability/proto/availability_prober_cache_entry.proto index 6a7b3a44..59ebfd24 100644 --- a/chrome/browser/previews/proto/previews_prober_cache_entry.proto +++ b/chrome/browser/availability/proto/availability_prober_cache_entry.proto
@@ -6,7 +6,7 @@ option optimize_for = LITE_RUNTIME; -message PreviewsProberCacheEntry { +message AvailabilityProberCacheEntry { // Whether the probe was successful. optional bool is_success = 1;
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc index a0267e12..98dcd7f5 100644 --- a/chrome/browser/banners/app_banner_manager.cc +++ b/chrome/browser/banners/app_banner_manager.cc
@@ -399,7 +399,7 @@ primary_icon_url_ = data.primary_icon_url; primary_icon_ = *data.primary_icon; - + has_maskable_primary_icon_ = data.has_maskable_primary_icon; // If we triggered the installability check on page load, then it's possible // we don't have enough engagement yet. If that's the case, return here but
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h index c806b10..6186fda2 100644 --- a/chrome/browser/banners/app_banner_manager.h +++ b/chrome/browser/banners/app_banner_manager.h
@@ -322,6 +322,9 @@ // The primary icon object. SkBitmap primary_icon_; + // Whether or not the primary icon is maskable. + bool has_maskable_primary_icon_; + // The current banner pipeline state for this page load. State state_;
diff --git a/chrome/browser/banners/app_banner_manager_android.cc b/chrome/browser/banners/app_banner_manager_android.cc index 1fd1bc2a..a3dd56d3 100644 --- a/chrome/browser/banners/app_banner_manager_android.cc +++ b/chrome/browser/banners/app_banner_manager_android.cc
@@ -210,7 +210,8 @@ weak_factory_.GetWeakPtr(), ShortcutHelper::CreateShortcutInfo(manifest_url_, manifest_, primary_icon_url_, badge_icon_url_), - primary_icon_, badge_icon_, install_source, can_install_webapk_); + primary_icon_, badge_icon_, install_source, can_install_webapk_, + has_maskable_primary_icon_); } else { ui_delegate_ = AppBannerUiDelegateAndroid::Create( weak_factory_.GetWeakPtr(), native_app_title_,
diff --git a/chrome/browser/banners/app_banner_ui_delegate_android.cc b/chrome/browser/banners/app_banner_ui_delegate_android.cc index 2e100ba..d167eb48 100644 --- a/chrome/browser/banners/app_banner_ui_delegate_android.cc +++ b/chrome/browser/banners/app_banner_ui_delegate_android.cc
@@ -34,11 +34,12 @@ const SkBitmap& primary_icon, const SkBitmap& badge_icon, WebappInstallSource install_source, - bool is_webapk) { + bool is_webapk, + bool has_primary_maskable_icon) { return std::unique_ptr<AppBannerUiDelegateAndroid>( new AppBannerUiDelegateAndroid(weak_manager, std::move(shortcut_info), primary_icon, badge_icon, install_source, - is_webapk)); + is_webapk, has_primary_maskable_icon)); } // static @@ -239,12 +240,14 @@ const SkBitmap& primary_icon, const SkBitmap& badge_icon, WebappInstallSource install_source, - bool is_webapk) + bool is_webapk, + bool has_primary_maskable_icon) : weak_manager_(weak_manager), app_title_(shortcut_info->name), shortcut_info_(std::move(shortcut_info)), primary_icon_(primary_icon), badge_icon_(badge_icon), + has_primary_maskable_icon_(has_primary_maskable_icon), type_(is_webapk ? AppType::WEBAPK : AppType::LEGACY_WEBAPP), install_source_(install_source), has_user_interaction_(false) { @@ -305,8 +308,8 @@ web_contents, shortcut_info_->url.spec(), AppBannerSettingsHelper::WEB); WebApkInstallService::Get(web_contents->GetBrowserContext()) - ->InstallAsync(web_contents, *shortcut_info_, primary_icon_, badge_icon_, - install_source_); + ->InstallAsync(web_contents, *shortcut_info_, primary_icon_, + has_primary_maskable_icon_, badge_icon_, install_source_); } void AppBannerUiDelegateAndroid::InstallLegacyWebApp(
diff --git a/chrome/browser/banners/app_banner_ui_delegate_android.h b/chrome/browser/banners/app_banner_ui_delegate_android.h index 3fede8c..88933d66 100644 --- a/chrome/browser/banners/app_banner_ui_delegate_android.h +++ b/chrome/browser/banners/app_banner_ui_delegate_android.h
@@ -44,7 +44,8 @@ const SkBitmap& primary_icon, const SkBitmap& badge_icon, WebappInstallSource install_source, - bool is_webapk); + bool is_webapk, + bool has_primary_maskable_icon); // Creates a delegate for promoting the installation of an Android app. static std::unique_ptr<AppBannerUiDelegateAndroid> Create( @@ -112,7 +113,8 @@ const SkBitmap& primary_icon, const SkBitmap& badge_icon, WebappInstallSource install_source, - bool is_webapk); + bool is_webapk, + bool has_primary_maskable_icon); // Delegate for promoting an Android app. AppBannerUiDelegateAndroid( @@ -145,6 +147,8 @@ const SkBitmap primary_icon_; const SkBitmap badge_icon_; + bool has_primary_maskable_icon_; + std::string package_name_; AppType type_;
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h index 2dee7b6..9c61a9e 100644 --- a/chrome/browser/browser_process.h +++ b/chrome/browser/browser_process.h
@@ -20,6 +20,7 @@ #include "build/build_config.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/shell_integration.h" +#include "chrome/common/buildflags.h" #include "media/media_buildflags.h" class BackgroundModeManager; @@ -248,8 +249,10 @@ virtual component_updater::ComponentUpdateService* component_updater() = 0; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) virtual component_updater::SupervisedUserWhitelistInstaller* supervised_user_whitelist_installer() = 0; +#endif virtual MediaFileSystemRegistry* media_file_system_registry() = 0;
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index ca4cf3d8..ec674868 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc
@@ -39,7 +39,6 @@ #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/component_updater/chrome_component_updater_configurator.h" -#include "chrome/browser/component_updater/supervised_user_whitelist_installer.h" #include "chrome/browser/defaults.h" #include "chrome/browser/devtools/devtools_auto_opener.h" #include "chrome/browser/devtools/remote_debugging_server.h" @@ -195,6 +194,10 @@ #include "chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h" #endif +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/component_updater/supervised_user_whitelist_installer.h" +#endif + #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS) // How often to check if the persistent instance of Chrome needs to restart // to install an update. @@ -376,9 +379,11 @@ notification_ui_manager_.reset(); #endif +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) // The SupervisedUserWhitelistInstaller observes the ProfileAttributesStorage, // so it needs to be shut down before the ProfileManager. supervised_user_whitelist_installer_.reset(); +#endif // Debugger must be cleaned up before ProfileManager. remote_debugging_server_.reset(); @@ -1031,6 +1036,7 @@ return component_updater_.get(); } +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) component_updater::SupervisedUserWhitelistInstaller* BrowserProcessImpl::supervised_user_whitelist_installer() { if (!supervised_user_whitelist_installer_) { @@ -1042,6 +1048,7 @@ } return supervised_user_whitelist_installer_.get(); } +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) void BrowserProcessImpl::OnKeepAliveStateChanged(bool is_keeping_alive) { if (is_keeping_alive)
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index 8029837..c02e294 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h
@@ -180,8 +180,10 @@ #endif component_updater::ComponentUpdateService* component_updater() override; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) component_updater::SupervisedUserWhitelistInstaller* supervised_user_whitelist_installer() override; +#endif MediaFileSystemRegistry* media_file_system_registry() override; WebRtcLogUploader* webrtc_log_uploader() override; network_time::NetworkTimeTracker* network_time_tracker() override; @@ -366,8 +368,10 @@ // but some users of component updater only install per-user. std::unique_ptr<component_updater::ComponentUpdateService> component_updater_; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) std::unique_ptr<component_updater::SupervisedUserWhitelistInstaller> supervised_user_whitelist_installer_; +#endif #if BUILDFLAG(ENABLE_PLUGINS) std::unique_ptr<PluginsResourceService> plugins_resource_service_;
diff --git a/chrome/browser/browsing_data/browsing_data_appcache_helper.cc b/chrome/browser/browsing_data/browsing_data_appcache_helper.cc index 6be57b42..8aded4c2 100644 --- a/chrome/browser/browsing_data/browsing_data_appcache_helper.cc +++ b/chrome/browser/browsing_data/browsing_data_appcache_helper.cc
@@ -18,6 +18,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_usage_info.h" +#include "content/public/common/content_features.h" #include "net/base/completion_once_callback.h" #include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h" @@ -30,7 +31,6 @@ BrowsingDataAppCacheHelper::FetchCallback callback, scoped_refptr<content::AppCacheInfoCollection> info_collection, int /*rv*/) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(!callback.is_null()); std::list<content::StorageUsageInfo> result; @@ -57,9 +57,13 @@ result.emplace_back(origin, total_size, last_modified); } - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(std::move(callback), std::move(result))); + if (base::FeatureList::IsEnabled(features::kNavigationLoaderOnUI)) { + std::move(callback).Run(std::move(result)); + } else { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::UI}, + base::BindOnce(std::move(callback), std::move(result))); + } } } // namespace @@ -72,25 +76,33 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!callback.is_null()); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&BrowsingDataAppCacheHelper::StartFetchingOnIOThread, this, - std::move(callback))); + if (base::FeatureList::IsEnabled(features::kNavigationLoaderOnUI)) { + StartFetchingOnLoaderThread(std::move(callback)); + } else { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&BrowsingDataAppCacheHelper::StartFetchingOnLoaderThread, + this, std::move(callback))); + } } void BrowsingDataAppCacheHelper::DeleteAppCaches(const url::Origin& origin) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&BrowsingDataAppCacheHelper::DeleteAppCachesOnIOThread, - this, origin)); + if (base::FeatureList::IsEnabled(features::kNavigationLoaderOnUI)) { + DeleteAppCachesOnLoaderThread(origin); + } else { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce( + &BrowsingDataAppCacheHelper::DeleteAppCachesOnLoaderThread, this, + origin)); + } } BrowsingDataAppCacheHelper::~BrowsingDataAppCacheHelper() {} -void BrowsingDataAppCacheHelper::StartFetchingOnIOThread( +void BrowsingDataAppCacheHelper::StartFetchingOnLoaderThread( FetchCallback callback) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK(!callback.is_null()); scoped_refptr<content::AppCacheInfoCollection> info_collection = @@ -102,9 +114,8 @@ info_collection)); } -void BrowsingDataAppCacheHelper::DeleteAppCachesOnIOThread( +void BrowsingDataAppCacheHelper::DeleteAppCachesOnLoaderThread( const url::Origin& origin) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); appcache_service_->DeleteAppCachesForOrigin(origin, net::CompletionOnceCallback()); }
diff --git a/chrome/browser/browsing_data/browsing_data_appcache_helper.h b/chrome/browser/browsing_data/browsing_data_appcache_helper.h index 5615ca401..ae536da 100644 --- a/chrome/browser/browsing_data/browsing_data_appcache_helper.h +++ b/chrome/browser/browsing_data/browsing_data_appcache_helper.h
@@ -41,8 +41,8 @@ virtual ~BrowsingDataAppCacheHelper(); private: - void StartFetchingOnIOThread(FetchCallback completion_callback); - void DeleteAppCachesOnIOThread(const url::Origin& origin); + void StartFetchingOnLoaderThread(FetchCallback completion_callback); + void DeleteAppCachesOnLoaderThread(const url::Origin& origin); // Owned by the profile. content::AppCacheService* appcache_service_;
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 5125ede2..b9e3c15 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -61,9 +61,9 @@ #include "chrome/browser/component_updater/optimization_hints_component_installer.h" #include "chrome/browser/component_updater/origin_trials_component_installer.h" #include "chrome/browser/component_updater/pepper_flash_component_installer.h" +#include "chrome/browser/component_updater/safety_tips_component_installer.h" #include "chrome/browser/component_updater/sth_set_component_remover.h" #include "chrome/browser/component_updater/subresource_filter_component_installer.h" -#include "chrome/browser/component_updater/supervised_user_whitelist_installer.h" #include "chrome/browser/defaults.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/lifetime/application_lifetime.h" @@ -341,6 +341,10 @@ #include "chrome/browser/resource_coordinator/tab_manager.h" #endif +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/component_updater/supervised_user_whitelist_installer.h" +#endif + using content::BrowserThread; namespace { @@ -485,9 +489,11 @@ RegisterPnaclComponent(cus); #endif // BUILDFLAG(ENABLE_NACL) && !defined(OS_ANDROID) +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) component_updater::SupervisedUserWhitelistInstaller* whitelist_installer = g_browser_process->supervised_user_whitelist_installer(); whitelist_installer->RegisterComponents(); +#endif RegisterSubresourceFilterComponent(cus); RegisterOnDeviceHeadSuggestComponent(cus); @@ -547,6 +553,8 @@ component_updater::RegisterVrAssetsComponent(cus); } #endif + + RegisterSafetyTipsComponent(cus, path); } #if !defined(OS_ANDROID)
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index bdb41ce..0b29bc11f 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -5209,13 +5209,6 @@ relying_party_id); } -#if defined(OS_MACOSX) -bool ChromeContentBrowserClient:: - IsWebAuthenticationTouchIdAuthenticatorSupported() { - return true; -} -#endif - std::unique_ptr<net::ClientCertStore> ChromeContentBrowserClient::CreateClientCertStore( content::ResourceContext* resource_context) { @@ -5844,6 +5837,7 @@ const ChromeSubresourceFilterClient* client = ChromeSubresourceFilterClient::FromWebContents(web_contents); if (client && client->GetThrottleManager()->IsFrameTaggedAsAd(frame_host)) { + download_policy->SetAllowed(content::NavigationDownloadType::kAdFrame); if (!user_gesture) { if (base::FeatureList::IsEnabled( blink::features:: @@ -5854,9 +5848,6 @@ download_policy->SetAllowed( content::NavigationDownloadType::kAdFrameNoGesture); } - } else { - download_policy->SetAllowed( - content::NavigationDownloadType::kAdFrameGesture); } } }
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 30a7226..069f597 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -521,9 +521,6 @@ GetWebAuthenticationRequestDelegate( content::RenderFrameHost* render_frame_host, const std::string& relying_party_id) override; -#if defined(OS_MACOSX) - bool IsWebAuthenticationTouchIdAuthenticatorSupported() override; -#endif std::unique_ptr<net::ClientCertStore> CreateClientCertStore( content::ResourceContext* resource_context) override; std::unique_ptr<content::LoginDelegate> CreateLoginDelegate(
diff --git a/chrome/browser/chrome_notification_types.h b/chrome/browser/chrome_notification_types.h index 1a0c83d..e2df7f6 100644 --- a/chrome/browser/chrome_notification_types.h +++ b/chrome/browser/chrome_notification_types.h
@@ -44,11 +44,6 @@ // DEPRECATED: Use BrowserListObserver::OnBrowserAdded() NOTIFICATION_BROWSER_OPENED = NOTIFICATION_CHROME_START, - // This message is sent after a window has been closed. The source is a - // Source<Browser> containing the affected Browser. No details are expected. - // DEPRECATED: Use BrowserListObserver::OnBrowserRemoved() - NOTIFICATION_BROWSER_CLOSED, - // This message is sent when closing a browser has been cancelled, either by // the user cancelling a beforeunload dialog, or IsClosingPermitted() // disallowing closing. This notification implies that no BROWSER_CLOSING or
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index fb0a07d4..c6e19a5 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -72,7 +72,6 @@ "//chrome/common", "//chrome/common/extensions/api", "//chrome/services/app_service:lib", - "//chrome/services/app_service/public/cpp:app_service_proxy", "//chrome/services/app_service/public/cpp:app_update", "//chrome/services/cups_proxy", "//chrome/services/cups_proxy/public/mojom",
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc index d1800dc..e70df52 100644 --- a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc +++ b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.cc
@@ -15,6 +15,8 @@ #include "chrome/browser/ui/app_list/app_list_syncable_service.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chromeos/components/multidevice/logging/logging.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" #include "extensions/common/extension.h" namespace chromeos { @@ -26,8 +28,16 @@ const PwaDomain kDomains[] = {PwaDomain::kProdAndroid, PwaDomain::kProdGoogle, PwaDomain::kStaging}; +const char kLastSuccessfulDomainPref[] = "android_sms.last_successful_domain"; + } // namespace +// static +void AndroidSmsAppManagerImpl::RegisterProfilePrefs( + PrefRegistrySimple* registry) { + registry->RegisterStringPref(kLastSuccessfulDomainPref, std::string()); +} + AndroidSmsAppManagerImpl::PwaDelegate::PwaDelegate() = default; AndroidSmsAppManagerImpl::PwaDelegate::~PwaDelegate() = default; @@ -50,11 +60,13 @@ AndroidSmsAppManagerImpl::AndroidSmsAppManagerImpl( Profile* profile, AndroidSmsAppSetupController* setup_controller, + PrefService* pref_service, app_list::AppListSyncableService* app_list_syncable_service, scoped_refptr<base::TaskRunner> task_runner) : profile_(profile), setup_controller_(setup_controller), app_list_syncable_service_(app_list_syncable_service), + pref_service_(pref_service), installed_url_at_last_notify_(GetCurrentAppUrl()), pwa_delegate_(std::make_unique<PwaDelegate>()), weak_ptr_factory_(this) { @@ -89,12 +101,14 @@ if (migrating_from && *migrating_from == GetPreferredPwaDomain()) migrating_from.reset(); + GURL install_url = GetAndroidMessagesURL(true /* use_install_url */); + is_new_app_setup_in_progress_ = true; setup_controller_->SetUpApp( - GetAndroidMessagesURL() /* app_url */, - GetAndroidMessagesURL(true /* use_install_url */) /* install_url */, + GetAndroidMessagesURL() /* app_url */, install_url, base::BindOnce(&AndroidSmsAppManagerImpl::OnSetUpNewAppResult, - weak_ptr_factory_.GetWeakPtr(), migrating_from)); + weak_ptr_factory_.GetWeakPtr(), migrating_from, + install_url)); } void AndroidSmsAppManagerImpl::SetUpAndLaunchAndroidSmsApp() { @@ -103,6 +117,8 @@ } void AndroidSmsAppManagerImpl::TearDownAndroidSmsApp() { + pref_service_->SetString(kLastSuccessfulDomainPref, std::string()); + base::Optional<GURL> installed_app_url = GetCurrentAppUrl(); if (!installed_app_url) return; @@ -111,6 +127,12 @@ base::DoNothing()); } +bool AndroidSmsAppManagerImpl::HasAppBeenManuallyUninstalledByUser() { + GURL url = GetAndroidMessagesURL(true /* use_install_url */); + return pref_service_->GetString(kLastSuccessfulDomainPref) == url.spec() && + !setup_controller_->GetPwa(url); +} + base::Optional<PwaDomain> AndroidSmsAppManagerImpl::GetInstalledPwaDomain() { for (auto* it = std::begin(kDomains); it != std::end(kDomains); ++it) { if (setup_controller_->GetPwa( @@ -153,6 +175,7 @@ void AndroidSmsAppManagerImpl::OnSetUpNewAppResult( const base::Optional<PwaDomain>& migrating_from, + const GURL& install_url, bool success) { is_new_app_setup_in_progress_ = false; @@ -165,6 +188,9 @@ return; } + if (success) + pref_service_->SetString(kLastSuccessfulDomainPref, install_url.spec()); + // If there is no PWA installed at the old URL, no migration is needed and // setup is finished. if (!migrating_from) {
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.h b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.h index b701e17e..9380caf 100644 --- a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.h +++ b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl.h
@@ -18,6 +18,9 @@ #include "components/content_settings/core/browser/host_content_settings_map.h" #include "url/gurl.h" +class PrefRegistrySimple; +class PrefService; + namespace app_list { class AppListSyncableService; } // namespace app_list @@ -38,10 +41,12 @@ AndroidSmsAppManagerImpl( Profile* profile, AndroidSmsAppSetupController* setup_controller, + PrefService* pref_service, app_list::AppListSyncableService* app_list_syncable_service, scoped_refptr<base::TaskRunner> task_runner = base::ThreadTaskRunnerHandle::Get()); ~AndroidSmsAppManagerImpl() override; + static void RegisterProfilePrefs(PrefRegistrySimple* registry); private: friend class AndroidSmsAppManagerImplTest; @@ -65,11 +70,13 @@ void SetUpAndroidSmsApp() override; void SetUpAndLaunchAndroidSmsApp() override; void TearDownAndroidSmsApp() override; + bool HasAppBeenManuallyUninstalledByUser() override; base::Optional<PwaDomain> GetInstalledPwaDomain(); void CompleteAsyncInitialization(); void NotifyInstalledAppUrlChangedIfNecessary(); void OnSetUpNewAppResult(const base::Optional<PwaDomain>& migrating_from, + const GURL& install_url, bool success); void OnRemoveOldAppResult(const base::Optional<PwaDomain>& migrating_from, bool success); @@ -80,6 +87,7 @@ Profile* profile_; AndroidSmsAppSetupController* setup_controller_; app_list::AppListSyncableService* app_list_syncable_service_; + PrefService* pref_service_; // True if installation is in currently in progress. bool is_new_app_setup_in_progress_ = false;
diff --git a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc index e621a5e..bd6e664 100644 --- a/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc +++ b/chrome/browser/chromeos/android_sms/android_sms_app_manager_impl_unittest.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/chromeos/android_sms/fake_android_sms_app_setup_controller.h" #include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/test/base/testing_profile.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/common/extension.h" #include "testing/gtest/include/gtest/gtest.h" @@ -27,6 +28,7 @@ const char kNewAppId[] = "newAppId"; const char kOldAppId[] = "oldAppId"; +const char kLastSuccessfulDomainPref[] = "android_sms.last_successful_domain"; GURL GetAndroidMessagesURLOld(bool use_install_url = false) { // For this test, consider the staging server to be the "old" URL. @@ -100,10 +102,15 @@ std::make_unique<FakeAndroidSmsAppSetupController>(); test_task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>(); + test_pref_service_ = + std::make_unique<sync_preferences::TestingPrefServiceSyncable>(); + AndroidSmsAppManagerImpl::RegisterProfilePrefs( + test_pref_service_->registry()); android_sms_app_manager_ = std::make_unique<AndroidSmsAppManagerImpl>( &profile_, fake_android_sms_app_setup_controller_.get(), - nullptr /* app_list_syncable_service */, test_task_runner_); + test_pref_service_.get(), nullptr /* app_list_syncable_service */, + test_task_runner_); auto test_pwa_delegate = std::make_unique<TestPwaDelegate>(); test_pwa_delegate_ = test_pwa_delegate.get(); @@ -132,10 +139,16 @@ return android_sms_app_manager_.get(); } + sync_preferences::TestingPrefServiceSyncable* test_pref_service() { + return test_pref_service_.get(); + } + private: content::TestBrowserThreadBundle thread_bundle_; TestingProfile profile_; + std::unique_ptr<sync_preferences::TestingPrefServiceSyncable> + test_pref_service_; std::unique_ptr<FakeAndroidSmsAppSetupController> fake_android_sms_app_setup_controller_; scoped_refptr<base::TestSimpleTaskRunner> test_task_runner_; @@ -163,18 +176,19 @@ GetAndroidMessagesURL(true /* use_install_url */))); EXPECT_FALSE(android_sms_app_manager()->GetCurrentAppUrl()); EXPECT_EQ(0u, test_observer()->num_installed_app_url_changed_events()); + EXPECT_EQ(std::string(), + test_pref_service()->GetString(kLastSuccessfulDomainPref)); } TEST_F(AndroidSmsAppManagerImplTest, TestSetUpMessages_ThenTearDown_NoPreviousApp) { CompleteAsyncInitialization(); + const GURL install_url = GetAndroidMessagesURL(true /* use_install_url */); android_sms_app_manager()->SetUpAndroidSmsApp(); fake_android_sms_app_setup_controller()->CompletePendingSetUpAppRequest( GetAndroidMessagesURL() /* expected_app_url */, - GetAndroidMessagesURL( - true /* use_install_url */) /* expected_install_url */, - kNewAppId); + install_url /* expected_install_url */, kNewAppId); // Verify that the app was installed and observers were notified. EXPECT_EQ(kNewAppId, fake_android_sms_app_setup_controller() @@ -182,12 +196,13 @@ true /* use_install_url */)) ->pwa->id()); EXPECT_TRUE(fake_android_sms_app_setup_controller() - ->GetAppMetadataAtUrl( - GetAndroidMessagesURL(true /* use_install_url */)) + ->GetAppMetadataAtUrl(install_url) ->is_cookie_present); EXPECT_EQ(GetAndroidMessagesURL(), *android_sms_app_manager()->GetCurrentAppUrl()); EXPECT_EQ(1u, test_observer()->num_installed_app_url_changed_events()); + EXPECT_EQ(install_url.spec(), + test_pref_service()->GetString(kLastSuccessfulDomainPref)); // Now, tear down the app, which should remove the DefaultToPersist cookie. android_sms_app_manager()->TearDownAndroidSmsApp(); @@ -199,17 +214,18 @@ ->GetAppMetadataAtUrl( GetAndroidMessagesURL(true /* use_install_url */)) ->is_cookie_present); + EXPECT_EQ(std::string(), + test_pref_service()->GetString(kLastSuccessfulDomainPref)); } TEST_F(AndroidSmsAppManagerImplTest, TestSetUpMessagesAndLaunch_NoPreviousApp) { CompleteAsyncInitialization(); + const GURL install_url = GetAndroidMessagesURL(true /* use_install_url */); android_sms_app_manager()->SetUpAndLaunchAndroidSmsApp(); fake_android_sms_app_setup_controller()->CompletePendingSetUpAppRequest( GetAndroidMessagesURL() /* expected_app_url */, - GetAndroidMessagesURL( - true /* use_install_url */) /* expected_install_url */, - kNewAppId); + install_url /* expected_install_url */, kNewAppId); // Verify that the app was installed and observers were notified. EXPECT_EQ(kNewAppId, fake_android_sms_app_setup_controller() @@ -217,12 +233,15 @@ true /* use_install_url */)) ->pwa->id()); EXPECT_TRUE(fake_android_sms_app_setup_controller() - ->GetAppMetadataAtUrl( - GetAndroidMessagesURL(true /* use_install_url */)) + ->GetAppMetadataAtUrl(install_url) ->is_cookie_present); EXPECT_EQ(GetAndroidMessagesURL(), *android_sms_app_manager()->GetCurrentAppUrl()); EXPECT_EQ(1u, test_observer()->num_installed_app_url_changed_events()); + EXPECT_EQ(install_url.spec(), + test_pref_service()->GetString(kLastSuccessfulDomainPref)); + EXPECT_FALSE( + android_sms_app_manager()->HasAppBeenManuallyUninstalledByUser()); // The app should have been launched. EXPECT_EQ(kNewAppId, test_pwa_delegate()->opened_app_ids()[0]); @@ -270,11 +289,10 @@ CompleteAsyncInitialization(); // This should trigger the new app to be installed. + const GURL install_url = GetAndroidMessagesURL(true /* use_install_url */); fake_android_sms_app_setup_controller()->CompletePendingSetUpAppRequest( GetAndroidMessagesURL() /* expected_app_url */, - GetAndroidMessagesURL( - true /* use_install_url */) /* expected_install_url */, - kNewAppId /* id_for_app */); + install_url /* expected_install_url */, kNewAppId /* id_for_app */); // Verify that the app was installed and attributes were transferred. By this // point, observers should not have been notified yet since the old app was @@ -289,6 +307,8 @@ ->is_cookie_present); EXPECT_EQ(GetAndroidMessagesURL(), *android_sms_app_manager()->GetCurrentAppUrl()); + EXPECT_EQ(install_url.spec(), + test_pref_service()->GetString(kLastSuccessfulDomainPref)); EXPECT_EQ(std::make_pair(std::string(kOldAppId), std::string(kNewAppId)), test_pwa_delegate()->transfer_item_attribute_params()[0]); EXPECT_EQ(0u, test_observer()->num_installed_app_url_changed_events()); @@ -302,6 +322,37 @@ GetAndroidMessagesURL() /* expected_migrated_to_app_url */, true /* success */); EXPECT_EQ(1u, test_observer()->num_installed_app_url_changed_events()); + EXPECT_FALSE( + android_sms_app_manager()->HasAppBeenManuallyUninstalledByUser()); +} + +TEST_F(AndroidSmsAppManagerImplTest, TestManualUninstall) { + const GURL install_url = GetAndroidMessagesURL(true /* use_install_url */); + CompleteAsyncInitialization(); + + android_sms_app_manager()->SetUpAndroidSmsApp(); + fake_android_sms_app_setup_controller()->CompletePendingSetUpAppRequest( + GetAndroidMessagesURL() /* expected_app_url */, + install_url /* expected_install_url */, kNewAppId); + + // Verify that the app was installed and observers were notified. + EXPECT_EQ(kNewAppId, fake_android_sms_app_setup_controller() + ->GetAppMetadataAtUrl(GetAndroidMessagesURL( + true /* use_install_url */)) + ->pwa->id()); + EXPECT_TRUE(fake_android_sms_app_setup_controller() + ->GetAppMetadataAtUrl(install_url) + ->is_cookie_present); + EXPECT_EQ(GetAndroidMessagesURL(), + *android_sms_app_manager()->GetCurrentAppUrl()); + EXPECT_EQ(1u, test_observer()->num_installed_app_url_changed_events()); + EXPECT_EQ(install_url.spec(), + test_pref_service()->GetString(kLastSuccessfulDomainPref)); + + // Now uninstall the app and verify that the app manager registers it. + fake_android_sms_app_setup_controller()->SetAppAtUrl(install_url, + base::nullopt); + EXPECT_TRUE(android_sms_app_manager()->HasAppBeenManuallyUninstalledByUser()); } } // namespace android_sms
diff --git a/chrome/browser/chromeos/android_sms/android_sms_service.cc b/chrome/browser/chromeos/android_sms/android_sms_service.cc index 8634823..f7b9a30 100644 --- a/chrome/browser/chromeos/android_sms/android_sms_service.cc +++ b/chrome/browser/chromeos/android_sms/android_sms_service.cc
@@ -40,6 +40,7 @@ android_sms_app_manager_(std::make_unique<AndroidSmsAppManagerImpl>( profile_, andoid_sms_app_setup_controller_.get(), + profile_->GetPrefs(), app_list_syncable_service)), android_sms_pairing_state_tracker_( std::make_unique<AndroidSmsPairingStateTrackerImpl>(
diff --git a/chrome/browser/chromeos/android_sms/android_sms_service_factory.cc b/chrome/browser/chromeos/android_sms/android_sms_service_factory.cc index 9c58176..0e9e1c7 100644 --- a/chrome/browser/chromeos/android_sms/android_sms_service_factory.cc +++ b/chrome/browser/chromeos/android_sms/android_sms_service_factory.cc
@@ -102,6 +102,7 @@ void AndroidSmsServiceFactory::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { PairingLostNotifier::RegisterProfilePrefs(registry); + AndroidSmsAppManagerImpl::RegisterProfilePrefs(registry); } } // namespace android_sms
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc index b231235..6c0c37e 100644 --- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc +++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
@@ -76,6 +76,8 @@ } else { close_reason = apps::IntentPickerCloseReason::ERROR_AFTER_PICKER; } + RecordUma(launch_name, app_type, close_reason, apps::Source::kHttpOrHttps, + should_persist); return; case apps::mojom::AppType::kUnknown: // TODO(crbug.com/826982): This workaround can be removed when preferences @@ -136,7 +138,9 @@ FindPwaForUrl(web_contents, url, std::move(apps)); bool show_persistence_options = ShouldShowPersistenceOptions(apps_for_picker); apps::AppsNavigationThrottle::ShowIntentPickerBubbleForApps( - web_contents, std::move(apps_for_picker), show_persistence_options, + web_contents, std::move(apps_for_picker), + /*show_stay_in_chrome=*/show_persistence_options, + /*show_remember_selection=*/show_persistence_options, base::BindOnce(&OnIntentPickerClosed, web_contents, ui_auto_display_service, url)); }
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc index eac2110f..05a47460 100644 --- a/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc +++ b/chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.cc
@@ -480,7 +480,7 @@ const bool stay_in_chrome = IsChromeAnAppCandidate(handlers); IntentPickerTabHelper::SetShouldShowIcon(web_contents, true); browser->window()->ShowIntentPickerBubble( - std::move(app_info), stay_in_chrome, /*show_persistence_options=*/true, + std::move(app_info), stay_in_chrome, /*show_remember_selection=*/true, base::BindOnce(OnIntentPickerClosed, render_process_host_id, routing_id, url, safe_to_bypass_ui, std::move(handlers))); }
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.cc b/chrome/browser/chromeos/crostini/crostini_export_import.cc index b901db0..ad3b9026 100644 --- a/chrome/browser/chromeos/crostini/crostini_export_import.cc +++ b/chrome/browser/chromeos/crostini/crostini_export_import.cc
@@ -7,8 +7,10 @@ #include <utility> #include "base/bind.h" +#include "base/files/file_util.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" +#include "base/task/post_task.h" #include "base/time/time.h" #include "chrome/browser/chromeos/crostini/crostini_manager_factory.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" @@ -175,12 +177,26 @@ switch (type) { case ExportImportType::EXPORT: - guest_os::GuestOsSharePath::GetForProfile(profile_)->SharePath( - kCrostiniDefaultVmName, path.DirName(), false, - base::BindOnce(&CrostiniExportImport::ExportAfterSharing, - weak_ptr_factory_.GetWeakPtr(), - std::move(container_id), path.BaseName(), - std::move(callback))); + base::PostTaskWithTraitsAndReply( + FROM_HERE, {base::MayBlock()}, + // Ensure file exists so that it can be shared. + base::BindOnce( + [](const base::FilePath& path) { + base::File file(path, base::File::FLAG_CREATE_ALWAYS | + base::File::FLAG_WRITE); + DCHECK(file.IsValid()) << path << " is invalid"; + }, + path), + base::BindOnce( + &guest_os::GuestOsSharePath::SharePath, + base::Unretained( + guest_os::GuestOsSharePath::GetForProfile(profile_)), + kCrostiniDefaultVmName, path, false, + base::BindOnce(&CrostiniExportImport::ExportAfterSharing, + weak_ptr_factory_.GetWeakPtr(), + std::move(container_id), std::move(callback)) + + )); break; case ExportImportType::IMPORT: guest_os::GuestOsSharePath::GetForProfile(profile_)->SharePath( @@ -194,7 +210,6 @@ void CrostiniExportImport::ExportAfterSharing( const ContainerId& container_id, - const base::FilePath& filename, CrostiniManager::CrostiniResultCallback callback, const base::FilePath& container_path, bool result, @@ -209,8 +224,7 @@ return; } CrostiniManager::GetForProfile(profile_)->ExportLxdContainer( - kCrostiniDefaultVmName, kCrostiniDefaultContainerName, - container_path.Append(filename), + kCrostiniDefaultVmName, kCrostiniDefaultContainerName, container_path, base::BindOnce(&CrostiniExportImport::OnExportComplete, weak_ptr_factory_.GetWeakPtr(), base::Time::Now(), container_id, std::move(callback))); @@ -238,6 +252,10 @@ } } else { LOG(ERROR) << "Error exporting " << int(result); + base::PostTaskWithTraits( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(base::IgnoreResult(&base::DeleteFile), + it->second->path(), false)); switch (result) { case CrostiniResult::CONTAINER_EXPORT_IMPORT_FAILED_VM_STOPPED: enum_hist_result = ExportContainerResult::kFailedVmStopped;
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import.h b/chrome/browser/chromeos/crostini/crostini_export_import.h index 64a92b2..c80a381 100644 --- a/chrome/browser/chromeos/crostini/crostini_export_import.h +++ b/chrome/browser/chromeos/crostini/crostini_export_import.h
@@ -131,7 +131,6 @@ uint64_t minimum_required_space) override; void ExportAfterSharing(const ContainerId& container_id, - const base::FilePath& filename, CrostiniManager::CrostiniResultCallback callback, const base::FilePath& container_path, bool result,
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_notification.h b/chrome/browser/chromeos/crostini/crostini_export_import_notification.h index b8a2fca..8a0593f5 100644 --- a/chrome/browser/chromeos/crostini/crostini_export_import_notification.h +++ b/chrome/browser/chromeos/crostini/crostini_export_import_notification.h
@@ -55,6 +55,7 @@ Status status() const { return status_; } ExportImportType type() const { return type_; } + const base::FilePath& path() const { return path_; } // Getters for testing. message_center::Notification* get_notification() { return notification_.get();
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc index adf4be9..3ecf41e 100644 --- a/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc +++ b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc
@@ -174,6 +174,9 @@ vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE); EXPECT_EQ(notification->status(), CrostiniExportImportNotification::Status::DONE); + // CrostiniExportImport should've created the exported file. + thread_bundle_.RunUntilIdle(); + EXPECT_TRUE(base::PathExists(tarball_)); } TEST_F(CrostiniExportImportTest, TestExportSuccess) { @@ -229,6 +232,9 @@ vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE); EXPECT_EQ(notification->status(), CrostiniExportImportNotification::Status::DONE); + // CrostiniExportImport should've created the exported file. + thread_bundle_.RunUntilIdle(); + EXPECT_TRUE(base::PathExists(tarball_)); } TEST_F(CrostiniExportImportTest, TestExportFail) { @@ -243,6 +249,9 @@ vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_FAILED); EXPECT_EQ(notification->status(), CrostiniExportImportNotification::Status::FAILED); + // CrostiniExportImport should cleanup the file if an export fails. + thread_bundle_.RunUntilIdle(); + EXPECT_FALSE(base::PathExists(tarball_)); } TEST_F(CrostiniExportImportTest, TestImportSuccess) {
diff --git a/chrome/browser/chromeos/crostini/crostini_test_helper.cc b/chrome/browser/chromeos/crostini/crostini_test_helper.cc index 91a8453..1390ab7b 100644 --- a/chrome/browser/chromeos/crostini/crostini_test_helper.cc +++ b/chrome/browser/chromeos/crostini/crostini_test_helper.cc
@@ -5,7 +5,8 @@ #include "chrome/browser/chromeos/crostini/crostini_test_helper.h" #include "base/feature_list.h" -#include "chrome/browser/apps/app_service/app_service_proxy_impl.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/chromeos/crostini/crostini_manager.h" #include "chrome/browser/chromeos/crostini/crostini_pref_names.h" #include "chrome/browser/chromeos/crostini/crostini_registry_service.h" @@ -115,7 +116,7 @@ // // We therefore manually have the App Service re-examine whether Crostini // is enabled for this profile. - auto* proxy = apps::AppServiceProxyImpl::GetImplForTesting(profile_); + auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile_); proxy->ReInitializeCrostiniForTesting(profile_); proxy->FlushMojoCallsForTesting(); }
diff --git a/chrome/browser/chromeos/first_run/goodies_displayer_browsertest.cc b/chrome/browser/chromeos/first_run/goodies_displayer_browsertest.cc index 9cfed79..7215886 100644 --- a/chrome/browser/chromeos/first_run/goodies_displayer_browsertest.cc +++ b/chrome/browser/chromeos/first_run/goodies_displayer_browsertest.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/chromeos/first_run/goodies_displayer.h" #include "base/command_line.h" +#include "base/run_loop.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser_finder.h" @@ -13,7 +14,6 @@ #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/test_launcher_utils.h" -#include "chrome/test/base/ui_test_utils.h" #include "components/prefs/pref_service.h" namespace chromeos { @@ -31,11 +31,8 @@ // Set up windowless browser and GoodiesDisplayer. |delta_days| is +/- delta // in days from kMaxDaysAfterOobeForGoodies; <= 0: "show", > 0: "don't show". Browser* CreateBrowserAndDisplayer(int delta_days) { - // Create a new browser and wait for completion. - ui_test_utils::BrowserAddedObserver browser_added_observer; Browser* browser = new Browser( Browser::CreateParams(ProfileManager::GetActiveUserProfile(), true)); - browser_added_observer.WaitForSingleNewBrowser(); // Set up Goodies Displayer and set fake age of device. setup_info_.days_since_oobe = @@ -74,10 +71,9 @@ // Wait for GoodiesDisplayer setup completion. The completion callback will // shut down the message loop. - scoped_refptr<content::MessageLoopRunner> message_loop_runner = - new content::MessageLoopRunner; - setup_info_.on_setup_complete_callback = message_loop_runner->QuitClosure(); - message_loop_runner->Run(); + base::RunLoop run_loop; + setup_info_.on_setup_complete_callback = run_loop.QuitClosure(); + run_loop.Run(); setup_info_.on_setup_complete_callback.Reset(); EXPECT_TRUE(setup_info_.setup_complete); }
diff --git a/chrome/browser/chromeos/guest_os/guest_os_share_path.cc b/chrome/browser/chromeos/guest_os/guest_os_share_path.cc index 29240b3..ffc927a5 100644 --- a/chrome/browser/chromeos/guest_os/guest_os_share_path.cc +++ b/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
@@ -632,18 +632,20 @@ return; } + // VolumeManager will be nullptr if running inside a test. + auto* vmgr = file_manager::VolumeManager::Get(profile_); + if (!vmgr) { + return; + } // If we can't find the path, check if the volume was unmounted. // FileWatchers may fire before VolumeManager::OnVolumeUnmounted. - bool volume_still_mounted = false; - const std::vector<base::WeakPtr<file_manager::Volume>>& volume_list = - file_manager::VolumeManager::Get(profile_)->GetVolumeList(); - for (const auto& volume : volume_list) { - if ((path == volume->mount_path() || volume->mount_path().IsParent(path)) && - base::PathExists(volume->mount_path())) { - volume_still_mounted = true; - break; - } - } + const auto volume_list = vmgr->GetVolumeList(); + const bool volume_still_mounted = std::any_of( + volume_list.begin(), volume_list.end(), [&path](const auto& volume) { + return (path == volume->mount_path() || + volume->mount_path().IsParent(path)) && + base::PathExists(volume->mount_path()); + }); if (!volume_still_mounted) { return; }
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc index b851d17..d6ea8e30 100644 --- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc +++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h" +#include <vector> + #include "base/bind.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" @@ -390,6 +392,10 @@ return kDefaultKerberosConfig; } +bool KerberosCredentialsManager::IsKerberosEnabled() { + return local_state_->GetBoolean(prefs::kKerberosEnabled); +} + void KerberosCredentialsManager::OnPolicyUpdated( const policy::PolicyNamespace& ns, const policy::PolicyMap& previous, @@ -450,17 +456,15 @@ LogError("AddAccountAndAuthenticate", error); - // Note: For managed accounts don't change the active principal. if (Succeeded(error)) { - // Don't change the active account if an account is added by policy. - if (!is_managed) - SetActivePrincipalName(updated_principal); - - // Set active account. + // Set active account. Be sure not to wipe user selection if the + // account was added automatically by policy. // TODO(https://crbug.com/948121): Wait until the files have been saved. // This is important when this code is triggered directly through a page // that requires Kerberos auth. - if (GetActivePrincipalName() == updated_principal) + if (!is_managed || GetActivePrincipalName().empty()) + SetActivePrincipalName(updated_principal); + else if (GetActivePrincipalName() == updated_principal) GetKerberosFiles(); // Bring the merry news to the observers, but only if there is no @@ -491,11 +495,9 @@ const kerberos::RemoveAccountResponse& response) { LogError("RemoveAccount", response.error()); if (Succeeded(response.error())) { - // Clear out active credentials. - if (GetActivePrincipalName() == principal_name) { - kerberos_files_handler_.DeleteFiles(); - ClearActivePrincipalName(); - } + // Reassign active principal if it got deleted. + if (GetActivePrincipalName() == principal_name) + ValidateActivePrincipal(); // Express our condolence to the observers. NotifyAccountsChanged(); @@ -506,19 +508,35 @@ void KerberosCredentialsManager::ClearAccounts(ResultCallback callback) { kerberos::ClearAccountsRequest request; + request.set_mode(kerberos::CLEAR_ALL); KerberosClient::Get()->ClearAccounts( request, base::BindOnce(&KerberosCredentialsManager::OnClearAccounts, - weak_factory_.GetWeakPtr(), std::move(callback))); + weak_factory_.GetWeakPtr(), request.mode(), + std::move(callback))); } void KerberosCredentialsManager::OnClearAccounts( + kerberos::ClearMode mode, ResultCallback callback, const kerberos::ClearAccountsResponse& response) { LogError("ClearAccounts", response.error()); if (Succeeded(response.error())) { - // Clear out active credentials. - kerberos_files_handler_.DeleteFiles(); - ClearActivePrincipalName(); + // Depending on the mode, we might have to check if the active principal is + // still valid. + if (!GetActivePrincipalName().empty()) { + switch (mode) { + case kerberos::CLEAR_ALL: + case kerberos::CLEAR_ONLY_MANAGED_ACCOUNTS: + case kerberos::CLEAR_ONLY_UNMANAGED_ACCOUNTS: + // Check if the active account was wiped and if so, replace it. + ValidateActivePrincipal(); + break; + + case kerberos::CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS: + // We're good, only passwords got wiped, not accounts. + break; + } + } // Tattle on the lost accounts to the observers. NotifyAccountsChanged(); @@ -538,8 +556,8 @@ ListAccountsCallback callback, const kerberos::ListAccountsResponse& response) { LogError("ListAccounts", response.error()); - // Lazily validate principal here. - ValidateActivePrincipal(response); + // Lazily validate principal here while we're at it. + DoValidateActivePrincipal(response); std::move(callback).Run(response); } @@ -548,10 +566,7 @@ if (!NormalizePrincipal(&principal_name)) return kerberos::ERROR_PARSE_PRINCIPAL_FAILED; - // Don't early out if names are equal, this might be required to bootstrap - // Kerberos credentials. SetActivePrincipalName(principal_name); - GetKerberosFiles(); NotifyAccountsChanged(); return kerberos::ERROR_NONE; } @@ -697,22 +712,35 @@ void KerberosCredentialsManager::SetActivePrincipalName( const std::string& principal_name) { + // Don't early out if names are equal, this might be required to bootstrap + // Kerberos credentials. primary_profile_->GetPrefs()->SetString(prefs::kKerberosActivePrincipalName, principal_name); + GetKerberosFiles(); } void KerberosCredentialsManager::ClearActivePrincipalName() { primary_profile_->GetPrefs()->ClearPref(prefs::kKerberosActivePrincipalName); + kerberos_files_handler_.DeleteFiles(); } -void KerberosCredentialsManager::ValidateActivePrincipal( +void KerberosCredentialsManager::ValidateActivePrincipal() { + kerberos::ListAccountsRequest request; + KerberosClient::Get()->ListAccounts( + request, + base::BindOnce(&KerberosCredentialsManager::DoValidateActivePrincipal, + weak_factory_.GetWeakPtr())); +} + +void KerberosCredentialsManager::DoValidateActivePrincipal( const kerberos::ListAccountsResponse& response) { const std::string& active_principal = GetActivePrincipalName(); bool found = false; for (int n = 0; n < response.accounts_size() && !found; ++n) found |= response.accounts(n).principal_name() == active_principal; + if (!found) { - LOG(ERROR) << "Active principal does not exist. Restoring."; + LOG(ERROR) << "Active principal got removed. Restoring."; if (response.accounts_size() > 0) SetActivePrincipalName(response.accounts(0).principal_name()); else @@ -721,15 +749,16 @@ } void KerberosCredentialsManager::UpdateEnabledFromPref() { - if (local_state_->GetBoolean(prefs::kKerberosEnabled)) { + if (IsKerberosEnabled()) { // Kerberos got enabled, re-populate managed accounts. + VLOG(1) << "Kerberos got enabled, populating managed accounts"; UpdateAccountsFromPref(); return; } // Note that ClearAccounts logs an error if the operation fails. VLOG(1) << "Kerberos got disabled, clearing accounts"; - ClearAccounts(base::BindOnce([](kerberos::ErrorType) {})); + ClearAccounts(EmptyResultCallback()); } void KerberosCredentialsManager::UpdateRememberPasswordEnabledFromPref() { @@ -740,9 +769,9 @@ kerberos::ClearAccountsRequest request; request.set_mode(kerberos::CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS); KerberosClient::Get()->ClearAccounts( - request, - base::BindOnce(&KerberosCredentialsManager::OnClearAccounts, - weak_factory_.GetWeakPtr(), EmptyResultCallback())); + request, base::BindOnce(&KerberosCredentialsManager::OnClearAccounts, + weak_factory_.GetWeakPtr(), request.mode(), + EmptyResultCallback())); } void KerberosCredentialsManager::UpdateAddAccountsAllowedFromPref() { @@ -753,27 +782,32 @@ kerberos::ClearAccountsRequest request; request.set_mode(kerberos::CLEAR_ONLY_UNMANAGED_ACCOUNTS); KerberosClient::Get()->ClearAccounts( - request, - base::BindOnce(&KerberosCredentialsManager::OnClearAccounts, - weak_factory_.GetWeakPtr(), EmptyResultCallback())); + request, base::BindOnce(&KerberosCredentialsManager::OnClearAccounts, + weak_factory_.GetWeakPtr(), request.mode(), + EmptyResultCallback())); } void KerberosCredentialsManager::UpdateAccountsFromPref() { - if (!local_state_->GetBoolean(prefs::kKerberosEnabled)) { + if (!IsKerberosEnabled()) { VLOG(1) << "Kerberos disabled"; NotifyRequiresLoginPassword(false); + // All managed accounts have already been removed here. No need to call + // RemoveAllManagedAccountsExcept(). return; } + // Principal names of all accounts added. const base::Value* accounts = local_state_->GetList(prefs::kKerberosAccounts); if (!accounts) { VLOG(1) << "No KerberosAccounts policy"; NotifyRequiresLoginPassword(false); + RemoveAllManagedAccountsExcept({}); return; } VLOG(1) << accounts->GetList().size() << " accounts in KerberosAccounts"; bool requires_login_password = false; + std::vector<std::string> managed_accounts_added; for (const auto& account : accounts->GetList()) { // Get the principal. Should always be set. const base::Value* principal_value = account.FindPath(kPrincipal); @@ -788,10 +822,6 @@ continue; } - // Kickstart active principal if it's not set yet. - if (GetActivePrincipalName().empty()) - SetActivePrincipalName(principal); - // Get the password, default to not set. const std::string* password_str = account.FindStringKey(kPassword); base::Optional<std::string> password; @@ -825,10 +855,27 @@ add_account_runners_.push_back(std::make_unique<KerberosAddAccountRunner>( this, principal, true /* is_managed */, password, remember_password, krb5_conf, true /* allow_existing */, EmptyResultCallback())); + managed_accounts_added.push_back(principal); } // Let UserSessionManager know whether it should keep the login password. NotifyRequiresLoginPassword(requires_login_password); + RemoveAllManagedAccountsExcept(std::move(managed_accounts_added)); +} + +void KerberosCredentialsManager::RemoveAllManagedAccountsExcept( + std::vector<std::string> keep_list) { + VLOG(1) << "Clearing out managed accounts except for " << keep_list.size(); + + kerberos::ClearAccountsRequest request; + request.set_mode(kerberos::CLEAR_ONLY_MANAGED_ACCOUNTS); + for (const std::string& principal_name : keep_list) + *request.add_principal_names_to_ignore() = principal_name; + + KerberosClient::Get()->ClearAccounts( + request, base::BindOnce(&KerberosCredentialsManager::OnClearAccounts, + weak_factory_.GetWeakPtr(), request.mode(), + EmptyResultCallback())); } void KerberosCredentialsManager::NotifyRequiresLoginPassword(
diff --git a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h index 73294e1..0e19b8f 100644 --- a/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h +++ b/chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h
@@ -73,6 +73,9 @@ // Returns the default Kerberos configuration (krb5.conf). static const char* GetDefaultKerberosConfig(); + // Returns true if the Kerberos feature is enabled. + bool IsKerberosEnabled(); + // PolicyService: void OnPolicyUpdated(const policy::PolicyNamespace& ns, const policy::PolicyMap& previous, @@ -160,7 +163,8 @@ const kerberos::RemoveAccountResponse& response); // Callback for ClearAccounts(). - void OnClearAccounts(ResultCallback callback, + void OnClearAccounts(kerberos::ClearMode mode, + ResultCallback callback, const kerberos::ClearAccountsResponse& response); // Callback for RemoveAccount(). @@ -201,11 +205,15 @@ void SetActivePrincipalName(const std::string& principal_name); void ClearActivePrincipalName(); + // Gets the current account list and calls DoValidateActivePrincipal(). + void ValidateActivePrincipal(); + // Checks whether the active principal is contained in the given |response|. // If not, resets it to the first principal or clears it if the list is empty. // It's not expected that this ever triggers, but it provides a fail safe if // the active principal should ever break for whatever reason. - void ValidateActivePrincipal(const kerberos::ListAccountsResponse& response); + void DoValidateActivePrincipal( + const kerberos::ListAccountsResponse& response); // Notification shown when the Kerberos ticket is about to expire. void ShowTicketExpiryNotification(); @@ -216,6 +224,12 @@ void UpdateAddAccountsAllowedFromPref(); void UpdateAccountsFromPref(); + // Does the main work for UpdateAccountsFromPref(). To clean up stale managed + // accounts, an up-to-date accounts list is needed. UpdateAccountsFromPref() + // first gets a list of accounts (asynchronously) and calls into this method + // to set new accounts and clean up old ones. + void RemoveAllManagedAccountsExcept(std::vector<std::string> keep_list); + // Informs session manager whether it needs to store the login password in the // kernel keyring. That's the case when '${PASSWORD}' is used as password in // the KerberosAccounts policy. The Kerberos daemon expands that to the login
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc index c1e128dfc..4af7571b 100644 --- a/chrome/browser/chromeos/login/existing_user_controller.cc +++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -1026,8 +1026,9 @@ l10n_util::GetStringUTF16(IDS_AUTO_LAUNCH_NOTIFICATION_BUTTON))); const base::string16 title = l10n_util::GetStringUTF16(IDS_AUTO_LAUNCH_NOTIFICATION_TITLE); - const base::string16 message = l10n_util::GetStringUTF16( - IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING); + const base::string16 message = l10n_util::GetStringFUTF16( + IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING, + base::UTF8ToUTF16(connector->GetEnterpriseDisplayDomain())); auto delegate = base::MakeRefCounted<message_center::HandleNotificationClickDelegate>( base::BindRepeating([](base::Optional<int> button_index) {
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc index fe11888..79fafcec 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc
@@ -619,8 +619,8 @@ } void UserSelectionScreen::CheckUserStatus(const AccountId& account_id) { - // No checks on lock screen. - if (ScreenLocker::default_screen_locker()) + // No checks on the multi-profiles signin or locker screen. + if (user_manager::UserManager::Get()->IsUserLoggedIn()) return; if (!token_handle_util_.get()) {
diff --git a/chrome/browser/chromeos/login/ui/login_display_mojo.cc b/chrome/browser/chromeos/login/ui/login_display_mojo.cc index aae0761..ec94c87 100644 --- a/chrome/browser/chromeos/login/ui/login_display_mojo.cc +++ b/chrome/browser/chromeos/login/ui/login_display_mojo.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" +#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" #include "chrome/browser/chromeos/login/existing_user_controller.h" #include "chrome/browser/chromeos/login/quick_unlock/pin_backend.h" #include "chrome/browser/chromeos/login/screens/chrome_user_selection_screen.h" @@ -19,6 +20,7 @@ #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/ui/ash/login_screen_client.h" #include "chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h" +#include "chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" @@ -104,10 +106,15 @@ // features (TPM firmware update) depend on system services running, which // is in turn blocked on the 'login-prompt-visible' signal. PrefService* local_state = g_browser_process->local_state(); - if (local_state->GetBoolean(prefs::kFactoryResetRequested)) + if (local_state->GetBoolean(prefs::kFactoryResetRequested)) { host_->StartWizard(ResetView::kScreenId); - else if (local_state->GetBoolean(prefs::kDebuggingFeaturesRequested)) + } else if (local_state->GetBoolean(prefs::kDebuggingFeaturesRequested)) { host_->StartWizard(EnableDebuggingScreenView::kScreenId); + } else if (!KioskAppManager::Get()->GetAutoLaunchApp().empty() && + KioskAppManager::Get()->IsAutoLaunchRequested()) { + VLOG(0) << "Showing auto-launch warning"; + host_->StartWizard(KioskAutolaunchScreenView::kScreenId); + } } }
diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc index 3b1ddfb..cae9121 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc +++ b/chrome/browser/chromeos/net/network_portal_detector_impl_browsertest.cc
@@ -55,6 +55,7 @@ constexpr char kTestUserGaiaId[] = "1234567890"; constexpr char kWifiServicePath[] = "/service/wifi"; constexpr char kWifiGuid[] = "wifi"; +constexpr char kProbeUrl[] = "http://play.googleapis.com/generate_204"; void ErrorCallbackFunction(const std::string& error_name, const std::string& error_message) { @@ -95,6 +96,10 @@ dbus::ObjectPath(kWifiServicePath), shill::kStateProperty, base::Value(shill::kStateRedirectFound), base::DoNothing(), base::Bind(&ErrorCallbackFunction)); + DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( + dbus::ObjectPath(kWifiServicePath), shill::kProbeUrlProperty, + base::Value(kProbeUrl), base::DoNothing(), + base::Bind(&ErrorCallbackFunction)); display_service_ = std::make_unique<NotificationDisplayServiceTester>( nullptr /* profile */); @@ -175,6 +180,7 @@ // No notification until portal detection is completed. EXPECT_FALSE(display_service_->GetNotification(kNotificationId)); RestartDetection(); + EXPECT_EQ(kProbeUrl, get_probe_url()); CompleteURLFetch(net::OK, 200, nullptr); // Check that wifi is marked as behind the portal and that notification
diff --git a/chrome/browser/component_updater/component_updater_prefs.cc b/chrome/browser/component_updater/component_updater_prefs.cc index 7a6604e..e9de57ac 100644 --- a/chrome/browser/component_updater/component_updater_prefs.cc +++ b/chrome/browser/component_updater/component_updater_prefs.cc
@@ -7,7 +7,11 @@ #include "chrome/browser/component_updater/chrome_component_updater_configurator.h" #include "chrome/browser/component_updater/recovery_component_installer.h" #include "chrome/browser/component_updater/recovery_improved_component_installer.h" +#include "chrome/common/buildflags.h" + +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h" +#endif namespace component_updater { @@ -15,7 +19,9 @@ RegisterPrefsForChromeComponentUpdaterConfigurator(registry); RegisterPrefsForRecoveryComponent(registry); RegisterPrefsForRecoveryImprovedComponent(registry); +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) SupervisedUserWhitelistInstaller::RegisterPrefs(registry); +#endif } } // namespace component_updater
diff --git a/chrome/browser/component_updater/safety_tips_component_installer.cc b/chrome/browser/component_updater/safety_tips_component_installer.cc new file mode 100644 index 0000000..2b98359 --- /dev/null +++ b/chrome/browser/component_updater/safety_tips_component_installer.cc
@@ -0,0 +1,150 @@ +// 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. + +#include "chrome/browser/component_updater/safety_tips_component_installer.h" + +#include <memory> +#include <utility> + +#include "base/bind.h" +#include "base/files/file_util.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/stl_util.h" +#include "base/task/post_task.h" +#include "chrome/browser/lookalikes/safety_tips/safety_tips.pb.h" +#include "chrome/browser/lookalikes/safety_tips/safety_tips_config.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" + +using component_updater::ComponentUpdateService; + +namespace { + +const base::FilePath::CharType kSafetyTipsConfigBinaryPbFileName[] = + FILE_PATH_LITERAL("safety_tips.pb"); + +// The SHA256 of the SubjectPublicKeyInfo used to sign the extension. +// The extension id is: jflookgnkcckhobaglndicnbbgbonegd +const uint8_t kSafetyTipsPublicKeySHA256[32] = { + 0x95, 0xbe, 0xea, 0x6d, 0xa2, 0x2a, 0x7e, 0x10, 0x6b, 0xd3, 0x82, + 0xd1, 0x16, 0x1e, 0xd4, 0x63, 0x21, 0xfe, 0x79, 0x5d, 0x02, 0x30, + 0xc2, 0xcf, 0x4a, 0x9c, 0x8a, 0x39, 0xcc, 0x4a, 0x00, 0xce}; + +std::unique_ptr<chrome_browser_safety_tips::SafetyTipsConfig> +LoadSafetyTipsProtoFromDisk(const base::FilePath& pb_path) { + std::string binary_pb; + if (!base::ReadFileToString(pb_path, &binary_pb)) { + // The file won't exist on new installations, so this is not always an + // error. + DVLOG(1) << "Failed reading from " << pb_path.value(); + return nullptr; + } + auto proto = std::make_unique<chrome_browser_safety_tips::SafetyTipsConfig>(); + if (!proto->ParseFromString(binary_pb)) { + DVLOG(1) << "Failed parsing proto " << pb_path.value(); + return nullptr; + } + return proto; +} + +} // namespace + +namespace component_updater { + +SafetyTipsComponentInstallerPolicy::SafetyTipsComponentInstallerPolicy() = + default; + +SafetyTipsComponentInstallerPolicy::~SafetyTipsComponentInstallerPolicy() = + default; + +bool SafetyTipsComponentInstallerPolicy:: + SupportsGroupPolicyEnabledComponentUpdates() const { + return false; +} + +bool SafetyTipsComponentInstallerPolicy::RequiresNetworkEncryption() const { + return false; +} + +update_client::CrxInstaller::Result +SafetyTipsComponentInstallerPolicy::OnCustomInstall( + const base::DictionaryValue& /* manifest */, + const base::FilePath& /* install_dir */) { + return update_client::CrxInstaller::Result(0); // Nothing custom here. +} + +void SafetyTipsComponentInstallerPolicy::OnCustomUninstall() {} + +base::FilePath SafetyTipsComponentInstallerPolicy::GetInstalledPath( + const base::FilePath& base) { + return base.Append(kSafetyTipsConfigBinaryPbFileName); +} + +void SafetyTipsComponentInstallerPolicy::ComponentReady( + const base::Version& version, + const base::FilePath& install_dir, + std::unique_ptr<base::DictionaryValue> /* manifest */) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DVLOG(1) << "Component ready, version " << version.GetString() << " in " + << install_dir.value(); + + const base::FilePath pb_path = GetInstalledPath(install_dir); + if (pb_path.empty()) + return; + + // The default proto will always be a placeholder since the updated versions + // are not checked in to the repo. Simply load whatever the component updater + // gave us without checking the default proto from the resource bundle. + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&LoadSafetyTipsProtoFromDisk, pb_path), + base::BindOnce(&safety_tips::SetProto)); +} + +// Called during startup and installation before ComponentReady(). +bool SafetyTipsComponentInstallerPolicy::VerifyInstallation( + const base::DictionaryValue& /* manifest */, + const base::FilePath& install_dir) const { + // No need to actually validate the proto here, since we'll do the checking + // in PopulateFromDynamicUpdate(). + return base::PathExists(GetInstalledPath(install_dir)); +} + +base::FilePath SafetyTipsComponentInstallerPolicy::GetRelativeInstallDir() + const { + return base::FilePath(FILE_PATH_LITERAL("SafetyTips")); +} + +void SafetyTipsComponentInstallerPolicy::GetHash( + std::vector<uint8_t>* hash) const { + hash->assign( + kSafetyTipsPublicKeySHA256, + kSafetyTipsPublicKeySHA256 + base::size(kSafetyTipsPublicKeySHA256)); +} + +std::string SafetyTipsComponentInstallerPolicy::GetName() const { + return "Safety Tips"; +} + +update_client::InstallerAttributes +SafetyTipsComponentInstallerPolicy::GetInstallerAttributes() const { + return update_client::InstallerAttributes(); +} + +std::vector<std::string> SafetyTipsComponentInstallerPolicy::GetMimeTypes() + const { + return std::vector<std::string>(); +} + +void RegisterSafetyTipsComponent(ComponentUpdateService* cus, + const base::FilePath& /* user_data_dir */) { + DVLOG(1) << "Registering Safety Tips component."; + + auto installer = base::MakeRefCounted<ComponentInstaller>( + std::make_unique<SafetyTipsComponentInstallerPolicy>()); + installer->Register(cus, base::OnceClosure()); +} + +} // namespace component_updater
diff --git a/chrome/browser/component_updater/safety_tips_component_installer.h b/chrome/browser/component_updater/safety_tips_component_installer.h new file mode 100644 index 0000000..eeeb8cab --- /dev/null +++ b/chrome/browser/component_updater/safety_tips_component_installer.h
@@ -0,0 +1,55 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_COMPONENT_UPDATER_SAFETY_TIPS_COMPONENT_INSTALLER_H_ +#define CHROME_BROWSER_COMPONENT_UPDATER_SAFETY_TIPS_COMPONENT_INSTALLER_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "base/macros.h" +#include "components/component_updater/component_installer.h" + +namespace base { +class FilePath; +} // namespace base + +namespace component_updater { + +class SafetyTipsComponentInstallerPolicy : public ComponentInstallerPolicy { + public: + SafetyTipsComponentInstallerPolicy(); + ~SafetyTipsComponentInstallerPolicy() override; + + private: + // ComponentInstallerPolicy methods: + bool SupportsGroupPolicyEnabledComponentUpdates() const override; + bool RequiresNetworkEncryption() const override; + update_client::CrxInstaller::Result OnCustomInstall( + const base::DictionaryValue& manifest, + const base::FilePath& install_dir) override; + void OnCustomUninstall() override; + bool VerifyInstallation(const base::DictionaryValue& manifest, + const base::FilePath& install_dir) const override; + void ComponentReady(const base::Version& version, + const base::FilePath& install_dir, + std::unique_ptr<base::DictionaryValue> manifest) override; + base::FilePath GetRelativeInstallDir() const override; + void GetHash(std::vector<uint8_t>* hash) const override; + std::string GetName() const override; + update_client::InstallerAttributes GetInstallerAttributes() const override; + std::vector<std::string> GetMimeTypes() const override; + + static base::FilePath GetInstalledPath(const base::FilePath& base); + + DISALLOW_COPY_AND_ASSIGN(SafetyTipsComponentInstallerPolicy); +}; + +void RegisterSafetyTipsComponent(ComponentUpdateService* cus, + const base::FilePath& user_data_dir); + +} // namespace component_updater + +#endif // CHROME_BROWSER_COMPONENT_UPDATER_SAFETY_TIPS_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/downgrade/user_data_downgrade.cc b/chrome/browser/downgrade/user_data_downgrade.cc index 9f7c3a882..c59e480 100644 --- a/chrome/browser/downgrade/user_data_downgrade.cc +++ b/chrome/browser/downgrade/user_data_downgrade.cc
@@ -110,8 +110,8 @@ if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) return; const base::Version current_version(chrome::kChromeVersion); - const base::Version downgrade_version = InstallUtil::GetDowngradeVersion(); - if (downgrade_version.IsValid() && downgrade_version > current_version) { + // Note: nullopt is always less than any value. + if (InstallUtil::GetDowngradeVersion() > current_version) { base::FilePath disk_cache_dir(GetDiskCacheDir()); // Without the browser process singleton protection, the directory may be // copied multiple times. In order to prevent that from happening, the temp
diff --git a/chrome/browser/download/download_frame_policy_browsertest.cc b/chrome/browser/download/download_frame_policy_browsertest.cc index 6d2f412..33ef238 100644 --- a/chrome/browser/download/download_frame_policy_browsertest.cc +++ b/chrome/browser/download/download_frame_policy_browsertest.cc
@@ -331,11 +331,10 @@ !enable_blocking_downloads_in_sandbox_without_user_activation || initiate_with_gesture || sandbox_option != SandboxOption::kDisallowDownloadsWithoutUserActivation; - + bool sandboxed = + sandbox_option == SandboxOption::kDisallowDownloadsWithoutUserActivation; bool expect_download_in_sandbox_without_user_activation = - sandbox_option == - SandboxOption::kDisallowDownloadsWithoutUserActivation && - !initiate_with_gesture; + sandboxed && !initiate_with_gesture; InitializeHistogramTesterAndWebFeatureWaiter(); SetNumDownloadsExpectation(expect_download); @@ -348,6 +347,10 @@ GetWebFeatureWaiter()->AddWebFeatureExpectation( blink::mojom::WebFeature::kDownloadPostPolicyCheck); } + if (sandboxed) { + GetWebFeatureWaiter()->AddWebFeatureExpectation( + blink::mojom::WebFeature::kDownloadInSandbox); + } if (expect_download_in_sandbox_without_user_activation) { GetWebFeatureWaiter()->AddWebFeatureExpectation( blink::mojom::WebFeature::kDownloadInSandboxWithoutUserGesture); @@ -423,8 +426,6 @@ bool expect_download = !enable_blocking_downloads_in_ad_frame_without_user_activation || initiate_with_gesture || !is_ad_frame; - bool expect_download_in_ad_frame_with_user_activation = - is_ad_frame && initiate_with_gesture; bool expect_download_in_ad_frame_without_user_activation = is_ad_frame && !initiate_with_gesture; @@ -439,9 +440,9 @@ GetWebFeatureWaiter()->AddWebFeatureExpectation( blink::mojom::WebFeature::kDownloadPostPolicyCheck); } - if (expect_download_in_ad_frame_with_user_activation) { + if (is_ad_frame) { GetWebFeatureWaiter()->AddWebFeatureExpectation( - blink::mojom::WebFeature::kDownloadInAdFrameWithUserGesture); + blink::mojom::WebFeature::kDownloadInAdFrame); } if (expect_download_in_ad_frame_without_user_activation) { GetWebFeatureWaiter()->AddWebFeatureExpectation( @@ -519,6 +520,8 @@ GetWebFeatureWaiter()->AddWebFeatureExpectation( blink::mojom::WebFeature::kDownloadPrePolicyCheck); + GetWebFeatureWaiter()->AddWebFeatureExpectation( + blink::mojom::WebFeature::kDownloadInSandbox); if (!expect_gesture) { GetWebFeatureWaiter()->AddWebFeatureExpectation( blink::mojom::WebFeature::kDownloadInSandboxWithoutUserGesture); @@ -631,10 +634,10 @@ GetWebFeatureWaiter()->AddWebFeatureExpectation( blink::mojom::WebFeature::kDownloadPrePolicyCheck); - if (expect_gesture) { - GetWebFeatureWaiter()->AddWebFeatureExpectation( - blink::mojom::WebFeature::kDownloadInAdFrameWithUserGesture); - } else { + GetWebFeatureWaiter()->AddWebFeatureExpectation( + blink::mojom::WebFeature::kDownloadInAdFrame); + + if (!expect_gesture) { GetWebFeatureWaiter()->AddWebFeatureExpectation( blink::mojom::WebFeature::kDownloadInAdFrameWithoutUserGesture); } @@ -724,11 +727,10 @@ !enable_blocking_downloads_in_sandbox_without_user_activation || initiate_with_gesture || sandbox_option != SandboxOption::kDisallowDownloadsWithoutUserActivation; - + bool sandboxed = + sandbox_option == SandboxOption::kDisallowDownloadsWithoutUserActivation; bool expect_download_in_sandbox_without_user_activation = - sandbox_option == - SandboxOption::kDisallowDownloadsWithoutUserActivation && - !initiate_with_gesture; + sandboxed && !initiate_with_gesture; InitializeHistogramTesterAndWebFeatureWaiter(); SetNumDownloadsExpectation(expect_download); @@ -740,6 +742,10 @@ GetWebFeatureWaiter()->AddWebFeatureExpectation( blink::mojom::WebFeature::kDownloadPostPolicyCheck); } + if (sandboxed) { + GetWebFeatureWaiter()->AddWebFeatureExpectation( + blink::mojom::WebFeature::kDownloadInSandbox); + } if (expect_download_in_sandbox_without_user_activation) { GetWebFeatureWaiter()->AddWebFeatureExpectation( blink::mojom::WebFeature::kDownloadInSandboxWithoutUserGesture);
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index 0a86a59..e26b2ba 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -770,6 +770,7 @@ ] deps = [ "//apps", + "//build:branding_buildflags", "//chrome:extra_resources", "//chrome:resources", "//chrome:strings",
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc index c871542..42b5813 100644 --- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc +++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
@@ -67,6 +67,7 @@ const char kCertificateProviderNoActiveDialog[] = "No active dialog from extension."; const char kCertificateProviderInvalidId[] = "Invalid signRequestId"; +const char kCertificateProviderInvalidAttemptsLeft[] = "Invalid attemptsLeft"; const char kCertificateProviderOtherFlowInProgress[] = "Other flow in progress"; const char kCertificateProviderPreviousDialogActive[] = "Previous request not finished"; @@ -292,8 +293,13 @@ browser_context()); DCHECK(service); - int attempts_left = - params->details.attempts_left ? *params->details.attempts_left : -1; + int attempts_left = -1; + if (params->details.attempts_left) { + if (*params->details.attempts_left < 0) + return RespondNow(Error(kCertificateProviderInvalidAttemptsLeft)); + attempts_left = *params->details.attempts_left; + } + const chromeos::PinDialogManager::RequestPinResult result = service->pin_dialog_manager()->RequestPin( extension()->id(), extension()->name(),
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc index c69cff3..2a26615 100644 --- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc +++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
@@ -569,6 +569,16 @@ EXPECT_TRUE(listener.WaitUntilSatisfied()); } +// Extension erroneously passes a negative attempts left count. +IN_PROC_BROWSER_TEST_F(CertificateProviderRequestPinTest, NegativeAttempts) { + AddFakeSignRequest(); + NavigateTo("operated.html"); + + EXPECT_TRUE(SendCommandAndWaitForMessage( + "RequestWithNegativeAttempts", "request1:error:Invalid attemptsLeft")); + EXPECT_FALSE(GetActivePinDialogView()); +} + // Extension erroneously attempts to close a non-existing dialog. IN_PROC_BROWSER_TEST_F(CertificateProviderRequestPinTest, CloseNonExisting) { AddFakeSignRequest();
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chrome/browser/extensions/api/extension_action/extension_action_api.cc index a9f1a55e..ef0c3b6b 100644 --- a/chrome/browser/extensions/api/extension_action/extension_action_api.cc +++ b/chrome/browser/extensions/api/extension_action/extension_action_api.cc
@@ -32,7 +32,6 @@ #include "chrome/common/extensions/api/extension_action/action_info.h" #include "content/public/browser/notification_service.h" #include "extensions/browser/event_router.h" -#include "extensions/browser/extension_function_registry.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_util.h" @@ -90,24 +89,7 @@ DestructorAtExit g_extension_action_api_factory = LAZY_INSTANCE_INITIALIZER; ExtensionActionAPI::ExtensionActionAPI(content::BrowserContext* context) - : browser_context_(context), - extension_prefs_(nullptr) { - ExtensionFunctionRegistry& registry = - ExtensionFunctionRegistry::GetInstance(); - - // Actions - // TODO(devlin): Remove this bespoke registration when action.enable() and - // action.disable() have appropriate tests. - registry.RegisterFunction<ActionSetIconFunction>(); - registry.RegisterFunction<ActionGetPopupFunction>(); - registry.RegisterFunction<ActionSetPopupFunction>(); - registry.RegisterFunction<ActionGetTitleFunction>(); - registry.RegisterFunction<ActionSetTitleFunction>(); - registry.RegisterFunction<ActionGetBadgeTextFunction>(); - registry.RegisterFunction<ActionSetBadgeTextFunction>(); - registry.RegisterFunction<ActionGetBadgeBackgroundColorFunction>(); - registry.RegisterFunction<ActionSetBadgeBackgroundColorFunction>(); -} + : browser_context_(context), extension_prefs_(nullptr) {} ExtensionActionAPI::~ExtensionActionAPI() { }
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_api.h b/chrome/browser/extensions/api/extension_action/extension_action_api.h index 63b1accf..f4d9ea2 100644 --- a/chrome/browser/extensions/api/extension_action/extension_action_api.h +++ b/chrome/browser/extensions/api/extension_action/extension_action_api.h
@@ -330,7 +330,21 @@ ~ActionSetBadgeBackgroundColorFunction() override {} }; -// TODO(devlin): Add the rest of the action APIs here. +class ActionEnableFunction : public ExtensionActionShowFunction { + public: + DECLARE_EXTENSION_FUNCTION("action.enable", ACTION_ENABLE) + + protected: + ~ActionEnableFunction() override {} +}; + +class ActionDisableFunction : public ExtensionActionHideFunction { + public: + DECLARE_EXTENSION_FUNCTION("action.disable", ACTION_DISABLE) + + protected: + ~ActionDisableFunction() override {} +}; // // browserAction.* aliases for supported browserAction APIs.
diff --git a/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc b/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc index 8a6c1f5..c90241d 100644 --- a/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc +++ b/chrome/browser/extensions/api/extension_action/extension_action_apitest.cc
@@ -234,8 +234,7 @@ } // Ensures the |action| is enabled on the tab with the given |tab_id|. - void EnsureActionIsEnabledOnActiveTab(ExtensionAction* action) { - const int tab_id = GetActiveTabId(); + void EnsureActionIsEnabledOnTab(ExtensionAction* action, int tab_id) { if (action->GetIsVisible(tab_id)) return; action->SetIsVisible(tab_id, true); @@ -246,6 +245,11 @@ extension_action_api->NotifyChange(action, GetActiveTab(), profile()); } + // Ensures the |action| is enabled on the currently-active tab. + void EnsureActionIsEnabledOnActiveTab(ExtensionAction* action) { + EnsureActionIsEnabledOnTab(action, GetActiveTabId()); + } + // Returns the id of the currently-active tab. int GetActiveTabId() const { content::WebContents* web_contents = GetActiveTab(); @@ -912,6 +916,121 @@ } } +// Tests the functions to enable and disable extension actions. +IN_PROC_BROWSER_TEST_P(MultiActionAPITest, EnableAndDisable) { + constexpr char kManifestTemplate[] = + R"({ + "name": "enabled/disabled action test", + "version": "0.1", + "manifest_version": 2, + "%s": {}, + "background": {"scripts": ["background.js"]} + })"; + + TestExtensionDir test_dir; + test_dir.WriteManifest( + base::StringPrintf(kManifestTemplate, GetManifestKey(GetParam()))); + test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), + "// This space left blank."); + const Extension* extension = LoadExtension(test_dir.UnpackedPath()); + ASSERT_TRUE(extension); + ExtensionAction* action = GetExtensionAction(*extension); + ASSERT_TRUE(action); + + const int tab_id1 = GetActiveTabId(); + EnsureActionIsEnabledOnTab(action, tab_id1); + + ui_test_utils::NavigateToURLWithDisposition( + browser(), GURL("chrome://newtab"), + WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + + const int tab_id2 = GetActiveTabId(); + EnsureActionIsEnabledOnTab(action, tab_id2); + + EXPECT_NE(tab_id1, tab_id2); + + const char* enable_function = nullptr; + const char* disable_function = nullptr; + switch (GetParam()) { + case ActionInfo::TYPE_ACTION: + case ActionInfo::TYPE_BROWSER: + enable_function = "enable"; + disable_function = "disable"; + break; + case ActionInfo::TYPE_PAGE: + enable_function = "show"; + disable_function = "hide"; + break; + } + + // Start by toggling the extension action on the current tab. + { + constexpr char kScriptTemplate[] = + R"(chrome.%s.%s(%d, () => { + chrome.test.assertNoLastError(); + chrome.test.notifyPass(); + });)"; + RunTestAndWaitForSuccess( + profile(), extension->id(), + base::StringPrintf(kScriptTemplate, GetAPIName(GetParam()), + disable_function, tab_id2)); + EXPECT_FALSE(action->GetIsVisible(tab_id2)); + EXPECT_TRUE(action->GetIsVisible(tab_id1)); + } + + { + constexpr char kScriptTemplate[] = + R"(chrome.%s.%s(%d, () => { + chrome.test.assertNoLastError(); + chrome.test.notifyPass(); + });)"; + RunTestAndWaitForSuccess( + profile(), extension->id(), + base::StringPrintf(kScriptTemplate, GetAPIName(GetParam()), + enable_function, tab_id2)); + EXPECT_TRUE(action->GetIsVisible(tab_id2)); + EXPECT_TRUE(action->GetIsVisible(tab_id1)); + } + + // Page actions can't be enabled/disabled globally, but others can. Try + // toggling global state by omitting the tab id if the type isn't a page + // action. + if (GetParam() == ActionInfo::TYPE_PAGE) + return; + + // We need to undo the explicit enable from above, since tab-specific + // values take precedence. + action->ClearAllValuesForTab(tab_id2); + { + constexpr char kScriptTemplate[] = + R"(chrome.%s.%s(() => { + chrome.test.assertNoLastError(); + chrome.test.notifyPass(); + });)"; + RunTestAndWaitForSuccess( + profile(), extension->id(), + base::StringPrintf(kScriptTemplate, GetAPIName(GetParam()), + disable_function)); + EXPECT_EQ(false, action->GetIsVisible(tab_id2)); + EXPECT_EQ(false, action->GetIsVisible(tab_id1)); + } + + { + constexpr char kScriptTemplate[] = + R"(chrome.%s.%s(() => { + chrome.test.assertNoLastError(); + chrome.test.notifyPass(); + });)"; + RunTestAndWaitForSuccess( + profile(), extension->id(), + base::StringPrintf(kScriptTemplate, GetAPIName(GetParam()), + enable_function)); + EXPECT_EQ(true, action->GetIsVisible(tab_id2)); + EXPECT_EQ(true, action->GetIsVisible(tab_id1)); + } +} + INSTANTIATE_TEST_SUITE_P(, MultiActionAPITest, testing::Values(ActionInfo::TYPE_ACTION,
diff --git a/chrome/browser/extensions/api/management/management_api_non_persistent_apitest.cc b/chrome/browser/extensions/api/management/management_api_non_persistent_apitest.cc index 312afc2b..af20dd9 100644 --- a/chrome/browser/extensions/api/management/management_api_non_persistent_apitest.cc +++ b/chrome/browser/extensions/api/management/management_api_non_persistent_apitest.cc
@@ -51,10 +51,6 @@ // Tests chrome.management.uninstallSelf API. IN_PROC_BROWSER_TEST_P(ManagementApiNonPersistentApiTest, UninstallSelf) { - if (GetParam() == ContextType::kEventPage) { - // Test has been flaky on all platforms. https://crbug.com/985936. - return; - } constexpr char kEventPageBackgroundScript[] = R"({"scripts": ["script.js"]})"; constexpr char kServiceWorkerBackgroundScript[] = R"({"service_worker": "script.js"})"; @@ -86,7 +82,9 @@ extensions::ExtensionRegistry::Get(browser()->profile())); base::FilePath path = test_dir.Pack(); - scoped_refptr<const Extension> extension = LoadExtension(path); + // NOTE: Do not use a scoped_refptr<Extension> as the |extension| might get + // uninstalled right away. + const Extension* extension = LoadExtension(path); EXPECT_EQ(extension, observer.WaitForExtensionUninstalled()); }
diff --git a/chrome/browser/extensions/chrome_process_manager_delegate.cc b/chrome/browser/extensions/chrome_process_manager_delegate.cc index 9d7ba9e9..e79841d 100644 --- a/chrome/browser/extensions/chrome_process_manager_delegate.cc +++ b/chrome/browser/extensions/chrome_process_manager_delegate.cc
@@ -15,6 +15,7 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_list.h" #include "chrome/common/chrome_switches.h" #include "components/user_manager/user_manager.h" #include "content/public/browser/notification_service.h" @@ -33,8 +34,7 @@ namespace extensions { ChromeProcessManagerDelegate::ChromeProcessManagerDelegate() { - registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, - content::NotificationService::AllSources()); + BrowserList::AddObserver(this); registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, content::NotificationService::AllSources()); @@ -44,6 +44,7 @@ } ChromeProcessManagerDelegate::~ChromeProcessManagerDelegate() { + BrowserList::RemoveObserver(this); } bool ChromeProcessManagerDelegate::AreBackgroundPagesAllowedForContext( @@ -111,7 +112,7 @@ // There are no browser windows open and the browser process was // started to show the app launcher. Background hosts will be loaded later - // via NOTIFICATION_BROWSER_OPENED. http://crbug.com/178260 + // via OnBrowserAdded(). http://crbug.com/178260 return chrome::GetBrowserCount(profile) == 0 && base::CommandLine::ForCurrentProcess()->HasSwitch( ::switches::kShowAppList); @@ -122,11 +123,6 @@ const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { - case chrome::NOTIFICATION_BROWSER_OPENED: { - Browser* browser = content::Source<Browser>(source).ptr(); - OnBrowserOpened(browser); - break; - } case chrome::NOTIFICATION_PROFILE_CREATED: { Profile* profile = content::Source<Profile>(source).ptr(); OnProfileCreated(profile); @@ -142,7 +138,7 @@ } } -void ChromeProcessManagerDelegate::OnBrowserOpened(Browser* browser) { +void ChromeProcessManagerDelegate::OnBrowserAdded(Browser* browser) { Profile* profile = browser->profile(); DCHECK(profile);
diff --git a/chrome/browser/extensions/chrome_process_manager_delegate.h b/chrome/browser/extensions/chrome_process_manager_delegate.h index bc670a6..f4bac25c 100644 --- a/chrome/browser/extensions/chrome_process_manager_delegate.h +++ b/chrome/browser/extensions/chrome_process_manager_delegate.h
@@ -7,6 +7,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" +#include "chrome/browser/ui/browser_list_observer.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "extensions/browser/process_manager_delegate.h" @@ -19,12 +20,13 @@ // Support for ProcessManager. Controls cases where Chrome wishes to disallow // extension background pages or defer their creation. class ChromeProcessManagerDelegate : public ProcessManagerDelegate, - public content::NotificationObserver { + public content::NotificationObserver, + public BrowserListObserver { public: ChromeProcessManagerDelegate(); ~ChromeProcessManagerDelegate() override; - // ProcessManagerDelegate implementation: + // ProcessManagerDelegate: bool AreBackgroundPagesAllowedForContext( content::BrowserContext* context) const override; bool IsExtensionBackgroundPageAllowed( @@ -33,14 +35,16 @@ bool DeferCreatingStartupBackgroundHosts( content::BrowserContext* context) const override; - // content::NotificationObserver implementation: + // content::NotificationObserver: void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) override; + // BrowserListObserver: + void OnBrowserAdded(Browser* browser) override; + private: // Notification handlers. - void OnBrowserOpened(Browser* browser); void OnProfileCreated(Profile* profile); void OnProfileDestroyed(Profile* profile);
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc index 02c665c..a83f450 100644 --- a/chrome/browser/extensions/extension_prefs_unittest.cc +++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -1097,4 +1097,40 @@ TEST_F(ExtensionPrefsRuntimeGrantedPermissions, ExtensionPrefsRuntimeGrantedPermissions) {} +// Tests the removal of obsolete keys from extension pref entries. +class ExtensionPrefsObsoletePrefRemoval : public ExtensionPrefsTest { + public: + ExtensionPrefsObsoletePrefRemoval() = default; + ~ExtensionPrefsObsoletePrefRemoval() override = default; + + void Initialize() override { + extension_ = prefs_.AddExtension("a"); + constexpr char kTestValue[] = "test_value"; + prefs()->UpdateExtensionPref(extension_->id(), + ExtensionPrefs::kFakeObsoletePrefForTesting, + std::make_unique<base::Value>(kTestValue)); + std::string str_value; + EXPECT_TRUE(prefs()->ReadPrefAsString( + extension_->id(), ExtensionPrefs::kFakeObsoletePrefForTesting, + &str_value)); + EXPECT_EQ(kTestValue, str_value); + + prefs()->MigrateObsoleteExtensionPrefs(); + } + + void Verify() override { + std::string str_value; + EXPECT_FALSE(prefs()->ReadPrefAsString( + extension_->id(), ExtensionPrefs::kFakeObsoletePrefForTesting, + &str_value)); + } + + private: + scoped_refptr<const Extension> extension_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionPrefsObsoletePrefRemoval); +}; + +TEST_F(ExtensionPrefsObsoletePrefRemoval, ExtensionPrefsObsoletePrefRemoval) {} + } // namespace extensions
diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc index 8c45fd7..2ed99c2d 100644 --- a/chrome/browser/extensions/extension_service_sync_unittest.cc +++ b/chrome/browser/extensions/extension_service_sync_unittest.cc
@@ -86,15 +86,18 @@ namespace { -const char autoupdate[] = "ogjcoiohnmldgjemafoockdghcjciccf"; const char good0[] = "behllobkkfkfnphdnhnkndlbkcpglgmj"; const char good2[] = "bjafgdebaacbbbecmhlhpofkepfkgcpa"; -const char good2048[] = "dfhpodpjggiioolfhoimofdbfjibmedp"; const char good_crx[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; const char page_action[] = "obcimlgaoabeegjmmpldobjndiealpln"; -const char permissions_increase[] = "pgdpcfcocojkjfbgpiianjngphoopgmo"; const char theme2_crx[] = "ibcijncamhmjjdodjamgiipcgnnaeagd"; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +const char autoupdate[] = "ogjcoiohnmldgjemafoockdghcjciccf"; +const char good2048[] = "dfhpodpjggiioolfhoimofdbfjibmedp"; +const char permissions_increase[] = "pgdpcfcocojkjfbgpiianjngphoopgmo"; +#endif + ExtensionSyncData GetDisableSyncData(const Extension& extension, int disable_reasons) { bool enabled = false;
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc index 855468eb..8e9ffd2 100644 --- a/chrome/browser/extensions/external_provider_impl.cc +++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -20,6 +20,7 @@ #include "base/trace_event/trace_event.h" #include "base/values.h" #include "base/version.h" +#include "build/branding_buildflags.h" #include "build/build_config.h" #include "chrome/browser/app_mode/app_mode_utils.h" #include "chrome/browser/browser_process.h" @@ -782,7 +783,7 @@ bundled_extension_creation_flags)); // Define a per-user source of external extensions. -#if defined(OS_MACOSX) || (defined(OS_LINUX) && defined(CHROMIUM_BUILD)) +#if defined(OS_MACOSX) || (defined(OS_LINUX) && BUILDFLAG(CHROMIUM_BRANDING)) provider_list->push_back(std::make_unique<ExternalProviderImpl>( service, new ExternalPrefLoader(chrome::DIR_USER_EXTERNAL_EXTENSIONS,
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 0dd8dc6..264ed9c 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1524,6 +1524,11 @@ "expiry_milestone": 80 }, { + "name": "enable-process-sharing-with-default-site-instances", + "owners": [ "acolwell" ], + "expiry_milestone": 81 + }, + { "name": "enable-process-sharing-with-strict-site-instances", "owners": [ "japhet" ], "expiry_milestone": 80 @@ -1569,6 +1574,11 @@ "expiry_milestone": 80 }, { + "name": "enable-filtering-scroll-events", + "owners": [ "axantoine", "eirage", "nzolghadr", "input-dev" ], + "expiry_milestone": 80 + }, + { "name": "enable-resource-load-scheduler", "owners": [ "toyoshim" ], "expiry_milestone": 78 @@ -2535,11 +2545,6 @@ "expiry_milestone": 80 }, { - "name": "omnibox-new-answer-layout", - "owners": [ "chrome-omnibox-team@google.com" ], - "expiry_milestone": 76 - }, - { "name": "omnibox-on-device-head-suggestions", "owners": [ "cechen", "suggest-2g@google.com" ], "expiry_milestone": 80 @@ -3229,6 +3234,11 @@ "name": "enable-streamlined-usb-printer-setup", "owners": [ "baileyberro" ], "expiry_milestone": 77 + }, + { + "name": "update-hover-at-begin-frame", + "owners": [ "lanwei", "input-dev" ], + "expiry_milestone": 81 } // This is an alphabetized list; please do your part to keep it organized by
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index ec94e32..5f751702 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -1035,6 +1035,10 @@ "Enables granting and removing access to features through the " "Feature-Policy HTTP header."; +const char kFilteringScrollPredictionName[] = "Filtering scroll prediction"; +const char kFilteringScrollPredictionDescription[] = + "Enable filtering of predicted scroll events"; + const char kForceEffectiveConnectionTypeName[] = "Override effective connection type"; const char kForceEffectiveConnectionTypeDescription[] = @@ -1304,6 +1308,11 @@ "Enable support for using the native notification toasts and notification " "center on platforms where these are available."; +const char kUpdateHoverAtBeginFrameName[] = "Update hover at the begin frame"; +const char kUpdateHoverAtBeginFrameDescription[] = + "Recompute hover state at BeginFrame for layout and scroll based mouse " + "moves, rather than old timing-based mechanism."; + const char kUseMultiloginEndpointName[] = "Use Multilogin endpoint."; const char kUseMultiloginEndpointDescription[] = "Use Gaia OAuth multilogin for identity consistency."; @@ -1346,10 +1355,6 @@ "Use material design weather icons in the omnibox when displaying weather " "answers."; -const char kOmniboxNewAnswerLayoutName[] = "Omnibox new answer layout"; -const char kOmniboxNewAnswerLayoutDescription[] = - "Modernize omnibox answers using an enhanced layout with larger icons."; - const char kOmniboxRichEntitySuggestionsName[] = "Omnibox rich entity suggestions"; const char kOmniboxRichEntitySuggestionsDescription[] = @@ -2501,6 +2506,16 @@ const char kPasswordManagerOnboardingAndroidDescription[] = "This flag enables showing the password manager onboarding experience."; +extern const char kProcessSharingWithDefaultSiteInstancesName[] = + "Process sharing with default site instances"; +extern const char kProcessSharingWithDefaultSiteInstancesDescription[] = + "When site isolation is disabled, this mode changes how sites are lumped " + "in to shared processes. For sites that do not require isolation, this " + "feature groups them into a single 'default' site instance (per browsing " + "instance) instead of creating unique site instances for each one. This " + "enables resource savings by creating fewer processes for sites that do " + "not need isolation."; + extern const char kProcessSharingWithStrictSiteInstancesName[] = "Process sharing with strict site instances"; extern const char kProcessSharingWithStrictSiteInstancesDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index d4230b8..d17b825 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -614,6 +614,9 @@ extern const char kFeaturePolicyName[]; extern const char kFeaturePolicyDescription[]; +extern const char kFilteringScrollPredictionName[]; +extern const char kFilteringScrollPredictionDescription[]; + extern const char kForceEffectiveConnectionTypeName[]; extern const char kForceEffectiveConnectionTypeDescription[]; extern const char kEffectiveConnectionTypeUnknownDescription[]; @@ -815,9 +818,6 @@ extern const char kOmniboxMaterialDesignWeatherIconsName[]; extern const char kOmniboxMaterialDesignWeatherIconsDescription[]; -extern const char kOmniboxNewAnswerLayoutName[]; -extern const char kOmniboxNewAnswerLayoutDescription[]; - extern const char kOmniboxRichEntitySuggestionsName[]; extern const char kOmniboxRichEntitySuggestionsDescription[]; @@ -898,6 +898,9 @@ extern const char kOverlayStrategiesUnoccluded[]; extern const char kOverlayStrategiesOccludedAndUnoccluded[]; +extern const char kUpdateHoverAtBeginFrameName[]; +extern const char kUpdateHoverAtBeginFrameDescription[]; + extern const char kUseNewAcceptLanguageHeaderName[]; extern const char kUseNewAcceptLanguageHeaderDescription[]; @@ -1480,6 +1483,9 @@ extern const char kPasswordManagerOnboardingAndroidName[]; extern const char kPasswordManagerOnboardingAndroidDescription[]; +extern const char kProcessSharingWithDefaultSiteInstancesName[]; +extern const char kProcessSharingWithDefaultSiteInstancesDescription[]; + extern const char kProcessSharingWithStrictSiteInstancesName[]; extern const char kProcessSharingWithStrictSiteInstancesDescription[];
diff --git a/chrome/browser/installable/installable_logging.cc b/chrome/browser/installable/installable_logging.cc index 2fd33da..a3b53188 100644 --- a/chrome/browser/installable/installable_logging.cc +++ b/chrome/browser/installable/installable_logging.cc
@@ -30,7 +30,7 @@ static const char kManifestMissingSuitableIconMessage[] = "Manifest does not contain a suitable icon - PNG format of at least " "%dpx is required, the sizes attribute must be set, and the purpose " - "attribute, if set, must include \"any\"."; + "attribute, if set, must include \"any\" or \"maskable\"."; static const char kNoMatchingServiceWorkerMessage[] = "No matching service worker detected. You may need to reload the page, or " "check that the service worker for the current page also controls the "
diff --git a/chrome/browser/installable/installable_manager.cc b/chrome/browser/installable/installable_manager.cc index 64c3808..6bbb97e 100644 --- a/chrome/browser/installable/installable_manager.cc +++ b/chrome/browser/installable/installable_manager.cc
@@ -72,9 +72,13 @@ using IconPurpose = blink::Manifest::ImageResource::Purpose; -// Returns true if |manifest| specifies a PNG icon with IconPurpose::ANY and of -// height and width >= kMinimumPrimaryIconSizeInPx (or size "any"). -bool DoesManifestContainRequiredIcon(const blink::Manifest& manifest) { +// Returns true if |manifest| specifies a PNG icon of height and width >= +// kMinimumPrimaryIconSizeInPx (or size "any"), and either +// 1. with IconPurpose::ANY or IconPurpose::MASKABLE, if maskable icon is +// preferred, or +// 2. with IconPurpose::ANY if maskable icon is not preferred. +bool DoesManifestContainRequiredIcon(const blink::Manifest& manifest, + bool prefer_maskable_icon) { for (const auto& icon : manifest.icons) { // The type field is optional. If it isn't present, fall back on checking // the src extension, and allow the icon if the extension ends with png. @@ -84,8 +88,12 @@ base::CompareCase::INSENSITIVE_ASCII))) continue; - if (!base::Contains(icon.purpose, - blink::Manifest::ImageResource::Purpose::ANY)) { + if (!(base::Contains(icon.purpose, + blink::Manifest::ImageResource::Purpose::ANY) || + (prefer_maskable_icon && + base::Contains( + icon.purpose, + blink::Manifest::ImageResource::Purpose::MASKABLE)))) { continue; } @@ -445,7 +453,8 @@ CheckAndFetchBestIcon(GetIdealPrimaryIconSizeInPx(), GetMinimumPrimaryIconSizeInPx(), IconPurpose::ANY); } else if (params.valid_manifest && !valid_manifest_->fetched) { - CheckManifestValid(params.check_webapp_manifest_display); + CheckManifestValid(params.check_webapp_manifest_display, + params.prefer_maskable_icon); } else if (params.has_worker && !worker_->fetched) { CheckServiceWorker(); } else if (params.valid_badge_icon && !IsIconFetched(IconPurpose::BADGE)) { @@ -503,20 +512,21 @@ WorkOnTask(); } -void InstallableManager::CheckManifestValid( - bool check_webapp_manifest_display) { +void InstallableManager::CheckManifestValid(bool check_webapp_manifest_display, + bool prefer_maskable_icon) { DCHECK(!valid_manifest_->fetched); DCHECK(!manifest().IsEmpty()); - valid_manifest_->is_valid = - IsManifestValidForWebApp(manifest(), check_webapp_manifest_display); + valid_manifest_->is_valid = IsManifestValidForWebApp( + manifest(), check_webapp_manifest_display, prefer_maskable_icon); valid_manifest_->fetched = true; WorkOnTask(); } bool InstallableManager::IsManifestValidForWebApp( const blink::Manifest& manifest, - bool check_webapp_manifest_display) { + bool check_webapp_manifest_display, + bool prefer_maskable_icon) { bool is_valid = true; if (manifest.IsEmpty()) { valid_manifest_->errors.push_back(MANIFEST_EMPTY); @@ -542,7 +552,7 @@ is_valid = false; } - if (!DoesManifestContainRequiredIcon(manifest)) { + if (!DoesManifestContainRequiredIcon(manifest, prefer_maskable_icon)) { valid_manifest_->errors.push_back(MANIFEST_MISSING_SUITABLE_ICON); is_valid = false; }
diff --git a/chrome/browser/installable/installable_manager.h b/chrome/browser/installable/installable_manager.h index 3803405f..d614b3d 100644 --- a/chrome/browser/installable/installable_manager.h +++ b/chrome/browser/installable/installable_manager.h
@@ -189,9 +189,11 @@ void OnDidGetManifest(const GURL& manifest_url, const blink::Manifest& manifest); - void CheckManifestValid(bool check_webapp_manifest_display); + void CheckManifestValid(bool check_webapp_manifest_display, + bool prefer_maskable_icon); bool IsManifestValidForWebApp(const blink::Manifest& manifest, - bool check_webapp_manifest_display); + bool check_webapp_manifest_display, + bool prefer_maskable_icon); void CheckServiceWorker(); void OnDidCheckHasServiceWorker(content::ServiceWorkerCapability capability);
diff --git a/chrome/browser/installable/installable_manager_unittest.cc b/chrome/browser/installable/installable_manager_unittest.cc index 4ae9bbb..f19c4688 100644 --- a/chrome/browser/installable/installable_manager_unittest.cc +++ b/chrome/browser/installable/installable_manager_unittest.cc
@@ -39,11 +39,12 @@ } bool IsManifestValid(const blink::Manifest& manifest, - bool check_webapp_manifest_display = true) { + bool check_webapp_manifest_display = true, + bool prefer_maskable_icon = false) { // Explicitly reset the error code before running the method. manager_->set_valid_manifest_error(NO_ERROR_DETECTED); - return manager_->IsManifestValidForWebApp(manifest, - check_webapp_manifest_display); + return manager_->IsManifestValidForWebApp( + manifest, check_webapp_manifest_display, prefer_maskable_icon); } InstallableStatusCode GetErrorCode() { @@ -153,6 +154,32 @@ EXPECT_EQ(NO_ERROR_DETECTED, GetErrorCode()); } +TEST_F(InstallableManagerUnitTest, + ManifestRequiresPurposeAnyOrMaskableWhenPreferringMaskable) { + blink::Manifest manifest = GetValidManifest(); + + EXPECT_TRUE(IsManifestValid(manifest, true, true)); + EXPECT_EQ(NO_ERROR_DETECTED, GetErrorCode()); + + manifest.icons[0].purpose[0] = IconPurpose::MASKABLE; + EXPECT_TRUE(IsManifestValid(manifest, true, true)); + EXPECT_EQ(NO_ERROR_DETECTED, GetErrorCode()); + + // The icon MUST have IconPurpose::ANY or IconPurpose::Maskable. + manifest.icons[0].purpose[0] = IconPurpose::BADGE; + EXPECT_FALSE(IsManifestValid(manifest, true, true)); + EXPECT_EQ(MANIFEST_MISSING_SUITABLE_ICON, GetErrorCode()); + + // If one of the icon purposes match the requirement, it should be accepted. + manifest.icons[0].purpose.push_back(IconPurpose::ANY); + EXPECT_TRUE(IsManifestValid(manifest, true, true)); + EXPECT_EQ(NO_ERROR_DETECTED, GetErrorCode()); + + manifest.icons[0].purpose[1] = IconPurpose::MASKABLE; + EXPECT_TRUE(IsManifestValid(manifest, true, true)); + EXPECT_EQ(NO_ERROR_DETECTED, GetErrorCode()); +} + TEST_F(InstallableManagerUnitTest, ManifestRequiresMinimalSize) { blink::Manifest manifest = GetValidManifest();
diff --git a/chrome/browser/lookalikes/safety_tips/safety_tips_config.cc b/chrome/browser/lookalikes/safety_tips/safety_tips_config.cc new file mode 100644 index 0000000..d673226 --- /dev/null +++ b/chrome/browser/lookalikes/safety_tips/safety_tips_config.cc
@@ -0,0 +1,37 @@ +// 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. + +#include "chrome/browser/lookalikes/safety_tips/safety_tips_config.h" + +#include "base/no_destructor.h" + +namespace { + +class SafetyTipsConfigSingleton { + public: + void SetProto( + std::unique_ptr<chrome_browser_safety_tips::SafetyTipsConfig> proto) { + proto_ = std::move(proto); + } + + static SafetyTipsConfigSingleton& GetInstance() { + static base::NoDestructor<SafetyTipsConfigSingleton> instance; + return *instance; + } + + private: + std::unique_ptr<chrome_browser_safety_tips::SafetyTipsConfig> proto_; +}; + +} // namespace + +namespace safety_tips { + +// static +void SetProto( + std::unique_ptr<chrome_browser_safety_tips::SafetyTipsConfig> proto) { + SafetyTipsConfigSingleton::GetInstance().SetProto(std::move(proto)); +} + +} // namespace safety_tips
diff --git a/chrome/browser/lookalikes/safety_tips/safety_tips_config.h b/chrome/browser/lookalikes/safety_tips/safety_tips_config.h new file mode 100644 index 0000000..f084d2f --- /dev/null +++ b/chrome/browser/lookalikes/safety_tips/safety_tips_config.h
@@ -0,0 +1,22 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_LOOKALIKES_SAFETY_TIPS_SAFETY_TIPS_CONFIG_H_ +#define CHROME_BROWSER_LOOKALIKES_SAFETY_TIPS_SAFETY_TIPS_CONFIG_H_ + +#include <memory> + +#include "chrome/browser/lookalikes/safety_tips/safety_tips.pb.h" + +namespace safety_tips { + +// Sets the global configuration for Safety Tips retrieved from the component +// updater. The configuration proto contains the list of URLs that can trigger +// a safety tip. +void SetProto( + std::unique_ptr<chrome_browser_safety_tips::SafetyTipsConfig> proto); + +} // namespace safety_tips + +#endif // CHROME_BROWSER_LOOKALIKES_SAFETY_TIPS_SAFETY_TIPS_CONFIG_H_
diff --git a/chrome/browser/mac/keystone_glue.mm b/chrome/browser/mac/keystone_glue.mm index 985fd3e2..ba76413 100644 --- a/chrome/browser/mac/keystone_glue.mm +++ b/chrome/browser/mac/keystone_glue.mm
@@ -24,6 +24,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/task/post_task.h" #include "base/version.h" +#include "build/branding_buildflags.h" #include "build/build_config.h" #import "chrome/browser/mac/keystone_registration.h" #include "chrome/common/channel_info.h" @@ -44,7 +45,7 @@ #if defined(GOOGLE_CHROME_BUILD) #define kStableBrandFileName @"Google Chrome Brand.plist" #define kCanaryBrandFileName @"Google Chrome Canary Brand.plist" -#elif defined(CHROMIUM_BUILD) +#elif BUILDFLAG(CHROMIUM_BRANDING) #define kStableBrandFileName @"Chromium Brand.plist" #define kCanaryBrandFileName @"Chromium Canary Brand.plist" #else
diff --git a/chrome/browser/media/router/BUILD.gn b/chrome/browser/media/router/BUILD.gn index 1689408..29707ed 100644 --- a/chrome/browser/media/router/BUILD.gn +++ b/chrome/browser/media/router/BUILD.gn
@@ -155,6 +155,7 @@ "providers/openscreen/platform/task_runner.cc", "providers/openscreen/platform/task_runner.h", "providers/openscreen/platform/time.cc", + "providers/openscreen/platform/trace_logging_platform.cc", ] configs +=
diff --git a/chrome/browser/media/router/providers/openscreen/platform/trace_logging_platform.cc b/chrome/browser/media/router/providers/openscreen/platform/trace_logging_platform.cc new file mode 100644 index 0000000..0e49107 --- /dev/null +++ b/chrome/browser/media/router/providers/openscreen/platform/trace_logging_platform.cc
@@ -0,0 +1,15 @@ +// 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. + +#include "third_party/openscreen/src/platform/api/trace_logging_platform.h" + +namespace openscreen { +namespace platform { + +bool IsTraceLoggingEnabled(TraceCategory::Value category) { + return false; +} + +} // namespace platform +} // namespace openscreen
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc index cb17b34..ced82c9 100644 --- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc +++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -225,6 +225,14 @@ UMA_HISTOGRAM_ENUMERATION("Windows.Kernel32Version", os_info.Kernel32Version(), base::win::Version::WIN_LAST); + int patch = os_info.version_number().patch; + int build = os_info.version_number().build; + int patch_level = 0; + + if (patch < 65536 && build < 65536) + patch_level = MAKELONG(patch, build); + DCHECK(patch_level) << "Windows version too high!"; + base::UmaHistogramSparse("Windows.PatchLevel", patch_level); UMA_HISTOGRAM_BOOLEAN("Windows.HasHighResolutionTimeTicks", base::TimeTicks::IsHighResolution());
diff --git a/chrome/browser/notifications/scheduler/test/BUILD.gn b/chrome/browser/notifications/scheduler/test/BUILD.gn index a1e45e3..ec4d221 100644 --- a/chrome/browser/notifications/scheduler/test/BUILD.gn +++ b/chrome/browser/notifications/scheduler/test/BUILD.gn
@@ -10,10 +10,16 @@ sources = [ "fake_clock.cc", "fake_clock.h", + "mock_display_agent.cc", + "mock_display_agent.h", + "mock_display_decider.cc", + "mock_display_decider.h", "mock_impression_history_tracker.cc", "mock_impression_history_tracker.h", "mock_notification_background_task_scheduler.cc", "mock_notification_background_task_scheduler.h", + "mock_scheduled_notification_manager.cc", + "mock_scheduled_notification_manager.h", "test_utils.cc", "test_utils.h", ]
diff --git a/chrome/browser/notifications/scheduler/test/mock_display_agent.cc b/chrome/browser/notifications/scheduler/test/mock_display_agent.cc new file mode 100644 index 0000000..e4e8881 --- /dev/null +++ b/chrome/browser/notifications/scheduler/test/mock_display_agent.cc
@@ -0,0 +1,15 @@ +// 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. + +#include "chrome/browser/notifications/scheduler/test/mock_display_agent.h" + +namespace notifications { +namespace test { + +MockDisplayAgent::MockDisplayAgent() = default; + +MockDisplayAgent::~MockDisplayAgent() = default; + +} // namespace test +} // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/test/mock_display_agent.h b/chrome/browser/notifications/scheduler/test/mock_display_agent.h new file mode 100644 index 0000000..99fa066e0 --- /dev/null +++ b/chrome/browser/notifications/scheduler/test/mock_display_agent.h
@@ -0,0 +1,26 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_TEST_MOCK_DISPLAY_AGENT_H_ +#define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_TEST_MOCK_DISPLAY_AGENT_H_ + +#include "chrome/browser/notifications/scheduler/public/display_agent.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace notifications { +namespace test { + +class MockDisplayAgent : public DisplayAgent { + public: + MockDisplayAgent(); + ~MockDisplayAgent() override; + MOCK_METHOD2(ShowNotification, + void(std::unique_ptr<NotificationData>, + std::unique_ptr<SystemData>)); +}; + +} // namespace test +} // namespace notifications + +#endif // CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_TEST_MOCK_DISPLAY_AGENT_H_
diff --git a/chrome/browser/notifications/scheduler/test/mock_display_decider.cc b/chrome/browser/notifications/scheduler/test/mock_display_decider.cc new file mode 100644 index 0000000..4db7f16a --- /dev/null +++ b/chrome/browser/notifications/scheduler/test/mock_display_decider.cc
@@ -0,0 +1,15 @@ +// 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. + +#include "chrome/browser/notifications/scheduler/test/mock_display_decider.h" + +namespace notifications { +namespace test { + +MockDisplayDecider::MockDisplayDecider() = default; + +MockDisplayDecider::~MockDisplayDecider() = default; + +} // namespace test +} // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/test/mock_display_decider.h b/chrome/browser/notifications/scheduler/test/mock_display_decider.h new file mode 100644 index 0000000..385811d0 --- /dev/null +++ b/chrome/browser/notifications/scheduler/test/mock_display_decider.h
@@ -0,0 +1,32 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_TEST_MOCK_DISPLAY_DECIDER_H_ +#define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_TEST_MOCK_DISPLAY_DECIDER_H_ + +#include "chrome/browser/notifications/scheduler/internal/display_decider.h" +#include "chrome/browser/notifications/scheduler/internal/distribution_policy.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace notifications { +namespace test { + +class MockDisplayDecider : public DisplayDecider { + public: + MockDisplayDecider(); + ~MockDisplayDecider() override; + MOCK_METHOD7(FindNotificationsToShow, + void(const SchedulerConfig*, + std::vector<SchedulerClientType>, + std::unique_ptr<DistributionPolicy>, + SchedulerTaskTime, + Notifications, + ClientStates, + Results*)); +}; + +} // namespace test +} // namespace notifications + +#endif // CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_TEST_MOCK_DISPLAY_DECIDER_H_
diff --git a/chrome/browser/notifications/scheduler/test/mock_scheduled_notification_manager.cc b/chrome/browser/notifications/scheduler/test/mock_scheduled_notification_manager.cc new file mode 100644 index 0000000..a838f54a --- /dev/null +++ b/chrome/browser/notifications/scheduler/test/mock_scheduled_notification_manager.cc
@@ -0,0 +1,16 @@ +// 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. +// + +#include "chrome/browser/notifications/scheduler/test/mock_scheduled_notification_manager.h" + +namespace notifications { +namespace test { + +MockScheduledNotificationManager::MockScheduledNotificationManager() = default; + +MockScheduledNotificationManager::~MockScheduledNotificationManager() = default; + +} // namespace test +} // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/test/mock_scheduled_notification_manager.h b/chrome/browser/notifications/scheduler/test/mock_scheduled_notification_manager.h new file mode 100644 index 0000000..2737735 --- /dev/null +++ b/chrome/browser/notifications/scheduler/test/mock_scheduled_notification_manager.h
@@ -0,0 +1,34 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_TEST_MOCK_SCHEDULED_NOTIFICATION_MANAGER_H_ +#define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_TEST_MOCK_SCHEDULED_NOTIFICATION_MANAGER_H_ + +#include "chrome/browser/notifications/scheduler/internal/scheduled_notification_manager.h" +#include "chrome/browser/notifications/scheduler/public/notification_params.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace notifications { +namespace test { + +class MockScheduledNotificationManager : public ScheduledNotificationManager { + public: + MockScheduledNotificationManager(); + ~MockScheduledNotificationManager() override; + + MOCK_METHOD2(Init, void(Delegate*, base::OnceCallback<void(bool)>)); + MOCK_METHOD1(ScheduleNotification, + void(std::unique_ptr<notifications::NotificationParams>)); + MOCK_METHOD1(DisplayNotification, void(const std::string&)); + MOCK_CONST_METHOD1(GetAllNotifications, void(Notifications*)); + MOCK_CONST_METHOD2(GetNotifications, + void(SchedulerClientType, + std::vector<const NotificationEntry*>*)); + MOCK_METHOD1(DeleteNotifications, void(SchedulerClientType)); +}; + +} // namespace test +} // namespace notifications + +#endif // CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_TEST_MOCK_SCHEDULED_NOTIFICATION_MANAGER_H_
diff --git a/chrome/browser/ntp_tiles/chrome_most_visited_sites_factory.cc b/chrome/browser/ntp_tiles/chrome_most_visited_sites_factory.cc index 6c16d93..90fcbacf 100644 --- a/chrome/browser/ntp_tiles/chrome_most_visited_sites_factory.cc +++ b/chrome/browser/ntp_tiles/chrome_most_visited_sites_factory.cc
@@ -18,10 +18,7 @@ #include "chrome/browser/ntp_tiles/chrome_popular_sites_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/suggestions/suggestions_service_factory.h" -#include "chrome/browser/supervised_user/supervised_user_service.h" -#include "chrome/browser/supervised_user/supervised_user_service_factory.h" -#include "chrome/browser/supervised_user/supervised_user_service_observer.h" -#include "chrome/browser/supervised_user/supervised_user_url_filter.h" +#include "chrome/common/buildflags.h" #include "components/history/core/browser/top_sites.h" #include "components/image_fetcher/core/image_fetcher_impl.h" #include "components/ntp_tiles/icon_cacher_impl.h" @@ -33,8 +30,16 @@ #include "chrome/browser/android/explore_sites/most_visited_client.h" #endif +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/supervised_user/supervised_user_service.h" +#include "chrome/browser/supervised_user/supervised_user_service_factory.h" +#include "chrome/browser/supervised_user/supervised_user_service_observer.h" +#include "chrome/browser/supervised_user/supervised_user_url_filter.h" +#endif + using suggestions::SuggestionsServiceFactory; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) namespace { class SupervisorBridge : public ntp_tiles::MostVisitedSitesSupervisor, @@ -110,6 +115,7 @@ } } // namespace +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) // static std::unique_ptr<ntp_tiles::MostVisitedSites> @@ -140,7 +146,12 @@ std::make_unique<ImageDecoderImpl>(), content::BrowserContext::GetDefaultStoragePartition(profile) ->GetURLLoaderFactoryForBrowserProcess())), - std::make_unique<SupervisorBridge>(profile)); +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + std::make_unique<SupervisorBridge>(profile) +#else + nullptr +#endif + ); #if defined(OS_ANDROID) most_visited_sites->SetExploreSitesClient( explore_sites::MostVisitedClient::Create());
diff --git a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc index e4125d7..7ddcb82 100644 --- a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc +++ b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
@@ -41,6 +41,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/resource_request_info.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_features.h" #include "content/public/common/previews_state.h" #include "content/public/common/resource_type.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -97,6 +98,14 @@ const int64_t kDownloadId = 42LL; +// Returns the thread the navigation URL loader will run on. This determines +// where the OfflinePageURLLoader should be created. +content::BrowserThread::ID GetNavigationLoaderThreadID() { + return base::FeatureList::IsEnabled(features::kNavigationLoaderOnUI) + ? content::BrowserThread::UI + : content::BrowserThread::IO; +} + struct ResponseInfo { explicit ResponseInfo(int request_status) : request_status(request_status) { DCHECK_NE(net::OK, request_status); @@ -262,15 +271,16 @@ private: void OnHandleReady(MojoResult result, const mojo::HandleSignalsState& state); - void InterceptRequestOnIO(const GURL& url, - const std::string& method, - const net::HttpRequestHeaders& extra_headers, - bool is_main_frame); + void InterceptRequestOnLoaderThread( + const GURL& url, + const std::string& method, + const net::HttpRequestHeaders& extra_headers, + bool is_main_frame); void MaybeStartLoader( const network::ResourceRequest& request, content::URLLoaderRequestInterceptor::RequestHandler request_handler); void ReadBody(); - void ReadCompletedOnIO(const ResponseInfo& response); + void ReadCompletedOnLoaderThread(const ResponseInfo& response); OfflinePageRequestHandlerTest* test_; std::unique_ptr<ChromeNavigationUIData> navigation_ui_data_; @@ -941,7 +951,8 @@ void OfflinePageURLLoaderBuilder::OnReceiveRedirect( const GURL& redirected_url) { - InterceptRequestOnIO(redirected_url, "GET", net::HttpRequestHeaders(), true); + InterceptRequestOnLoaderThread(redirected_url, "GET", + net::HttpRequestHeaders(), true); } void OfflinePageURLLoaderBuilder::OnReceiveResponse( @@ -958,19 +969,19 @@ mime_type_.clear(); body_.clear(); } - ReadCompletedOnIO( + ReadCompletedOnLoaderThread( ResponseInfo(client_->completion_status().error_code, mime_type_, body_)); // Clear intermediate data in preparation for next potential page loading. mime_type_.clear(); body_.clear(); } -void OfflinePageURLLoaderBuilder::InterceptRequestOnIO( +void OfflinePageURLLoaderBuilder::InterceptRequestOnLoaderThread( const GURL& url, const std::string& method, const net::HttpRequestHeaders& extra_headers, bool is_main_frame) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK_CURRENTLY_ON(GetNavigationLoaderThreadID()); client_ = std::make_unique<TestURLLoaderClient>(this); @@ -1000,21 +1011,25 @@ bool is_main_frame) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::IO}, - base::BindOnce(&OfflinePageURLLoaderBuilder::InterceptRequestOnIO, - base::Unretained(this), url, method, extra_headers, - is_main_frame)); + if (GetNavigationLoaderThreadID() == content::BrowserThread::UI) { + InterceptRequestOnLoaderThread(url, method, extra_headers, is_main_frame); + } else { + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce( + &OfflinePageURLLoaderBuilder::InterceptRequestOnLoaderThread, + base::Unretained(this), url, method, extra_headers, is_main_frame)); + } base::RunLoop().Run(); } void OfflinePageURLLoaderBuilder::MaybeStartLoader( const network::ResourceRequest& request, content::URLLoaderRequestInterceptor::RequestHandler request_handler) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK_CURRENTLY_ON(GetNavigationLoaderThreadID()); if (!request_handler) { - ReadCompletedOnIO(ResponseInfo(net::ERR_FAILED)); + ReadCompletedOnLoaderThread(ResponseInfo(net::ERR_FAILED)); return; } @@ -1049,7 +1064,7 @@ // The pipe was closed. if (rv == MOJO_RESULT_FAILED_PRECONDITION) { - ReadCompletedOnIO(ResponseInfo(net::ERR_FAILED)); + ReadCompletedOnLoaderThread(ResponseInfo(net::ERR_FAILED)); return; } @@ -1064,15 +1079,15 @@ MojoResult result, const mojo::HandleSignalsState& state) { if (result != MOJO_RESULT_OK) { - ReadCompletedOnIO(ResponseInfo(net::ERR_FAILED)); + ReadCompletedOnLoaderThread(ResponseInfo(net::ERR_FAILED)); return; } ReadBody(); } -void OfflinePageURLLoaderBuilder::ReadCompletedOnIO( +void OfflinePageURLLoaderBuilder::ReadCompletedOnLoaderThread( const ResponseInfo& response) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + DCHECK_CURRENTLY_ON(GetNavigationLoaderThreadID()); handle_watcher_.reset(); client_.reset(); @@ -1085,11 +1100,15 @@ if (offline_page_data && offline_page_data->is_offline_page()) is_offline_page_set_in_navigation_data = true; - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&OfflinePageRequestHandlerTest::ReadCompleted, - base::Unretained(test()), response, - is_offline_page_set_in_navigation_data)); + if (GetNavigationLoaderThreadID() == content::BrowserThread::UI) { + test()->ReadCompleted(response, is_offline_page_set_in_navigation_data); + } else { + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&OfflinePageRequestHandlerTest::ReadCompleted, + base::Unretained(test()), response, + is_offline_page_set_in_navigation_data)); + } } TEST_F(OfflinePageRequestHandlerTest, FailedToCreateRequestJob) {
diff --git a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc index 050d1344..2a2473b5 100644 --- a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc +++ b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
@@ -86,7 +86,6 @@ WebFeature::kSignedExchangeInnerResponseInMainFrame, WebFeature::kSignedExchangeInnerResponseInSubFrame, WebFeature::kWebShareShare, - WebFeature::kDownloadInAdFrameWithUserGesture, WebFeature::kDownloadInAdFrameWithoutUserGesture, WebFeature::kOpenWebDatabase, WebFeature::kV8MediaCapabilities_DecodingInfo_Method, @@ -109,6 +108,11 @@ WebFeature::kAccelerometerConstructor, WebFeature::kGyroscopeConstructor, WebFeature::kServiceWorkerInterceptedRequestFromOriginDirtyStyleSheet, + WebFeature::kDownloadPrePolicyCheck, + WebFeature::kDownloadPostPolicyCheck, + WebFeature::kDownloadInAdFrame, + WebFeature::kDownloadInSandbox, + WebFeature::kDownloadWithoutUserGesture, })); return *opt_in_features; }
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.cc b/chrome/browser/password_manager/native_backend_gnome_x.cc deleted file mode 100644 index 6ade8c8e..0000000 --- a/chrome/browser/password_manager/native_backend_gnome_x.cc +++ /dev/null
@@ -1,759 +0,0 @@ -// Copyright (c) 2012 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/password_manager/native_backend_gnome_x.h" - -#include <map> -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/logging.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_piece.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/synchronization/waitable_event.h" -#include "base/task/post_task.h" -#include "base/time/time.h" -#include "chrome/browser/password_manager/password_manager_util_linux.h" -#include "components/autofill/core/common/password_form.h" -#include "components/password_manager/core/browser/password_manager_metrics_util.h" -#include "components/password_manager/core/browser/password_manager_util.h" -#include "components/password_manager/core/browser/psl_matching_helper.h" -#include "content/public/browser/browser_task_traits.h" -#include "content/public/browser/browser_thread.h" - -using autofill::PasswordForm; -using base::UTF8ToUTF16; -using base::UTF16ToUTF8; -using password_manager::MatchResult; -using password_manager::PasswordStore; - -namespace { - -// Convert the attributes of a given keyring entry into a new PasswordForm. -// Note: does *not* get the actual password, as that is not a key attribute! -// Returns NULL if the attributes are for the wrong application. -std::unique_ptr<PasswordForm> FormFromAttributes( - GnomeKeyringAttributeList* attrs) { - // Read the string and int attributes into the appropriate map. - std::map<std::string, std::string> string_attr_map; - std::map<std::string, uint32_t> uint_attr_map; - for (guint i = 0; i < attrs->len; ++i) { - GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index(attrs, i); - if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) - string_attr_map[attr.name] = attr.value.string; - else if (attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32) - uint_attr_map[attr.name] = attr.value.integer; - } - // Check to make sure this is a password we care about. - const std::string& app_value = string_attr_map["application"]; - if (!base::StringPiece(app_value).starts_with(kLibsecretAndGnomeAppString)) - return std::unique_ptr<PasswordForm>(); - - std::unique_ptr<PasswordForm> form(new PasswordForm()); - form->origin = GURL(string_attr_map["origin_url"]); - form->action = GURL(string_attr_map["action_url"]); - form->username_element = UTF8ToUTF16(string_attr_map["username_element"]); - form->username_value = UTF8ToUTF16(string_attr_map["username_value"]); - form->password_element = UTF8ToUTF16(string_attr_map["password_element"]); - form->submit_element = UTF8ToUTF16(string_attr_map["submit_element"]); - form->signon_realm = string_attr_map["signon_realm"]; - form->preferred = uint_attr_map["preferred"]; - int64_t date_created = 0; - bool date_ok = base::StringToInt64(string_attr_map["date_created"], - &date_created); - DCHECK(date_ok); - // In the past |date_created| was stored as time_t. Currently is stored as - // base::Time's internal value. We need to distinguish, which format the - // number in |date_created| was stored in. We use the fact that - // kMaxPossibleTimeTValue interpreted as the internal value corresponds to an - // unlikely date back in 17th century, and anything above - // kMaxPossibleTimeTValue clearly must be in the internal value format. - form->date_created = date_created < kMaxPossibleTimeTValue - ? base::Time::FromTimeT(date_created) - : base::Time::FromInternalValue(date_created); - form->blacklisted_by_user = uint_attr_map["blacklisted_by_user"]; - form->type = static_cast<PasswordForm::Type>(uint_attr_map["type"]); - form->times_used = uint_attr_map["times_used"]; - form->scheme = static_cast<PasswordForm::Scheme>(uint_attr_map["scheme"]); - int64_t date_synced = 0; - base::StringToInt64(string_attr_map["date_synced"], &date_synced); - form->date_synced = base::Time::FromInternalValue(date_synced); - form->display_name = UTF8ToUTF16(string_attr_map["display_name"]); - form->icon_url = GURL(string_attr_map["avatar_url"]); - form->federation_origin = - url::Origin::Create(GURL(string_attr_map["federation_url"])); - form->skip_zero_click = uint_attr_map.count("should_skip_zero_click") - ? uint_attr_map["should_skip_zero_click"] - : true; - form->generation_upload_status = - static_cast<PasswordForm::GenerationUploadStatus>( - uint_attr_map["generation_upload_status"]); - if (!string_attr_map["form_data"].empty()) { - bool success = DeserializeFormDataFromBase64String( - string_attr_map["form_data"], &form->form_data); - password_manager::metrics_util::FormDeserializationStatus status = - success ? password_manager::metrics_util::GNOME_SUCCESS - : password_manager::metrics_util::GNOME_FAILURE; - LogFormDataDeserializationStatus(status); - } - return form; -} - -// Converts native credentials in |found| to PasswordForms. If not NULL, -// |lookup_form| is used to filter out results -- only credentials with signon -// realms passing the PSL matching against |lookup_form->signon_realm| will be -// kept. PSL matched results get their signon_realm, origin, and action -// rewritten to those of |lookup_form_|, with the original signon_realm saved -// into the result's original_signon_realm data member. -std::vector<std::unique_ptr<PasswordForm>> ConvertFormList( - GList* found, - const PasswordStore::FormDigest* lookup_form) { - std::vector<std::unique_ptr<PasswordForm>> forms; - password_manager::PSLDomainMatchMetric psl_domain_match_metric = - password_manager::PSL_DOMAIN_MATCH_NONE; - for (GList* element = g_list_first(found); element; - element = g_list_next(element)) { - GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); - GnomeKeyringAttributeList* attrs = data->attributes; - - std::unique_ptr<PasswordForm> form(FormFromAttributes(attrs)); - if (!form) { - LOG(WARNING) << "Could not initialize PasswordForm from attributes!"; - continue; - } - - if (lookup_form) { - switch (GetMatchResult(*form, *lookup_form)) { - case MatchResult::NO_MATCH: - continue; - case MatchResult::EXACT_MATCH: - break; - case MatchResult::PSL_MATCH: - psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; - form->is_public_suffix_match = true; - break; - case MatchResult::FEDERATED_MATCH: - break; - case MatchResult::FEDERATED_PSL_MATCH: - psl_domain_match_metric = - password_manager::PSL_DOMAIN_MATCH_FOUND_FEDERATED; - form->is_public_suffix_match = true; - break; - } - } - - if (data->secret) { - form->password_value = UTF8ToUTF16(data->secret); - } else { - LOG(WARNING) << "Unable to access password from list element!"; - } - forms.push_back(std::move(form)); - } - if (lookup_form) { - const bool allow_psl_match = password_manager::ShouldPSLDomainMatchingApply( - password_manager::GetRegistryControlledDomain( - GURL(lookup_form->signon_realm))); - UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", - allow_psl_match - ? psl_domain_match_metric - : password_manager::PSL_DOMAIN_MATCH_NOT_USED, - password_manager::PSL_DOMAIN_MATCH_COUNT); - } - return forms; -} - -// Schema is analogous to the fields in PasswordForm. -const GnomeKeyringPasswordSchema kGnomeSchema = { - GNOME_KEYRING_ITEM_GENERIC_SECRET, - {{"origin_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"action_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"username_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"username_value", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"password_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"submit_element", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"signon_realm", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"preferred", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32}, - {"date_created", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"blacklisted_by_user", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32}, - {"scheme", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32}, - {"type", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32}, - {"times_used", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32}, - {"date_synced", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"display_name", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"avatar_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"federation_url", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {"should_skip_zero_click", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32}, - {"generation_upload_status", GNOME_KEYRING_ATTRIBUTE_TYPE_UINT32}, - {"form_data", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - // This field is always "chrome" so that we can search for it. - {"application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, - {nullptr}}}; - -// Sadly, PasswordStore goes to great lengths to switch from the originally -// calling thread to the DB thread, and to provide an asynchronous API to -// callers while using a synchronous (virtual) API provided by subclasses like -// PasswordStoreX -- but GNOME Keyring really wants to be on the GLib main -// thread, which is the UI thread to us. So we end up having to switch threads -// again, possibly back to the very same thread (in case the UI thread is the -// caller, e.g. in the password management UI), and *block* the DB thread -// waiting for a response from the UI thread to provide the synchronous API -// PasswordStore expects of us. (It will then in turn switch back to the -// original caller to send the asynchronous reply to the original request.) - -// This class represents a call to a GNOME Keyring method. A RunnableMethod -// should be posted to the UI thread to call one of its action methods, and then -// a WaitResult() method should be called to wait for the result. Each instance -// supports only one outstanding method at a time, though multiple instances may -// be used in parallel. -class GKRMethod : public GnomeKeyringLoader { - public: - GKRMethod(scoped_refptr<base::SequencedTaskRunner> main_task_runner, - scoped_refptr<base::SequencedTaskRunner> background_task_runner) - : main_task_runner_(std::move(main_task_runner)), - background_task_runner_(std::move(background_task_runner)), - event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED), - result_(GNOME_KEYRING_RESULT_CANCELLED) {} - - // Action methods. These call gnome_keyring_* functions. Call from UI thread. - // See GetProfileSpecificAppString() for more information on the app string. - void AddLogin(const PasswordForm& form, const char* app_string); - void LoginSearch(const PasswordForm& form, const char* app_string); - void RemoveLogin(const PasswordForm& form, const char* app_string); - void GetLogins(const PasswordStore::FormDigest& form, const char* app_string); - void GetLoginsList(uint32_t blacklisted_by_user, const char* app_string); - void GetAllLogins(const char* app_string); - - // Use after AddLogin, RemoveLogin. - GnomeKeyringResult WaitResult(); - - // Use after LoginSearch, GetLogins, GetLoginsList, GetAllLogins. Replaces the - // content of |forms| with found logins. - GnomeKeyringResult WaitResult( - std::vector<std::unique_ptr<PasswordForm>>* forms); - - private: - struct GnomeKeyringAttributeListFreeDeleter { - inline void operator()(void* list) const { - gnome_keyring_attribute_list_free_ptr( - static_cast<GnomeKeyringAttributeList*>(list)); - } - }; - - typedef std::unique_ptr<GnomeKeyringAttributeList, - GnomeKeyringAttributeListFreeDeleter> - ScopedAttributeList; - - // Helper methods to abbreviate Gnome Keyring long API names. - static void AppendString(ScopedAttributeList* list, - const char* name, - const char* value); - static void AppendString(ScopedAttributeList* list, - const char* name, - const std::string& value); - static void AppendUint32(ScopedAttributeList* list, - const char* name, - guint32 value); - - // All these callbacks are called on UI thread. - static void OnOperationDone(GnomeKeyringResult result, gpointer data); - - // This is marked as static, but acts on the GKRMethod instance that |data| - // points to. Saves |result| to |result_|. If the result is OK, overwrites - // |forms_| with the found credentials. Clears |forms_| otherwise. - static void OnOperationGetList(GnomeKeyringResult result, GList* list, - gpointer data); - - scoped_refptr<base::SequencedTaskRunner> main_task_runner_; - scoped_refptr<base::SequencedTaskRunner> background_task_runner_; - base::WaitableEvent event_; - GnomeKeyringResult result_; - std::vector<std::unique_ptr<PasswordForm>> forms_; - // If the credential search is specified by a single form and needs to use - // PSL matching, then the specifying form is stored in |lookup_form_|. If - // PSL matching is used to find a result, then the results signon realm and - // origin are stored are replaced by those of |lookup_form_|. Additionally, - // |lookup_form_->signon_realm| is also used to narrow down the found logins - // to those which indeed PSL-match the look-up. And finally, |lookup_form_| - // set to NULL means that PSL matching is not required. - std::unique_ptr<const PasswordStore::FormDigest> lookup_form_; -}; - -void GKRMethod::AddLogin(const PasswordForm& form, const char* app_string) { - DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); - int64_t date_created = form.date_created.ToInternalValue(); - // If we are asked to save a password with 0 date, use the current time. - // We don't want to actually save passwords as though on January 1, 1601. - if (!date_created) - date_created = base::Time::Now().ToInternalValue(); - int64_t date_synced = form.date_synced.ToInternalValue(); - std::string form_data; - SerializeFormDataToBase64String(form.form_data, &form_data); - // clang-format off - gnome_keyring_store_password_ptr( - &kGnomeSchema, - nullptr, // Default keyring. - form.origin.spec().c_str(), // Display name. - UTF16ToUTF8(form.password_value).c_str(), OnOperationDone, - this, // data - nullptr, // destroy_data - "origin_url", form.origin.spec().c_str(), - "action_url", form.action.spec().c_str(), - "username_element", UTF16ToUTF8(form.username_element).c_str(), - "username_value", UTF16ToUTF8(form.username_value).c_str(), - "password_element", UTF16ToUTF8(form.password_element).c_str(), - "submit_element", UTF16ToUTF8(form.submit_element).c_str(), - "signon_realm", form.signon_realm.c_str(), - "preferred", form.preferred, - "date_created", base::NumberToString(date_created).c_str(), - "blacklisted_by_user", form.blacklisted_by_user, - "type", form.type, - "times_used", form.times_used, - "scheme", form.scheme, - "date_synced", base::NumberToString(date_synced).c_str(), - "display_name", UTF16ToUTF8(form.display_name).c_str(), - "avatar_url", form.icon_url.spec().c_str(), - // We serialize unique origins as "", in order to make other systems that - // read from the login database happy. https://crbug.com/591310 - "federation_url", form.federation_origin.opaque() - ? "" - : form.federation_origin.Serialize().c_str(), - "should_skip_zero_click", form.skip_zero_click, - "generation_upload_status", form.generation_upload_status, - "form_data", form_data.c_str(), - "application", app_string, - nullptr); - // clang-format on -} - -void GKRMethod::LoginSearch(const PasswordForm& form, - const char* app_string) { - DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); - lookup_form_.reset(nullptr); - // Search GNOME Keyring for matching passwords to update. - ScopedAttributeList attrs(gnome_keyring_attribute_list_new_ptr()); - AppendString(&attrs, "origin_url", form.origin.spec()); - AppendString(&attrs, "username_element", UTF16ToUTF8(form.username_element)); - AppendString(&attrs, "username_value", UTF16ToUTF8(form.username_value)); - AppendString(&attrs, "password_element", UTF16ToUTF8(form.password_element)); - AppendString(&attrs, "signon_realm", form.signon_realm); - AppendString(&attrs, "application", app_string); - gnome_keyring_find_items_ptr(GNOME_KEYRING_ITEM_GENERIC_SECRET, attrs.get(), - OnOperationGetList, - /*data=*/this, - /*destroy_data=*/nullptr); -} - -void GKRMethod::RemoveLogin(const PasswordForm& form, const char* app_string) { - DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); - // We find forms using the same fields as LoginDatabase::RemoveLogin(). - gnome_keyring_delete_password_ptr( - &kGnomeSchema, - OnOperationDone, - this, // data - nullptr, // destroy_data - "origin_url", form.origin.spec().c_str(), - "username_element", UTF16ToUTF8(form.username_element).c_str(), - "username_value", UTF16ToUTF8(form.username_value).c_str(), - "password_element", UTF16ToUTF8(form.password_element).c_str(), - "signon_realm", form.signon_realm.c_str(), - "application", app_string, - nullptr); -} - -void GKRMethod::GetLogins(const PasswordStore::FormDigest& form, - const char* app_string) { - DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); - lookup_form_.reset(new PasswordStore::FormDigest(form)); - // Search GNOME Keyring for matching passwords. - ScopedAttributeList attrs(gnome_keyring_attribute_list_new_ptr()); - if (!password_manager::ShouldPSLDomainMatchingApply( - password_manager::GetRegistryControlledDomain( - GURL(form.signon_realm))) && - form.scheme != PasswordForm::Scheme::kHtml) { - // Don't retrieve the PSL matched and federated credentials. - AppendString(&attrs, "signon_realm", form.signon_realm); - } - AppendString(&attrs, "application", app_string); - gnome_keyring_find_items_ptr(GNOME_KEYRING_ITEM_GENERIC_SECRET, attrs.get(), - OnOperationGetList, - /*data=*/this, - /*destroy_data=*/nullptr); -} - -void GKRMethod::GetLoginsList(uint32_t blacklisted_by_user, - const char* app_string) { - DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); - lookup_form_.reset(nullptr); - // Search GNOME Keyring for matching passwords. - ScopedAttributeList attrs(gnome_keyring_attribute_list_new_ptr()); - AppendUint32(&attrs, "blacklisted_by_user", blacklisted_by_user); - AppendString(&attrs, "application", app_string); - gnome_keyring_find_items_ptr(GNOME_KEYRING_ITEM_GENERIC_SECRET, attrs.get(), - OnOperationGetList, - /*data=*/this, - /*destroy_data=*/nullptr); -} - -void GKRMethod::GetAllLogins(const char* app_string) { - DCHECK(main_task_runner_->RunsTasksInCurrentSequence()); - lookup_form_.reset(nullptr); - // We need to search for something, otherwise we get no results - so - // we search for the fixed application string. - ScopedAttributeList attrs(gnome_keyring_attribute_list_new_ptr()); - AppendString(&attrs, "application", app_string); - gnome_keyring_find_items_ptr(GNOME_KEYRING_ITEM_GENERIC_SECRET, attrs.get(), - OnOperationGetList, - /*data=*/this, - /*destroy_data=*/nullptr); -} - -GnomeKeyringResult GKRMethod::WaitResult() { - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - event_.Wait(); - return result_; -} - -GnomeKeyringResult GKRMethod::WaitResult( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - event_.Wait(); - *forms = std::move(forms_); - return result_; -} - -// static -void GKRMethod::AppendString(GKRMethod::ScopedAttributeList* list, - const char* name, - const char* value) { - gnome_keyring_attribute_list_append_string_ptr(list->get(), name, value); -} - -// static -void GKRMethod::AppendString(GKRMethod::ScopedAttributeList* list, - const char* name, - const std::string& value) { - AppendString(list, name, value.c_str()); -} - -// static -void GKRMethod::AppendUint32(GKRMethod::ScopedAttributeList* list, - const char* name, - guint32 value) { - gnome_keyring_attribute_list_append_uint32_ptr(list->get(), name, value); -} - -// static -void GKRMethod::OnOperationDone(GnomeKeyringResult result, gpointer data) { - GKRMethod* method = static_cast<GKRMethod*>(data); - method->result_ = result; - method->event_.Signal(); -} - -// static -void GKRMethod::OnOperationGetList(GnomeKeyringResult result, GList* list, - gpointer data) { - GKRMethod* method = static_cast<GKRMethod*>(data); - method->result_ = result; - // |list| will be freed after this callback returns, so convert it now. - if (result == GNOME_KEYRING_RESULT_OK) - method->forms_ = ConvertFormList(list, method->lookup_form_.get()); - else - method->forms_.clear(); - method->lookup_form_.reset(); - method->event_.Signal(); -} - -} // namespace - -// This uses BrowserThread::UI for the main thread, because the Gnome Keyring -// library needs to run there (see the comment at the top of this file). -// This also uses USER_VISIBLE priority for the background task runner, because -// the passwords obtained through tasks on the background runner influence what -// the user sees. The need for WithBaseSyncPrimitives is caused by calls to -// Wait() to synchronise the background task with its response from -// GnomeKeyring which needs to be produced on the main task runner for library -// limitations. While unfortunate, https://crbug.com/739897 provides the -// discussion which resulted in accepting this until the whole backend is -// deprecated. -NativeBackendGnome::NativeBackendGnome(LocalProfileId id) - : app_string_(GetProfileSpecificAppString(id)), - main_task_runner_(base::CreateSingleThreadTaskRunnerWithTraits( - {content::BrowserThread::UI})), - background_task_runner_(base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::WithBaseSyncPrimitives(), - base::TaskPriority::USER_VISIBLE})) {} - -NativeBackendGnome::~NativeBackendGnome() { -} - -bool NativeBackendGnome::Init() { - return LoadGnomeKeyring() && gnome_keyring_is_available_ptr(); -} - -bool NativeBackendGnome::RawAddLogin(const PasswordForm& form) { - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - GKRMethod method(main_task_runner_, background_task_runner_); - main_task_runner_->PostTask( - FROM_HERE, base::BindOnce(&GKRMethod::AddLogin, base::Unretained(&method), - form, app_string_.c_str())); - GnomeKeyringResult result = method.WaitResult(); - if (result != GNOME_KEYRING_RESULT_OK) { - LOG(ERROR) << "Keyring save failed: " - << gnome_keyring_result_to_message_ptr(result); - return false; - } - return true; -} - -password_manager::PasswordStoreChangeList NativeBackendGnome::AddLogin( - const PasswordForm& form) { - // Based on LoginDatabase::AddLogin(), we search for an existing match based - // on origin_url, username_element, username_value, password_element, submit - // element, and signon_realm first, remove that, and then add the new entry. - // We'd add the new one first, and then delete the original, but then the - // delete might actually delete the newly-added entry! - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - GKRMethod method(main_task_runner_, background_task_runner_); - main_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&GKRMethod::LoginSearch, base::Unretained(&method), form, - app_string_.c_str())); - std::vector<std::unique_ptr<PasswordForm>> forms; - GnomeKeyringResult result = method.WaitResult(&forms); - if (result != GNOME_KEYRING_RESULT_OK && - result != GNOME_KEYRING_RESULT_NO_MATCH) { - LOG(ERROR) << "Keyring find failed: " - << gnome_keyring_result_to_message_ptr(result); - return password_manager::PasswordStoreChangeList(); - } - password_manager::PasswordStoreChangeList changes; - if (forms.size() > 0) { - password_manager::PasswordStoreChangeList temp_changes; - if (forms.size() > 1) { - LOG(WARNING) << "Adding login when there are " << forms.size() - << " matching logins already!"; - } - for (const auto& old_form : forms) { - if (!RemoveLogin(*old_form, &temp_changes)) - return changes; - } - changes.push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::REMOVE, *forms[0])); - } - if (RawAddLogin(form)) { - changes.push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::ADD, form)); - } - return changes; -} - -bool NativeBackendGnome::UpdateLogin( - const PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) { - // Based on LoginDatabase::UpdateLogin(), we search for forms to update by - // origin_url, username_element, username_value, password_element, and - // signon_realm. We then compare the result to the updated form. If they - // differ in any of the mutable fields, then we remove the original, and - // then add the new entry. We'd add the new one first, and then delete the - // original, but then the delete might actually delete the newly-added entry! - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - DCHECK(changes); - GKRMethod method(main_task_runner_, background_task_runner_); - main_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&GKRMethod::LoginSearch, base::Unretained(&method), form, - app_string_.c_str())); - std::vector<std::unique_ptr<PasswordForm>> forms; - GnomeKeyringResult result = method.WaitResult(&forms); - if (result == GNOME_KEYRING_RESULT_NO_MATCH) - return true; - if (result != GNOME_KEYRING_RESULT_OK) { - LOG(ERROR) << "Keyring find failed: " - << gnome_keyring_result_to_message_ptr(result); - return false; - } - if (forms.size() == 1 && *forms.front() == form) - return true; - - password_manager::PasswordStoreChangeList temp_changes; - for (const auto& keychain_form : forms) { - // Remove all the obsolete forms. Note that RemoveLogin can remove any form - // matching the unique key. Thus, it's important to call it the right number - // of times. - if (!RemoveLogin(*keychain_form, &temp_changes)) - return false; - } - - if (RawAddLogin(form)) { - password_manager::PasswordStoreChange change( - password_manager::PasswordStoreChange::UPDATE, form); - changes->push_back(change); - return true; - } - return false; -} - -bool NativeBackendGnome::RemoveLogin( - const PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) { - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - DCHECK(changes); - GKRMethod method(main_task_runner_, background_task_runner_); - main_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&GKRMethod::RemoveLogin, base::Unretained(&method), form, - app_string_.c_str())); - GnomeKeyringResult result = method.WaitResult(); - if (result == GNOME_KEYRING_RESULT_NO_MATCH) - return true; - - if (result != GNOME_KEYRING_RESULT_OK) { - LOG(ERROR) << "Keyring delete failed: " - << gnome_keyring_result_to_message_ptr(result); - return false; - } - changes->push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::REMOVE, form)); - return true; -} - -bool NativeBackendGnome::RemoveLoginsCreatedBetween( - base::Time delete_begin, - base::Time delete_end, - password_manager::PasswordStoreChangeList* changes) { - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - changes->clear(); - std::vector<std::unique_ptr<PasswordForm>> all_forms; - if (!GetAllLogins(&all_forms)) - return false; - - for (const auto& saved_form : all_forms) { - if (delete_begin <= saved_form->date_created && - (delete_end.is_null() || saved_form->date_created < delete_end) && - !RemoveLogin(*saved_form, changes)) { - return false; - } - } - - return true; -} - -bool NativeBackendGnome::DisableAutoSignInForOrigins( - const base::Callback<bool(const GURL&)>& origin_filter, - password_manager::PasswordStoreChangeList* changes) { - std::vector<std::unique_ptr<PasswordForm>> forms; - if (!GetAllLogins(&forms)) - return false; - - for (const std::unique_ptr<PasswordForm>& form : forms) { - if (origin_filter.Run(form->origin) && !form->skip_zero_click) { - form->skip_zero_click = true; - if (!UpdateLogin(*form, changes)) - return false; - } - } - - return true; -} - -bool NativeBackendGnome::GetLogins( - const PasswordStore::FormDigest& form, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - GKRMethod method(main_task_runner_, background_task_runner_); - main_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&GKRMethod::GetLogins, base::Unretained(&method), form, - app_string_.c_str())); - GnomeKeyringResult result = method.WaitResult(forms); - if (result == GNOME_KEYRING_RESULT_NO_MATCH) - return true; - if (result != GNOME_KEYRING_RESULT_OK) { - LOG(ERROR) << "Keyring find failed: " - << gnome_keyring_result_to_message_ptr(result); - return false; - } - return true; -} - -bool NativeBackendGnome::GetAutofillableLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - return GetLoginsList(true, forms); -} - -bool NativeBackendGnome::GetBlacklistLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - return GetLoginsList(false, forms); -} - -bool NativeBackendGnome::GetLoginsList( - bool autofillable, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - - uint32_t blacklisted_by_user = !autofillable; - - GKRMethod method(main_task_runner_, background_task_runner_); - main_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&GKRMethod::GetLoginsList, base::Unretained(&method), - blacklisted_by_user, app_string_.c_str())); - GnomeKeyringResult result = method.WaitResult(forms); - if (result == GNOME_KEYRING_RESULT_NO_MATCH) - return true; - if (result != GNOME_KEYRING_RESULT_OK) { - LOG(ERROR) << "Keyring find failed: " - << gnome_keyring_result_to_message_ptr(result); - return false; - } - - // Get rid of the forms with the same sync tags. - std::vector<std::unique_ptr<PasswordForm>> duplicates; - std::vector<std::vector<autofill::PasswordForm*>> tag_groups; - password_manager_util::FindDuplicates(forms, &duplicates, &tag_groups); - if (duplicates.empty()) - return true; - for (const auto& group : tag_groups) { - if (group.size() > 1) { - // There are duplicates. Readd the first form. AddLogin() is smart enough - // to clean the previous ones. - password_manager::PasswordStoreChangeList changes = AddLogin(*group[0]); - if (changes.empty() || - changes.back().type() != password_manager::PasswordStoreChange::ADD) - return false; - } - } - return true; -} - -bool NativeBackendGnome::GetAllLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); - GKRMethod method(main_task_runner_, background_task_runner_); - main_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&GKRMethod::GetAllLogins, base::Unretained(&method), - app_string_.c_str())); - GnomeKeyringResult result = method.WaitResult(forms); - if (result == GNOME_KEYRING_RESULT_NO_MATCH) - return true; - if (result != GNOME_KEYRING_RESULT_OK) { - LOG(ERROR) << "Keyring find failed: " - << gnome_keyring_result_to_message_ptr(result); - return false; - } - return true; -} - -scoped_refptr<base::SequencedTaskRunner> -NativeBackendGnome::GetBackgroundTaskRunner() { - return background_task_runner_; -}
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.h b/chrome/browser/password_manager/native_backend_gnome_x.h deleted file mode 100644 index c9660898..0000000 --- a/chrome/browser/password_manager/native_backend_gnome_x.h +++ /dev/null
@@ -1,81 +0,0 @@ -// Copyright (c) 2012 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 CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_GNOME_X_H_ -#define CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_GNOME_X_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/sequenced_task_runner.h" -#include "base/time/time.h" -#include "chrome/browser/password_manager/password_store_factory.h" -#include "chrome/browser/password_manager/password_store_x.h" -#include "chrome/browser/profiles/profile.h" -#include "components/os_crypt/keyring_util_linux.h" - -namespace autofill { -struct PasswordForm; -} - -// NativeBackend implementation using GNOME Keyring. -class NativeBackendGnome : public PasswordStoreX::NativeBackend, - public GnomeKeyringLoader { - public: - explicit NativeBackendGnome(LocalProfileId id); - - ~NativeBackendGnome() override; - - bool Init() override; - - // Implements NativeBackend interface. - password_manager::PasswordStoreChangeList AddLogin( - const autofill::PasswordForm& form) override; - bool UpdateLogin(const autofill::PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) override; - bool RemoveLogin(const autofill::PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) override; - bool RemoveLoginsCreatedBetween( - base::Time delete_begin, - base::Time delete_end, - password_manager::PasswordStoreChangeList* changes) override; - bool DisableAutoSignInForOrigins( - const base::Callback<bool(const GURL&)>& origin_filter, - password_manager::PasswordStoreChangeList* changes) override; - bool GetLogins( - const password_manager::PasswordStore::FormDigest& form, - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - bool GetAutofillableLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - bool GetBlacklistLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - bool GetAllLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner() override; - - private: - // Adds a login form without checking for one to replace first. - bool RawAddLogin(const autofill::PasswordForm& form); - - // Retrieves all autofillable or all blacklisted credentials (depending on - // |autofillable|) from the keyring into |forms|, overwriting the original - // contents of |forms|. Returns true on success. - bool GetLoginsList(bool autofillable, - std::vector<std::unique_ptr<autofill::PasswordForm>>* - forms) WARN_UNUSED_RESULT; - - // The app string, possibly based on the local profile id. - std::string app_string_; - - scoped_refptr<base::SequencedTaskRunner> main_task_runner_; - scoped_refptr<base::SequencedTaskRunner> background_task_runner_; - - DISALLOW_COPY_AND_ASSIGN(NativeBackendGnome); -}; - -#endif // CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_GNOME_X_H_
diff --git a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc deleted file mode 100644 index 0551c69..0000000 --- a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc +++ /dev/null
@@ -1,1271 +0,0 @@ -// Copyright (c) 2012 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 <stdarg.h> -#include <stddef.h> -#include <stdint.h> - -#include <map> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/location.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/stringprintf.h" -#include "base/strings/utf_string_conversions.h" -#include "base/task_runner_util.h" -#include "base/time/time.h" -#include "chrome/browser/password_manager/native_backend_gnome_x.h" -#include "chrome/test/base/testing_profile.h" -#include "components/autofill/core/common/password_form.h" -#include "components/password_manager/core/browser/psl_matching_helper.h" -#include "components/password_manager/core/common/password_manager_pref_names.h" -#include "components/prefs/pref_service.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "content/public/test/test_utils.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using autofill::PasswordForm; -using base::UTF8ToUTF16; -using base::UTF16ToUTF8; -using password_manager::PasswordStore; -using password_manager::PasswordStoreChange; -using password_manager::PasswordStoreChangeList; -using testing::Pointee; -using testing::UnorderedElementsAre; - -namespace { - -// What follows is a very simple implementation of the subset of the GNOME -// Keyring API that we actually use. It gets substituted for the real one by -// MockGnomeKeyringLoader, which hooks into the facility normally used to load -// the GNOME Keyring library at runtime to avoid a static dependency on it. - -struct MockKeyringItem { - MockKeyringItem() {} - MockKeyringItem(const char* keyring, - const std::string& display_name, - const std::string& password) - : keyring(keyring ? keyring : "login"), - display_name(display_name), - password(password) {} - - struct ItemAttribute { - ItemAttribute() : type(UINT32), value_uint32(0) {} - explicit ItemAttribute(uint32_t value) - : type(UINT32), value_uint32(value) {} - explicit ItemAttribute(const std::string& value) - : type(STRING), value_string(value) {} - - bool Equals(const ItemAttribute& x) const { - if (type != x.type) return false; - return (type == STRING) ? value_string == x.value_string - : value_uint32 == x.value_uint32; - } - - enum Type { UINT32, STRING } type; - uint32_t value_uint32; - std::string value_string; - }; - - typedef std::map<std::string, ItemAttribute> attribute_map; - typedef std::vector<std::pair<std::string, ItemAttribute> > attribute_query; - - bool Matches(const attribute_query& query) const { - // The real GNOME Keyring doesn't match empty queries. - if (query.empty()) return false; - for (size_t i = 0; i < query.size(); ++i) { - auto match = attributes.find(query[i].first); - if (match == attributes.end()) return false; - if (!match->second.Equals(query[i].second)) return false; - } - return true; - } - - std::string keyring; - std::string display_name; - std::string password; - - attribute_map attributes; -}; - -// The list of all keyring items we have stored. -std::vector<MockKeyringItem> mock_keyring_items; -bool mock_keyring_reject_local_ids = false; - -bool IsStringAttribute(const GnomeKeyringPasswordSchema* schema, - const std::string& name) { - for (size_t i = 0; schema->attributes[i].name; ++i) - if (name == schema->attributes[i].name) - return schema->attributes[i].type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING; - NOTREACHED() << "Requested type of nonexistent attribute"; - return false; -} - -gboolean mock_gnome_keyring_is_available() { - return true; -} - -gpointer mock_gnome_keyring_store_password( - const GnomeKeyringPasswordSchema* schema, - const gchar* keyring, - const gchar* display_name, - const gchar* password, - GnomeKeyringOperationDoneCallback callback, - gpointer data, - GDestroyNotify destroy_data, - ...) { - mock_keyring_items.push_back( - MockKeyringItem(keyring, display_name, password)); - MockKeyringItem* item = &mock_keyring_items.back(); - const std::string keyring_desc = - keyring ? base::StringPrintf("keyring %s", keyring) - : std::string("default keyring"); - VLOG(1) << "Adding item with origin " << display_name - << " to " << keyring_desc; - va_list ap; - va_start(ap, destroy_data); - char* name; - while ((name = va_arg(ap, gchar*))) { - if (IsStringAttribute(schema, name)) { - item->attributes[name] = - MockKeyringItem::ItemAttribute(va_arg(ap, gchar*)); - VLOG(1) << "Adding item attribute " << name - << ", value '" << item->attributes[name].value_string << "'"; - } else { - item->attributes[name] = - MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t)); - VLOG(1) << "Adding item attribute " << name - << ", value " << item->attributes[name].value_uint32; - } - } - va_end(ap); - // As a hack to ease testing migration, make it possible to reject the new - // format for the app string. This way we can add them easily to migrate. - if (mock_keyring_reject_local_ids) { - auto it = item->attributes.find("application"); - if (it != item->attributes.end() && - it->second.type == MockKeyringItem::ItemAttribute::STRING && - base::StringPiece(it->second.value_string).starts_with("chrome-")) { - mock_keyring_items.pop_back(); - // GnomeKeyringResult, data - callback(GNOME_KEYRING_RESULT_IO_ERROR, data); - return nullptr; - } - } - // GnomeKeyringResult, data - callback(GNOME_KEYRING_RESULT_OK, data); - return nullptr; -} - -gpointer mock_gnome_keyring_delete_password( - const GnomeKeyringPasswordSchema* schema, - GnomeKeyringOperationDoneCallback callback, - gpointer data, - GDestroyNotify destroy_data, - ...) { - MockKeyringItem::attribute_query query; - va_list ap; - va_start(ap, destroy_data); - char* name; - while ((name = va_arg(ap, gchar*))) { - if (IsStringAttribute(schema, name)) { - query.push_back(make_pair(std::string(name), - MockKeyringItem::ItemAttribute(va_arg(ap, gchar*)))); - VLOG(1) << "Querying with item attribute " << name - << ", value '" << query.back().second.value_string << "'"; - } else { - query.push_back(make_pair(std::string(name), - MockKeyringItem::ItemAttribute(va_arg(ap, uint32_t)))); - VLOG(1) << "Querying with item attribute " << name - << ", value " << query.back().second.value_uint32; - } - } - va_end(ap); - bool deleted = false; - for (size_t i = mock_keyring_items.size(); i > 0; --i) { - const MockKeyringItem* item = &mock_keyring_items[i - 1]; - if (item->Matches(query)) { - VLOG(1) << "Deleting item with origin " << item->display_name; - mock_keyring_items.erase(mock_keyring_items.begin() + (i - 1)); - deleted = true; - } - } - // GnomeKeyringResult, data - callback(deleted ? GNOME_KEYRING_RESULT_OK - : GNOME_KEYRING_RESULT_NO_MATCH, data); - return nullptr; -} - -gpointer mock_gnome_keyring_find_items( - GnomeKeyringItemType type, - GnomeKeyringAttributeList* attributes, - GnomeKeyringOperationGetListCallback callback, - gpointer data, - GDestroyNotify destroy_data) { - MockKeyringItem::attribute_query query; - for (size_t i = 0; i < attributes->len; ++i) { - GnomeKeyringAttribute attribute = - g_array_index(attributes, GnomeKeyringAttribute, i); - if (attribute.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING) { - query.push_back( - make_pair(std::string(attribute.name), - MockKeyringItem::ItemAttribute(attribute.value.string))); - VLOG(1) << "Querying with item attribute " << attribute.name - << ", value '" << query.back().second.value_string << "'"; - } else { - query.push_back( - make_pair(std::string(attribute.name), - MockKeyringItem::ItemAttribute(attribute.value.integer))); - VLOG(1) << "Querying with item attribute " << attribute.name << ", value " - << query.back().second.value_uint32; - } - } - // Find matches and add them to a list of results. - GList* results = nullptr; - for (size_t i = 0; i < mock_keyring_items.size(); ++i) { - const MockKeyringItem* item = &mock_keyring_items[i]; - if (item->Matches(query)) { - GnomeKeyringFound* found = new GnomeKeyringFound; - found->keyring = strdup(item->keyring.c_str()); - found->item_id = i; - found->attributes = gnome_keyring_attribute_list_new(); - for (auto it = item->attributes.begin(); it != item->attributes.end(); - ++it) { - if (it->second.type == MockKeyringItem::ItemAttribute::STRING) { - gnome_keyring_attribute_list_append_string( - found->attributes, it->first.c_str(), - it->second.value_string.c_str()); - } else { - gnome_keyring_attribute_list_append_uint32( - found->attributes, it->first.c_str(), - it->second.value_uint32); - } - } - found->secret = strdup(item->password.c_str()); - results = g_list_prepend(results, found); - } - } - // GnomeKeyringResult, GList*, data - callback(results ? GNOME_KEYRING_RESULT_OK - : GNOME_KEYRING_RESULT_NO_MATCH, results, data); - // Now free the list of results. - GList* element = g_list_first(results); - while (element) { - GnomeKeyringFound* found = static_cast<GnomeKeyringFound*>(element->data); - free(found->keyring); - gnome_keyring_attribute_list_free(found->attributes); - free(found->secret); - delete found; - element = g_list_next(element); - } - g_list_free(results); - return nullptr; -} - -const gchar* mock_gnome_keyring_result_to_message(GnomeKeyringResult res) { - return "mock keyring simulating failure"; -} - -// Inherit to get access to protected fields. -class MockGnomeKeyringLoader : public GnomeKeyringLoader { - public: - static bool LoadMockGnomeKeyring() { - // Mocked methods - gnome_keyring_is_available_ptr = &mock_gnome_keyring_is_available; - gnome_keyring_store_password_ptr = &mock_gnome_keyring_store_password; - gnome_keyring_delete_password_ptr = &mock_gnome_keyring_delete_password; - gnome_keyring_find_items_ptr = &mock_gnome_keyring_find_items; - gnome_keyring_result_to_message_ptr = &mock_gnome_keyring_result_to_message; - // Non-mocked methods - gnome_keyring_attribute_list_free_ptr = - &::gnome_keyring_attribute_list_free; - gnome_keyring_attribute_list_new_ptr = &::gnome_keyring_attribute_list_new; - gnome_keyring_attribute_list_append_string_ptr = - &::gnome_keyring_attribute_list_append_string; - gnome_keyring_attribute_list_append_uint32_ptr = - &::gnome_keyring_attribute_list_append_uint32; - - keyring_loaded = true; - // Reset the state of the mock library. - mock_keyring_items.clear(); - mock_keyring_reject_local_ids = false; - return true; - } -}; - -void CheckPasswordChanges(const PasswordStoreChangeList& expected_list, - const PasswordStoreChangeList& actual_list) { - ASSERT_EQ(expected_list.size(), actual_list.size()); - for (size_t i = 0; i < expected_list.size(); ++i) { - EXPECT_EQ(expected_list[i].type(), actual_list[i].type()); - const PasswordForm& expected = expected_list[i].form(); - const PasswordForm& actual = actual_list[i].form(); - - EXPECT_EQ(expected.origin, actual.origin); - EXPECT_EQ(expected.password_value, actual.password_value); - EXPECT_EQ(expected.action, actual.action); - EXPECT_EQ(expected.username_element, actual.username_element); - EXPECT_EQ(expected.username_value, actual.username_value); - EXPECT_EQ(expected.password_element, actual.password_element); - EXPECT_EQ(expected.submit_element, actual.submit_element); - EXPECT_EQ(expected.signon_realm, actual.signon_realm); - EXPECT_EQ(expected.preferred, actual.preferred); - EXPECT_EQ(expected.date_created, actual.date_created); - EXPECT_EQ(expected.blacklisted_by_user, actual.blacklisted_by_user); - EXPECT_EQ(expected.type, actual.type); - EXPECT_EQ(expected.times_used, actual.times_used); - EXPECT_EQ(expected.scheme, actual.scheme); - EXPECT_EQ(expected.date_synced, actual.date_synced); - EXPECT_EQ(expected.display_name, actual.display_name); - EXPECT_EQ(expected.icon_url, actual.icon_url); - EXPECT_EQ(expected.federation_origin.Serialize(), - actual.federation_origin.Serialize()); - EXPECT_EQ(expected.skip_zero_click, actual.skip_zero_click); - EXPECT_EQ(expected.generation_upload_status, - actual.generation_upload_status); - } -} - -void CheckPasswordChangesWithResult(const PasswordStoreChangeList* expected, - const PasswordStoreChangeList* actual, - bool result) { - EXPECT_TRUE(result); - CheckPasswordChanges(*expected, *actual); -} - -void CheckTrue(bool result) { - EXPECT_TRUE(result); -} - -} // anonymous namespace - -class NativeBackendGnomeTest : public testing::Test { - protected: - enum UpdateType { // Used in CheckPSLUpdate(). - UPDATE_BY_UPDATELOGIN, - UPDATE_BY_ADDLOGIN, - }; - - NativeBackendGnomeTest() {} - - void SetUp() override { - ASSERT_TRUE(MockGnomeKeyringLoader::LoadMockGnomeKeyring()); - - form_google_.origin = GURL("http://www.google.com/"); - form_google_.action = GURL("http://www.google.com/login"); - form_google_.username_element = UTF8ToUTF16("user"); - form_google_.username_value = UTF8ToUTF16("joeschmoe"); - form_google_.password_element = UTF8ToUTF16("pass"); - form_google_.password_value = UTF8ToUTF16("seekrit"); - form_google_.submit_element = UTF8ToUTF16("submit"); - form_google_.signon_realm = "http://www.google.com/"; - form_google_.type = PasswordForm::Type::kGenerated; - form_google_.date_created = base::Time::Now(); - form_google_.date_synced = base::Time::Now(); - form_google_.display_name = UTF8ToUTF16("Joe Schmoe"); - form_google_.icon_url = GURL("http://www.google.com/icon"); - form_google_.federation_origin = - url::Origin::Create(GURL("http://www.google.com/")); - form_google_.skip_zero_click = true; - form_google_.generation_upload_status = - PasswordForm::GenerationUploadStatus::kPositiveSignalSent; - form_google_.form_data.name = UTF8ToUTF16("form_name"); - - form_facebook_.origin = GURL("http://www.facebook.com/"); - form_facebook_.action = GURL("http://www.facebook.com/login"); - form_facebook_.username_element = UTF8ToUTF16("user"); - form_facebook_.username_value = UTF8ToUTF16("a"); - form_facebook_.password_element = UTF8ToUTF16("password"); - form_facebook_.password_value = UTF8ToUTF16("b"); - form_facebook_.submit_element = UTF8ToUTF16("submit"); - form_facebook_.signon_realm = "http://www.facebook.com/"; - form_facebook_.date_created = base::Time::Now(); - form_facebook_.date_synced = base::Time::Now(); - form_facebook_.display_name = UTF8ToUTF16("Joe Schmoe"); - form_facebook_.icon_url = GURL("http://www.facebook.com/icon"); - form_facebook_.federation_origin = - url::Origin::Create(GURL("http://www.facebook.com/")); - form_facebook_.skip_zero_click = true; - form_facebook_.generation_upload_status = - PasswordForm::GenerationUploadStatus::kNoSignalSent; - - form_isc_.origin = GURL("http://www.isc.org/"); - form_isc_.action = GURL("http://www.isc.org/auth"); - form_isc_.username_element = UTF8ToUTF16("id"); - form_isc_.username_value = UTF8ToUTF16("janedoe"); - form_isc_.password_element = UTF8ToUTF16("passwd"); - form_isc_.password_value = UTF8ToUTF16("ihazabukkit"); - form_isc_.submit_element = UTF8ToUTF16("login"); - form_isc_.signon_realm = "http://www.isc.org/"; - form_isc_.date_created = base::Time::Now(); - form_isc_.date_synced = base::Time::Now(); - - other_auth_.origin = GURL("http://www.example.com/"); - other_auth_.username_value = UTF8ToUTF16("username"); - other_auth_.password_value = UTF8ToUTF16("pass"); - other_auth_.signon_realm = "http://www.example.com/Realm"; - other_auth_.date_created = base::Time::Now(); - other_auth_.date_synced = base::Time::Now(); - } - - void CheckUint32Attribute(const MockKeyringItem* item, - const std::string& attribute, - uint32_t value) { - auto it = item->attributes.find(attribute); - EXPECT_NE(item->attributes.end(), it); - if (it != item->attributes.end()) { - EXPECT_EQ(MockKeyringItem::ItemAttribute::UINT32, it->second.type); - EXPECT_EQ(value, it->second.value_uint32); - } - } - - void CheckStringAttribute(const MockKeyringItem* item, - const std::string& attribute, - const std::string& value) { - auto it = item->attributes.find(attribute); - EXPECT_NE(item->attributes.end(), it); - if (it != item->attributes.end()) { - EXPECT_EQ(MockKeyringItem::ItemAttribute::STRING, it->second.type); - EXPECT_EQ(value, it->second.value_string); - } - } - - void CheckMockKeyringItem(const MockKeyringItem* item, - const PasswordForm& form, - const std::string& app_string) { - // We always add items to the login keyring. - EXPECT_EQ("login", item->keyring); - EXPECT_EQ(form.origin.spec(), item->display_name); - EXPECT_EQ(UTF16ToUTF8(form.password_value), item->password); - EXPECT_EQ(21u, item->attributes.size()); - CheckStringAttribute(item, "origin_url", form.origin.spec()); - CheckStringAttribute(item, "action_url", form.action.spec()); - CheckStringAttribute(item, "username_element", - UTF16ToUTF8(form.username_element)); - CheckStringAttribute(item, "username_value", - UTF16ToUTF8(form.username_value)); - CheckStringAttribute(item, "password_element", - UTF16ToUTF8(form.password_element)); - CheckStringAttribute(item, "submit_element", - UTF16ToUTF8(form.submit_element)); - CheckStringAttribute(item, "signon_realm", form.signon_realm); - CheckUint32Attribute(item, "preferred", form.preferred); - // We don't check the date created. It varies. - CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user); - CheckUint32Attribute(item, "type", static_cast<uint32_t>(form.type)); - CheckUint32Attribute(item, "times_used", form.times_used); - CheckUint32Attribute(item, "scheme", static_cast<uint32_t>(form.scheme)); - CheckStringAttribute( - item, "date_synced", - base::NumberToString(form.date_synced.ToInternalValue())); - CheckStringAttribute(item, "display_name", UTF16ToUTF8(form.display_name)); - CheckStringAttribute(item, "avatar_url", form.icon_url.spec()); - // We serialize unique origins as "", in order to make other systems that - // read from the login database happy. https://crbug.com/591310 - CheckStringAttribute(item, "federation_url", - form.federation_origin.opaque() - ? "" - : form.federation_origin.Serialize()); - CheckUint32Attribute(item, "should_skip_zero_click", form.skip_zero_click); - CheckUint32Attribute(item, "generation_upload_status", - static_cast<uint32_t>(form.generation_upload_status)); - CheckStringAttribute(item, "application", app_string); - autofill::FormData actual; - DeserializeFormDataFromBase64String( - item->attributes.at("form_data").value_string, &actual); - EXPECT_TRUE(form.form_data.SameFormAs(actual)); - } - - // Saves |credentials| and then gets logins matching |url| and |scheme|. - // Returns true when something is found, and in such case copies the result to - // |result| when |result| is not NULL. (Note that there can be max. 1 result, - // derived from |credentials|.) - bool CheckCredentialAvailability(const PasswordForm& credentials, - const GURL& url, - const PasswordForm::Scheme& scheme, - PasswordForm* result) { - NativeBackendGnome backend(321); - backend.Init(); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), credentials)); - - PasswordStore::FormDigest target_form = {scheme, url.spec(), url}; - if (scheme != PasswordForm::Scheme::kHtml) { - // For non-HTML forms, the realm used for authentication - // (http://tools.ietf.org/html/rfc1945#section-10.2) is appended to the - // signon_realm. Just use a default value for now. - target_form.signon_realm.append("Realm"); - } - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::GetLogins, base::Unretained(&backend), - target_form, &form_list), - base::Bind(&CheckTrue)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], credentials, "chrome-321"); - mock_keyring_items.clear(); - - if (form_list.empty()) - return false; - EXPECT_EQ(1u, form_list.size()); - if (result) - *result = *form_list[0]; - return true; - } - - // Test that updating does not use PSL matching: Add a www.facebook.com - // password, then use PSL matching to get a copy of it for m.facebook.com, and - // add that copy as well. Now update the www.facebook.com password -- the - // m.facebook.com password should not get updated. Depending on the argument, - // the credential update is done via UpdateLogin or AddLogin. - void CheckPSLUpdate(UpdateType update_type) { - NativeBackendGnome backend(321); - backend.Init(); - - // Add |form_facebook_| to saved logins. - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::AddLogin, base::Unretained(&backend), - form_facebook_), - base::Bind(&CheckPasswordChanges, - PasswordStoreChangeList( - 1, PasswordStoreChange(PasswordStoreChange::ADD, - form_facebook_)))); - - // Get the PSL-matched copy of the saved login for m.facebook. - const GURL kMobileURL("http://m.facebook.com/"); - PasswordStore::FormDigest m_facebook_lookup = { - PasswordForm::Scheme::kHtml, kMobileURL.spec(), kMobileURL}; - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::GetLogins, base::Unretained(&backend), - m_facebook_lookup, &form_list), - base::Bind(&CheckTrue)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - EXPECT_EQ(1u, form_list.size()); - PasswordForm m_facebook = *form_list[0]; - form_list.clear(); - m_facebook.origin = kMobileURL; - m_facebook.signon_realm = kMobileURL.spec(); - - // Add the PSL-matched copy to saved logins. - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), m_facebook)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(2u, mock_keyring_items.size()); - - // Update www.facebook.com login. - PasswordForm new_facebook(form_facebook_); - const base::string16 kOldPassword(form_facebook_.password_value); - const base::string16 kNewPassword(UTF8ToUTF16("new_b")); - EXPECT_NE(kOldPassword, kNewPassword); - new_facebook.password_value = kNewPassword; - PasswordStoreChangeList changes; - PasswordStoreChangeList expected_changes; - switch (update_type) { - case UPDATE_BY_UPDATELOGIN: - expected_changes.push_back( - PasswordStoreChange(PasswordStoreChange::UPDATE, new_facebook)); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::UpdateLogin, - base::Unretained(&backend), new_facebook, &changes), - base::Bind(&CheckPasswordChangesWithResult, &expected_changes, - &changes)); - break; - case UPDATE_BY_ADDLOGIN: - expected_changes.push_back( - PasswordStoreChange(PasswordStoreChange::REMOVE, form_facebook_)); - expected_changes.push_back( - PasswordStoreChange(PasswordStoreChange::ADD, new_facebook)); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::AddLogin, - base::Unretained(&backend), new_facebook), - base::Bind(&CheckPasswordChanges, expected_changes)); - break; - } - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(2u, mock_keyring_items.size()); - - // Check that m.facebook.com login was not modified by the update. - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::GetLogins, base::Unretained(&backend), - m_facebook_lookup, &form_list), - base::Bind(&CheckTrue)); - - test_browser_thread_bundle_.RunUntilIdle(); - - // There should be two results -- the exact one, and the PSL-matched one. - EXPECT_EQ(2u, form_list.size()); - size_t index_non_psl = 0; - if (form_list[index_non_psl]->is_public_suffix_match) - index_non_psl = 1; - EXPECT_EQ(kMobileURL, form_list[index_non_psl]->origin); - EXPECT_EQ(kMobileURL.spec(), form_list[index_non_psl]->signon_realm); - EXPECT_EQ(kOldPassword, form_list[index_non_psl]->password_value); - form_list.clear(); - - // Check that www.facebook.com login was modified by the update. - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::GetLogins, base::Unretained(&backend), - PasswordStore::FormDigest(form_facebook_), &form_list), - base::Bind(&CheckTrue)); - - test_browser_thread_bundle_.RunUntilIdle(); - - // There should be two results -- the exact one, and the PSL-matched one. - EXPECT_EQ(2u, form_list.size()); - index_non_psl = 0; - if (form_list[index_non_psl]->is_public_suffix_match) - index_non_psl = 1; - EXPECT_EQ(form_facebook_.origin, form_list[index_non_psl]->origin); - EXPECT_EQ(form_facebook_.signon_realm, - form_list[index_non_psl]->signon_realm); - EXPECT_EQ(kNewPassword, form_list[index_non_psl]->password_value); - } - - void CheckMatchingWithScheme(const PasswordForm::Scheme& scheme) { - other_auth_.scheme = scheme; - - // Don't match a non-HTML form with an HTML form. - EXPECT_FALSE( - CheckCredentialAvailability(other_auth_, GURL("http://www.example.com"), - PasswordForm::Scheme::kHtml, nullptr)); - // Don't match an HTML form with non-HTML auth form. - EXPECT_FALSE(CheckCredentialAvailability( - form_google_, GURL("http://www.google.com/"), scheme, nullptr)); - // Don't match two different non-HTML auth forms with different origin. - EXPECT_FALSE(CheckCredentialAvailability( - other_auth_, GURL("http://first.example.com"), scheme, nullptr)); - // Do match non-HTML forms from the same origin. - EXPECT_TRUE(CheckCredentialAvailability( - other_auth_, GURL("http://www.example.com/"), scheme, nullptr)); - } - - content::TestBrowserThreadBundle test_browser_thread_bundle_; - - // Provide some test forms to avoid having to set them up in each test. - PasswordForm form_google_; - PasswordForm form_facebook_; - PasswordForm form_isc_; - PasswordForm other_auth_; -}; - -TEST_F(NativeBackendGnomeTest, BasicAddLogin) { - NativeBackendGnome backend(42); - backend.Init(); - - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::AddLogin, base::Unretained(&backend), - form_google_), - base::Bind( - &CheckPasswordChanges, - PasswordStoreChangeList( - 1, PasswordStoreChange(PasswordStoreChange::ADD, form_google_)))); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); -} - -TEST_F(NativeBackendGnomeTest, BasicListLogins) { - NativeBackendGnome backend(42); - backend.Init(); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::GetAutofillableLogins, - base::Unretained(&backend), &form_list), - base::Bind(&CheckTrue)); - - test_browser_thread_bundle_.RunUntilIdle(); - - // Quick check that we got something back. - EXPECT_EQ(1u, form_list.size()); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); -} - -// Save a password for www.facebook.com and see it suggested for m.facebook.com. -TEST_F(NativeBackendGnomeTest, PSLMatchingPositive) { - PasswordForm result; - const GURL kMobileURL("http://m.facebook.com/"); - EXPECT_TRUE(CheckCredentialAvailability( - form_facebook_, kMobileURL, PasswordForm::Scheme::kHtml, &result)); - EXPECT_EQ(form_facebook_.origin, result.origin); - EXPECT_EQ(form_facebook_.signon_realm, result.signon_realm); -} - -// Save a password for www.facebook.com and see it not suggested for -// m-facebook.com. -TEST_F(NativeBackendGnomeTest, PSLMatchingNegativeDomainMismatch) { - EXPECT_FALSE(CheckCredentialAvailability( - form_facebook_, GURL("http://m-facebook.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -// Test PSL matching is off for domains excluded from it. -TEST_F(NativeBackendGnomeTest, PSLMatchingDisabledDomains) { - EXPECT_FALSE( - CheckCredentialAvailability(form_google_, GURL("http://one.google.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -// Make sure PSL matches aren't available for non-HTML forms. -TEST_F(NativeBackendGnomeTest, PSLMatchingDisabledForNonHTMLForms) { - CheckMatchingWithScheme(PasswordForm::Scheme::kBasic); - CheckMatchingWithScheme(PasswordForm::Scheme::kDigest); - CheckMatchingWithScheme(PasswordForm::Scheme::kOther); -} - -TEST_F(NativeBackendGnomeTest, PSLUpdatingStrictUpdateLogin) { - CheckPSLUpdate(UPDATE_BY_UPDATELOGIN); -} - -TEST_F(NativeBackendGnomeTest, PSLUpdatingStrictAddLogin) { - CheckPSLUpdate(UPDATE_BY_ADDLOGIN); -} - -TEST_F(NativeBackendGnomeTest, FetchFederatedCredentialOnHTTPS) { - other_auth_.signon_realm = "federation://www.example.com/google.com"; - other_auth_.origin = GURL("https://www.example.com/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_TRUE( - CheckCredentialAvailability(other_auth_, GURL("https://www.example.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendGnomeTest, FetchFederatedCredentialOnLocalhost) { - other_auth_.signon_realm = "federation://localhost/google.com"; - other_auth_.origin = GURL("http://localhost:8080/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_TRUE( - CheckCredentialAvailability(other_auth_, GURL("http://localhost:8080/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendGnomeTest, DontFetchFederatedCredentialOnHTTP) { - other_auth_.signon_realm = "federation://www.example.com/google.com"; - other_auth_.origin = GURL("https://www.example.com/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_FALSE( - CheckCredentialAvailability(other_auth_, GURL("http://www.example.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendGnomeTest, FetchPSLMatchedFederatedCredentialOnHTTPS) { - other_auth_.signon_realm = "federation://www.sub.example.com/google.com"; - other_auth_.origin = GURL("https://www.sub.example.com/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_TRUE( - CheckCredentialAvailability(other_auth_, GURL("https://www.example.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendGnomeTest, DontFetchPSLMatchedFederatedCredentialOnHTTP) { - other_auth_.signon_realm = "federation://www.sub.example.com/google.com"; - other_auth_.origin = GURL("https://www.sub.example.com/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_FALSE( - CheckCredentialAvailability(other_auth_, GURL("http://www.example.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendGnomeTest, BasicUpdateLogin) { - NativeBackendGnome backend(42); - backend.Init(); - - // First add google login. - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - - test_browser_thread_bundle_.RunUntilIdle(); - - PasswordForm new_form_google(form_google_); - new_form_google.times_used = 1; - new_form_google.action = GURL("http://www.google.com/different/login"); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); - - // Update login - PasswordStoreChangeList changes; - PasswordStoreChangeList expected_changes( - 1, PasswordStoreChange(PasswordStoreChange::UPDATE, new_form_google)); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::UpdateLogin, base::Unretained(&backend), - new_form_google, &changes), - base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], new_form_google, "chrome-42"); -} - -TEST_F(NativeBackendGnomeTest, BasicRemoveLogin) { - NativeBackendGnome backend(42); - backend.Init(); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); - - PasswordStoreChangeList changes; - PasswordStoreChangeList expected_changes( - 1, PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_)); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::RemoveLogin, base::Unretained(&backend), - form_google_, &changes), - base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(0u, mock_keyring_items.size()); -} - -// Verify fix for http://crbug.com/408783. -TEST_F(NativeBackendGnomeTest, RemoveLoginActionMismatch) { - NativeBackendGnome backend(42); - backend.Init(); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); - - // Action url match not required for removal. - form_google_.action = GURL("https://some.other.url.com/path"); - - PasswordStoreChangeList changes; - PasswordStoreChangeList expected_changes( - 1, PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_)); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::RemoveLogin, base::Unretained(&backend), - form_google_, &changes), - base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(0u, mock_keyring_items.size()); -} - -TEST_F(NativeBackendGnomeTest, RemoveNonexistentLogin) { - NativeBackendGnome backend(42); - backend.Init(); - - // First add an unrelated login. - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); - - // Attempt to remove a login that doesn't exist. - PasswordStoreChangeList changes; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::RemoveLogin, base::Unretained(&backend), - form_isc_, &changes), - base::Bind(&CheckPasswordChangesWithResult, - base::Owned(new PasswordStoreChangeList), &changes)); - - // Make sure we can still get the first form back. - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::GetAutofillableLogins, - base::Unretained(&backend), &form_list), - base::Bind(&CheckTrue)); - - test_browser_thread_bundle_.RunUntilIdle(); - - // Quick check that we got something back. - EXPECT_EQ(1u, form_list.size()); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); -} - -TEST_F(NativeBackendGnomeTest, UpdateNonexistentLogin) { - NativeBackendGnome backend(42); - backend.Init(); - - // First add an unrelated login. - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); - - // Attempt to update a login that doesn't exist. - PasswordStoreChangeList changes; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::UpdateLogin, base::Unretained(&backend), - form_isc_, &changes), - base::Bind(&CheckPasswordChangesWithResult, - base::Owned(new PasswordStoreChangeList), &changes)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); -} - -TEST_F(NativeBackendGnomeTest, UpdateSameLogin) { - NativeBackendGnome backend(42); - backend.Init(); - - // First add an unrelated login. - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); - - // Attempt to update the same login without changing anything. - PasswordStoreChangeList changes; - PasswordStoreChangeList expected_changes; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::UpdateLogin, base::Unretained(&backend), - form_google_, &changes), - base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); -} - -TEST_F(NativeBackendGnomeTest, AddDuplicateLogin) { - NativeBackendGnome backend(42); - backend.Init(); - - PasswordStoreChangeList changes; - changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, - form_google_)); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::AddLogin, base::Unretained(&backend), - form_google_), - base::Bind(&CheckPasswordChanges, changes)); - - changes.clear(); - changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, - form_google_)); - form_google_.times_used++; - form_google_.submit_element = UTF8ToUTF16("submit2"); - changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, - form_google_)); - - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::AddLogin, base::Unretained(&backend), - form_google_), - base::Bind(&CheckPasswordChanges, changes)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); -} - -TEST_F(NativeBackendGnomeTest, AndroidCredentials) { - NativeBackendGnome backend(42); - backend.Init(); - - PasswordForm saved_android_form; - saved_android_form.scheme = PasswordForm::Scheme::kHtml; - saved_android_form.signon_realm = - "android://7x7IDboo8u9YKraUsbmVkuf1-@net.rateflix.app/"; - saved_android_form.username_value = base::UTF8ToUTF16("randomusername"); - saved_android_form.password_value = base::UTF8ToUTF16("password"); - saved_android_form.date_created = base::Time::Now(); - - PasswordStore::FormDigest observed_android_form(saved_android_form); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::AddLogin, base::Unretained(&backend), - saved_android_form), - base::Bind(&CheckPasswordChanges, - PasswordStoreChangeList( - 1, PasswordStoreChange(PasswordStoreChange::ADD, - saved_android_form)))); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::GetLogins, base::Unretained(&backend), - observed_android_form, &form_list), - base::Bind(&CheckTrue)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, form_list.size()); - EXPECT_EQ(saved_android_form, *form_list[0]); -} - -TEST_F(NativeBackendGnomeTest, RemoveLoginsCreatedBetween) { - NativeBackendGnome backend(42); - backend.Init(); - - base::Time now = base::Time::Now(); - base::Time next_day = now + base::TimeDelta::FromDays(1); - form_google_.date_created = now; - form_isc_.date_created = next_day; - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_isc_)); - - PasswordStoreChangeList expected_changes; - expected_changes.emplace_back(PasswordStoreChange::REMOVE, form_google_); - PasswordStoreChangeList changes; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::BindOnce(&NativeBackendGnome::RemoveLoginsCreatedBetween, - base::Unretained(&backend), base::Time(), next_day, - &changes), - base::BindOnce(&CheckPasswordChangesWithResult, &expected_changes, - &changes)); - - test_browser_thread_bundle_.RunUntilIdle(); - - ASSERT_EQ(1u, mock_keyring_items.size()); - CheckMockKeyringItem(&mock_keyring_items[0], form_isc_, "chrome-42"); - - // Remove form_isc_. - expected_changes.clear(); - expected_changes.emplace_back(PasswordStoreChange::REMOVE, form_isc_); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::BindOnce(&NativeBackendGnome::RemoveLoginsCreatedBetween, - base::Unretained(&backend), next_day, base::Time(), - &changes), - base::BindOnce(&CheckPasswordChangesWithResult, &expected_changes, - &changes)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_TRUE(mock_keyring_items.empty()); -} - -TEST_F(NativeBackendGnomeTest, DisableAutoSignInForOrigins) { - NativeBackendGnome backend(42); - backend.Init(); - form_google_.skip_zero_click = false; - form_facebook_.skip_zero_click = false; - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_facebook_)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(2u, mock_keyring_items.size()); - for (const auto& item : mock_keyring_items) - CheckUint32Attribute(&item, "should_skip_zero_click", 0); - - // Set the canonical forms to the updated value for the following comparison. - form_google_.skip_zero_click = true; - form_facebook_.skip_zero_click = true; - PasswordStoreChangeList expected_changes; - expected_changes.push_back( - PasswordStoreChange(PasswordStoreChange::UPDATE, form_facebook_)); - - PasswordStoreChangeList changes; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind( - &NativeBackendGnome::DisableAutoSignInForOrigins, - base::Unretained(&backend), - base::Bind( - static_cast<bool (*)(const GURL&, const GURL&)>(operator==), - form_facebook_.origin), - &changes), - base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(2u, mock_keyring_items.size()); - CheckStringAttribute( - &mock_keyring_items[0], "origin_url", form_google_.origin.spec()); - CheckUint32Attribute(&mock_keyring_items[0], "should_skip_zero_click", 0); - CheckStringAttribute( - &mock_keyring_items[1], "origin_url", form_facebook_.origin.spec()); - CheckUint32Attribute(&mock_keyring_items[1], "should_skip_zero_click", 1); -} - -TEST_F(NativeBackendGnomeTest, ReadDuplicateForms) { - NativeBackendGnome backend(42); - backend.Init(); - - // Add 2 slightly different password forms. - const char unique_string[] = "unique_unique_string"; - const char unique_string_replacement[] = "uniKue_unique_string"; - form_google_.origin = - GURL(std::string("http://www.google.com/") + unique_string); - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - form_google_.origin = - GURL(std::string("http://www.google.com/") + unique_string_replacement); - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - - test_browser_thread_bundle_.RunUntilIdle(); - - // Read the raw value back. Change the |unique_string| to - // |unique_string_replacement| so the forms become unique. - ASSERT_EQ(2u, mock_keyring_items.size()); - auto it = mock_keyring_items[0].attributes.find("origin_url"); - ASSERT_NE(mock_keyring_items[0].attributes.end(), it); - size_t position = it->second.value_string.find(unique_string); - ASSERT_NE(std::string::npos, position) << it->second.value_string; - it->second.value_string.replace( - position, std::string(unique_string_replacement).length(), - unique_string_replacement); - - // Now test that GetAutofillableLogins returns only one form. - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::GetAutofillableLogins, - base::Unretained(&backend), &form_list), - base::Bind(&CheckTrue)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(1u, form_list.size()); - EXPECT_EQ(form_google_, *form_list[0]); - - EXPECT_EQ(1u, mock_keyring_items.size()); - if (mock_keyring_items.size() > 0) - CheckMockKeyringItem(&mock_keyring_items[0], form_google_, "chrome-42"); -} - -TEST_F(NativeBackendGnomeTest, GetAllLogins) { - NativeBackendGnome backend(42); - backend.Init(); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_google_)); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendGnome::AddLogin), - base::Unretained(&backend), form_facebook_)); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendGnome::GetAllLogins, base::Unretained(&backend), - &form_list), - base::Bind(&CheckTrue)); - - test_browser_thread_bundle_.RunUntilIdle(); - - EXPECT_EQ(2u, form_list.size()); - EXPECT_THAT(form_list, UnorderedElementsAre(Pointee(form_google_), - Pointee(form_facebook_))); -} - -// TODO(mdm): add more basic tests here at some point.
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.cc b/chrome/browser/password_manager/native_backend_kwallet_x.cc deleted file mode 100644 index ed1c42c..0000000 --- a/chrome/browser/password_manager/native_backend_kwallet_x.cc +++ /dev/null
@@ -1,826 +0,0 @@ -// Copyright (c) 2012 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/password_manager/native_backend_kwallet_x.h" - -#include <stddef.h> -#include <stdint.h> - -#include <iterator> -#include <map> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/logging.h" -#include "base/metrics/histogram_macros.h" -#include "base/pickle.h" -#include "base/stl_util.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" -#include "base/task/post_task.h" -#include "base/threading/thread_restrictions.h" -#include "chrome/grit/chromium_strings.h" -#include "components/autofill/core/common/password_form.h" -#include "components/dbus/thread_linux/dbus_thread_linux.h" -#include "components/password_manager/core/browser/password_manager_util.h" -#include "dbus/bus.h" -#include "dbus/message.h" -#include "dbus/object_path.h" -#include "ui/base/l10n/l10n_util.h" -#include "url/origin.h" - -using autofill::PasswordForm; - -namespace { - -// In case the fields in the pickle ever change, version them so we can try to -// read old pickles. (Note: do not eat old pickles past the expiration date.) -const int kPickleVersion = 9; - -// We could localize this string, but then changing your locale would cause -// you to lose access to all your stored passwords. Maybe best not to do that. -// Name of the folder to store passwords in. -const char kKWalletFolder[] = "Chrome Form Data"; - -// Checks a serialized list of PasswordForms for sanity. Returns true if OK. -// Note that |realm| is only used for generating a useful warning message. -bool CheckSerializedValue(const uint8_t* byte_array, - size_t length, - const std::string& realm) { - const base::Pickle::Header* header = - reinterpret_cast<const base::Pickle::Header*>(byte_array); - if (length < sizeof(*header) || - header->payload_size > length - sizeof(*header)) { - LOG(WARNING) << "Invalid KWallet entry detected (realm: " << realm << ")"; - return false; - } - return true; -} - -// Convenience function to read a GURL from a Pickle. Assumes the URL has -// been written as a UTF-8 string. Returns true on success. -bool ReadGURL(base::PickleIterator* iter, bool warn_only, GURL* url) { - std::string url_string; - if (!iter->ReadString(&url_string)) { - if (!warn_only) - LOG(ERROR) << "Failed to deserialize URL."; - *url = GURL(); - return false; - } - *url = GURL(url_string); - return true; -} - -// Convenience function to read a url::Origin from a Pickle. Assumes the origin -// has been written as a UTF-8 string. Returns true on success. -bool ReadOrigin(base::PickleIterator* iter, - bool warn_only, - url::Origin* origin) { - std::string origin_string; - if (!iter->ReadString(&origin_string)) { - if (!warn_only) - LOG(ERROR) << "Failed to deserialize Origin."; - *origin = url::Origin(); - return false; - } - *origin = url::Origin::Create(GURL(origin_string)); - return true; -} - -void LogDeserializationWarning(int version, - std::string signon_realm, - bool warn_only) { - if (warn_only) { - LOG(WARNING) << "Failed to deserialize version " << version - << " KWallet entry (realm: " << signon_realm - << ") with native architecture size; will try alternate " - << "size."; - } else { - LOG(ERROR) << "Failed to deserialize version " << version - << " KWallet entry (realm: " << signon_realm << ")"; - } -} - -// Deserializes a list of credentials from the wallet to |forms| (replacing -// the contents of |forms|). |size_32| controls reading the size field within -// the pickle as 32 bits. We used to use Pickle::WriteSize() to write the number -// of password forms, but that has a different size on 32- and 64-bit systems. -// So, now we always write a 64-bit quantity, but we support trying to read it -// as either size when reading old pickles that fail to deserialize using the -// native size. Returns true on success. -bool DeserializeValueSize(const std::string& signon_realm, - const base::PickleIterator& init_iter, - int version, - bool size_32, - bool warn_only, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - base::PickleIterator iter = init_iter; - - size_t count = 0; - if (size_32) { - uint32_t count_32 = 0; - if (!iter.ReadUInt32(&count_32)) { - LOG(ERROR) << "Failed to deserialize KWallet entry " - << "(realm: " << signon_realm << ")"; - return false; - } - count = count_32; - } else { - uint64_t count_64 = 0; - if (!iter.ReadUInt64(&count_64)) { - LOG(ERROR) << "Failed to deserialize KWallet entry " - << "(realm: " << signon_realm << ")"; - return false; - } - count = static_cast<size_t>(count_64); - } - - if (count > 0xFFFF) { - // Trying to pin down the cause of http://crbug.com/80728 (or fix it). - // This is a very large number of passwords to be saved for a single realm. - // It is almost certainly a corrupt pickle and not real data. Ignore it. - // This very well might actually be http://crbug.com/107701, so if we're - // reading an old pickle, we don't even log this the first time we try to - // read it. (That is, when we're reading the native architecture size.) - if (!warn_only) { - LOG(ERROR) << "Suspiciously large number of entries in KWallet entry " - << "(" << count << "; realm: " << signon_realm << ")"; - } - return false; - } - - // We'll swap |converted_forms| with |*forms| on success, to make sure we - // don't return partial results on failure. - std::vector<std::unique_ptr<PasswordForm>> converted_forms; - converted_forms.reserve(count); - for (size_t i = 0; i < count; ++i) { - std::unique_ptr<PasswordForm> form(new PasswordForm()); - form->signon_realm.assign(signon_realm); - - int scheme = 0; - int64_t date_created = 0; - int type = 0; - int generation_upload_status = 0; - // Note that these will be read back in the order listed due to - // short-circuit evaluation. This is important. - if (!iter.ReadInt(&scheme) || !ReadGURL(&iter, warn_only, &form->origin) || - !ReadGURL(&iter, warn_only, &form->action) || - !iter.ReadString16(&form->username_element) || - !iter.ReadString16(&form->username_value) || - !iter.ReadString16(&form->password_element) || - !iter.ReadString16(&form->password_value) || - !iter.ReadString16(&form->submit_element)) { - LogDeserializationWarning(version, signon_realm, warn_only); - return false; - } - if (version <= 8) { - bool dummy_unused_flag = false; - if (!iter.ReadBool(&dummy_unused_flag)) { - LogDeserializationWarning(version, signon_realm, warn_only); - return false; - } - } - if (!iter.ReadBool(&form->preferred) || - !iter.ReadBool(&form->blacklisted_by_user) || - !iter.ReadInt64(&date_created)) { - LogDeserializationWarning(version, signon_realm, warn_only); - return false; - } - form->scheme = static_cast<PasswordForm::Scheme>(scheme); - - if (version > 1) { - if (!iter.ReadInt(&type) || - !iter.ReadInt(&form->times_used) || - !autofill::DeserializeFormData(&iter, &form->form_data)) { - LogDeserializationWarning(version, signon_realm, false); - return false; - } - form->type = static_cast<PasswordForm::Type>(type); - } - - if (version > 2) { - int64_t date_synced = 0; - if (!iter.ReadInt64(&date_synced)) { - LogDeserializationWarning(version, signon_realm, false); - return false; - } - form->date_synced = base::Time::FromInternalValue(date_synced); - } - - if (version > 3) { - if (!iter.ReadString16(&form->display_name) || - !ReadGURL(&iter, warn_only, &form->icon_url) || - !ReadOrigin(&iter, warn_only, &form->federation_origin) || - !iter.ReadBool(&form->skip_zero_click)) { - LogDeserializationWarning(version, signon_realm, false); - return false; - } - if (version <= 7) - form->skip_zero_click = true; - } - - if (version > 4) { - form->date_created = base::Time::FromInternalValue(date_created); - } else { - form->date_created = base::Time::FromTimeT(date_created); - } - - if (version > 5) { - bool read_success = iter.ReadInt(&generation_upload_status); - if (!read_success && version > 6) { - // Valid version 6 pickles might still lack the - // generation_upload_status, see http://crbug.com/494229#c11. - LogDeserializationWarning(version, signon_realm, false); - return false; - } - if (read_success) { - form->generation_upload_status = - static_cast<PasswordForm::GenerationUploadStatus>( - generation_upload_status); - } - } - - converted_forms.push_back(std::move(form)); - } - - forms->swap(converted_forms); - return true; -} - -// Serializes a list of PasswordForms to be stored in the wallet. -void SerializeValue(const std::vector<std::unique_ptr<PasswordForm>>& forms, - base::Pickle* pickle) { - pickle->WriteInt(kPickleVersion); - pickle->WriteUInt64(forms.size()); - for (const auto& form : forms) { - pickle->WriteInt(static_cast<int>(form->scheme)); - pickle->WriteString(form->origin.spec()); - pickle->WriteString(form->action.spec()); - pickle->WriteString16(form->username_element); - pickle->WriteString16(form->username_value); - pickle->WriteString16(form->password_element); - pickle->WriteString16(form->password_value); - pickle->WriteString16(form->submit_element); - pickle->WriteBool(form->preferred); - pickle->WriteBool(form->blacklisted_by_user); - pickle->WriteInt64(form->date_created.ToInternalValue()); - pickle->WriteInt(static_cast<int>(form->type)); - pickle->WriteInt(form->times_used); - autofill::SerializeFormData(form->form_data, pickle); - pickle->WriteInt64(form->date_synced.ToInternalValue()); - pickle->WriteString16(form->display_name); - pickle->WriteString(form->icon_url.spec()); - // We serialize unique origins as "", in order to make other systems that - // read from the login database happy. https://crbug.com/591310 - pickle->WriteString(form->federation_origin.opaque() - ? std::string() - : form->federation_origin.Serialize()); - pickle->WriteBool(form->skip_zero_click); - pickle->WriteInt(static_cast<int>(form->generation_upload_status)); - } -} - -} // namespace - -// Using USER_VISIBLE priority, because the passwords obtained through tasks on -// the background runner influence what the user sees. -NativeBackendKWallet::NativeBackendKWallet( - LocalProfileId id, - base::nix::DesktopEnvironment desktop_env) - : profile_id_(id), - kwallet_dbus_(desktop_env), - app_name_(l10n_util::GetStringUTF8(IDS_PRODUCT_NAME)) { - folder_name_ = GetProfileSpecificFolderName(); -} - -NativeBackendKWallet::~NativeBackendKWallet() { - // This destructor is called on the thread that is destroying the Profile - // containing the PasswordStore that owns this NativeBackend. Generally that - // won't be run by the background task runner; it will be on the main one. So - // we post a message to shut it down on the background task runner, and it - // will be destroyed afterward when the scoped_refptr<dbus::Bus> goes out of - // scope. The NativeBackend will be destroyed before that occurs, but that's - // OK. - if (kwallet_dbus_.GetSessionBus()) { - dbus_thread_linux::GetTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock, - kwallet_dbus_.GetSessionBus())); - } -} - -bool NativeBackendKWallet::Init() { - // Without the |optional_bus| parameter, a real bus will be instantiated. - return InitWithBus(scoped_refptr<dbus::Bus>()); -} - -bool NativeBackendKWallet::InitWithBus(scoped_refptr<dbus::Bus> optional_bus) { - // We must synchronously do a few DBus calls to figure out if initialization - // succeeds, but later, we'll want to do most of the work on the background - // task runner. So we have to do the initialization on the background task - // runner here too, and wait for it. - bool success = false; - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); - // NativeBackendKWallet isn't reference counted, but we wait for InitWithBus - // to finish, so we can safely use base::Unretained here. - dbus_thread_linux::GetTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(&NativeBackendKWallet::InitOnBackgroundTaskRunner, - base::Unretained(this), optional_bus, &event, &success)); - - // This ScopedAllowBaseSyncPrimitives should not be here. However, the whole - // backend is so close to deprecation that it does not make sense to refactor - // it. More info on https://crbug.com/739897. - base::ScopedAllowBaseSyncPrimitives allow_wait; - event.Wait(); - return success; -} - -void NativeBackendKWallet::InitOnBackgroundTaskRunner( - scoped_refptr<dbus::Bus> optional_bus, - base::WaitableEvent* event, - bool* success) { - DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence()); - DCHECK(!kwallet_dbus_.GetSessionBus()); - if (optional_bus.get()) { - // The optional_bus parameter is given when this method is called in tests. - kwallet_dbus_.SetSessionBus(optional_bus); - } else { - // Get a (real) connection to the session bus. - dbus::Bus::Options options; - options.bus_type = dbus::Bus::SESSION; - options.connection_type = dbus::Bus::PRIVATE; - kwallet_dbus_.SetSessionBus(new dbus::Bus(options)); - } - // kwalletd may not be running. If we get a temporary failure initializing it, - // try to start it and then try again. (Note the short-circuit evaluation.) - const InitResult result = InitWallet(); - *success = (result == INIT_SUCCESS || - (result == TEMPORARY_FAIL && kwallet_dbus_.StartKWalletd() && - InitWallet() == INIT_SUCCESS)); - event->Signal(); -} - -NativeBackendKWallet::InitResult NativeBackendKWallet::InitWallet() { - DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence()); - - // Check that KWallet is enabled. - bool enabled = false; - KWalletDBus::Error error = kwallet_dbus_.IsEnabled(&enabled); - switch (error) { - case KWalletDBus::Error::CANNOT_CONTACT: - return TEMPORARY_FAIL; - case KWalletDBus::Error::CANNOT_READ: - return PERMANENT_FAIL; - case KWalletDBus::Error::SUCCESS: - break; - } - if (!enabled) - return PERMANENT_FAIL; - - // Get the wallet name. - error = kwallet_dbus_.NetworkWallet(&wallet_name_); - switch (error) { - case KWalletDBus::Error::CANNOT_CONTACT: - return TEMPORARY_FAIL; - case KWalletDBus::Error::CANNOT_READ: - return PERMANENT_FAIL; - case KWalletDBus::Error::SUCCESS: - return INIT_SUCCESS; - } - - NOTREACHED(); - return PERMANENT_FAIL; -} - -password_manager::PasswordStoreChangeList NativeBackendKWallet::AddLogin( - const PasswordForm& form) { - int wallet_handle = WalletHandle(); - if (wallet_handle == kInvalidKWalletHandle) - return password_manager::PasswordStoreChangeList(); - - std::vector<std::unique_ptr<PasswordForm>> forms; - if (!GetLoginsList(form.signon_realm, wallet_handle, &forms)) - return password_manager::PasswordStoreChangeList(); - - auto it = std::partition( - forms.begin(), forms.end(), - [&form](const std::unique_ptr<PasswordForm>& current_form) { - return !ArePasswordFormUniqueKeysEqual(form, *current_form); - }); - password_manager::PasswordStoreChangeList changes; - if (it != forms.end()) { - // It's an update. - changes.push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::REMOVE, **it)); - forms.erase(it, forms.end()); - } - - forms.push_back(std::make_unique<PasswordForm>(form)); - changes.push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::ADD, form)); - - bool ok = SetLoginsList(forms, form.signon_realm, wallet_handle); - if (!ok) - changes.clear(); - - return changes; -} - -bool NativeBackendKWallet::UpdateLogin( - const PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) { - DCHECK(changes); - int wallet_handle = WalletHandle(); - if (wallet_handle == kInvalidKWalletHandle) - return false; - - std::vector<std::unique_ptr<PasswordForm>> forms; - if (!GetLoginsList(form.signon_realm, wallet_handle, &forms)) - return false; - - auto it = std::partition( - forms.begin(), forms.end(), - [&form](const std::unique_ptr<PasswordForm>& current_form) { - return !ArePasswordFormUniqueKeysEqual(form, *current_form); - }); - - if (it == forms.end()) - return true; - - forms.erase(it, forms.end()); - forms.push_back(std::make_unique<PasswordForm>(form)); - if (SetLoginsList(forms, form.signon_realm, wallet_handle)) { - changes->push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::UPDATE, form)); - return true; - } - - return false; -} - -bool NativeBackendKWallet::RemoveLogin( - const PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) { - DCHECK(changes); - int wallet_handle = WalletHandle(); - if (wallet_handle == kInvalidKWalletHandle) - return false; - - std::vector<std::unique_ptr<PasswordForm>> all_forms; - if (!GetLoginsList(form.signon_realm, wallet_handle, &all_forms)) - return false; - - std::vector<std::unique_ptr<PasswordForm>> kept_forms; - kept_forms.reserve(all_forms.size()); - for (std::unique_ptr<PasswordForm>& saved_form : all_forms) { - if (!ArePasswordFormUniqueKeysEqual(form, *saved_form)) { - kept_forms.push_back(std::move(saved_form)); - } - } - - if (kept_forms.size() != all_forms.size()) { - changes->push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::REMOVE, form)); - return SetLoginsList(kept_forms, form.signon_realm, wallet_handle); - } - - return true; -} - -bool NativeBackendKWallet::RemoveLoginsCreatedBetween( - base::Time delete_begin, - base::Time delete_end, - password_manager::PasswordStoreChangeList* changes) { - DCHECK(changes); - changes->clear(); - int wallet_handle = WalletHandle(); - if (wallet_handle == kInvalidKWalletHandle) - return false; - - // We could probably also use readEntryList here. - std::vector<std::string> realm_list; - KWalletDBus::Error error = kwallet_dbus_.EntryList( - wallet_handle, folder_name_, app_name_, &realm_list); - if (error) - return false; - - bool ok = true; - for (const auto& signon_realm : realm_list) { - std::vector<uint8_t> bytes; - KWalletDBus::Error error = kwallet_dbus_.ReadEntry( - wallet_handle, folder_name_, signon_realm, app_name_, &bytes); - if (error) - continue; - if (bytes.empty() || - !CheckSerializedValue(bytes.data(), bytes.size(), signon_realm)) { - continue; - } - - // Can't we all just agree on whether bytes are signed or not? Please? - base::Pickle pickle(reinterpret_cast<const char*>(bytes.data()), - bytes.size()); - std::vector<std::unique_ptr<PasswordForm>> all_forms = - DeserializeValue(signon_realm, pickle); - - std::vector<std::unique_ptr<PasswordForm>> kept_forms; - kept_forms.reserve(all_forms.size()); - for (auto& saved_form : all_forms) { - if (delete_begin <= saved_form->date_created && - (delete_end.is_null() || saved_form->date_created < delete_end)) { - changes->emplace_back(password_manager::PasswordStoreChange::REMOVE, - *saved_form); - } else { - kept_forms.push_back(std::move(saved_form)); - } - } - - if (!SetLoginsList(kept_forms, signon_realm, wallet_handle)) { - ok = false; - changes->clear(); - } - } - return ok; -} - -bool NativeBackendKWallet::DisableAutoSignInForOrigins( - const base::Callback<bool(const GURL&)>& origin_filter, - password_manager::PasswordStoreChangeList* changes) { - std::vector<std::unique_ptr<PasswordForm>> all_forms; - if (!GetAllLogins(&all_forms)) - return false; - - for (const std::unique_ptr<PasswordForm>& form : all_forms) { - if (origin_filter.Run(form->origin) && !form->skip_zero_click) { - form->skip_zero_click = true; - if (!UpdateLogin(*form, changes)) - return false; - } - } - return true; -} - -bool NativeBackendKWallet::GetLogins( - const password_manager::PasswordStore::FormDigest& form, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - int wallet_handle = WalletHandle(); - if (wallet_handle == kInvalidKWalletHandle) - return false; - return GetLoginsList(form.signon_realm, wallet_handle, forms); -} - -bool NativeBackendKWallet::GetAutofillableLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - int wallet_handle = WalletHandle(); - if (wallet_handle == kInvalidKWalletHandle) - return false; - return GetLoginsList(BlacklistOptions::AUTOFILLABLE, wallet_handle, forms); -} - -bool NativeBackendKWallet::GetBlacklistLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - int wallet_handle = WalletHandle(); - if (wallet_handle == kInvalidKWalletHandle) - return false; - return GetLoginsList(BlacklistOptions::BLACKLISTED, wallet_handle, forms); -} - -bool NativeBackendKWallet::GetAllLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - int wallet_handle = WalletHandle(); - if (wallet_handle == kInvalidKWalletHandle) - return false; - return GetAllLoginsInternal(wallet_handle, forms); -} - -scoped_refptr<base::SequencedTaskRunner> -NativeBackendKWallet::GetBackgroundTaskRunner() { - return dbus_thread_linux::GetTaskRunner(); -} - -bool NativeBackendKWallet::GetLoginsList( - const std::string& signon_realm, - int wallet_handle, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - forms->clear(); - // Is there an entry in the wallet? - bool has_entry = false; - KWalletDBus::Error error = kwallet_dbus_.HasEntry( - wallet_handle, folder_name_, signon_realm, app_name_, &has_entry); - if (error) - return false; - if (!has_entry) - return true; - - std::vector<uint8_t> bytes; - error = kwallet_dbus_.ReadEntry(wallet_handle, folder_name_, signon_realm, - app_name_, &bytes); - if (error) - return false; - if (!bytes.empty() && - !CheckSerializedValue(bytes.data(), bytes.size(), signon_realm)) { - // This is weird, but we choose not to call it an error. There is an - // invalid entry somehow, but by just ignoring it, we make it easier to - // repair without having to delete it using kwalletmanager (that is, by - // just saving a new password within this realm to overwrite it). - return true; - } - - // Can't we all just agree on whether bytes are signed or not? Please? - base::Pickle pickle(reinterpret_cast<const char*>(bytes.data()), - bytes.size()); - *forms = DeserializeValue(signon_realm, pickle); - - return true; -} - -bool NativeBackendKWallet::GetLoginsList( - BlacklistOptions options, - int wallet_handle, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - forms->clear(); - std::vector<std::unique_ptr<PasswordForm>> all_forms; - if (!GetAllLoginsInternal(wallet_handle, &all_forms)) - return false; - - // Remove the duplicate sync tags. - std::vector<std::unique_ptr<PasswordForm>> duplicates; - password_manager_util::FindDuplicates(&all_forms, &duplicates, nullptr); - if (!duplicates.empty()) { - // Fill the signon realms to be updated. - std::map<std::string, std::vector<std::unique_ptr<PasswordForm>>> - update_forms; - for (const auto& form : duplicates) { - update_forms.insert(std::make_pair( - form->signon_realm, std::vector<std::unique_ptr<PasswordForm>>())); - } - - // Fill the actual forms to be saved. - for (const auto& form : all_forms) { - auto it = update_forms.find(form->signon_realm); - if (it != update_forms.end()) - it->second.push_back(std::make_unique<PasswordForm>(*form)); - } - - // Update the backend. - for (const auto& update_forms_for_realm : update_forms) { - if (!SetLoginsList(update_forms_for_realm.second, - update_forms_for_realm.first, wallet_handle)) { - return false; - } - } - } - // We have to read all the entries, and then filter them here. - forms->reserve(all_forms.size()); - for (std::unique_ptr<PasswordForm>& saved_form : all_forms) { - if (saved_form->blacklisted_by_user == - (options == BlacklistOptions::BLACKLISTED)) { - forms->push_back(std::move(saved_form)); - } - } - - return true; -} - -bool NativeBackendKWallet::GetAllLoginsInternal( - int wallet_handle, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - // We could probably also use readEntryList here. - std::vector<std::string> realm_list; - KWalletDBus::Error error = kwallet_dbus_.EntryList( - wallet_handle, folder_name_, app_name_, &realm_list); - if (error) - return false; - - forms->clear(); - for (const std::string& signon_realm : realm_list) { - std::vector<uint8_t> bytes; - KWalletDBus::Error error = kwallet_dbus_.ReadEntry( - wallet_handle, folder_name_, signon_realm, app_name_, &bytes); - if (error) - return false; - if (bytes.empty() || - !CheckSerializedValue(bytes.data(), bytes.size(), signon_realm)) - continue; - - // Can't we all just agree on whether bytes are signed or not? Please? - base::Pickle pickle(reinterpret_cast<const char*>(bytes.data()), - bytes.size()); - std::vector<std::unique_ptr<PasswordForm>> from_pickle = - DeserializeValue(signon_realm, pickle); - forms->reserve(forms->size() + from_pickle.size()); - std::move(from_pickle.begin(), from_pickle.end(), - std::back_inserter(*forms)); - } - return true; -} - -bool NativeBackendKWallet::SetLoginsList( - const std::vector<std::unique_ptr<PasswordForm>>& forms, - const std::string& signon_realm, - int wallet_handle) { - if (forms.empty()) { - int ret = 0; - KWalletDBus::Error error = kwallet_dbus_.RemoveEntry( - wallet_handle, folder_name_, signon_realm, app_name_, &ret); - if (error) - return false; - if (ret != 0) - LOG(ERROR) << "Bad return code " << ret << " from KWallet removeEntry"; - return ret == 0; - } - - base::Pickle value; - SerializeValue(forms, &value); - - int ret = 0; - KWalletDBus::Error error = kwallet_dbus_.WriteEntry( - wallet_handle, folder_name_, signon_realm, app_name_, - static_cast<const uint8_t*>(value.data()), value.size(), &ret); - if (error) - return false; - if (ret != 0) - LOG(ERROR) << "Bad return code " << ret << " from KWallet writeEntry"; - return ret == 0; -} - -// static -std::vector<std::unique_ptr<PasswordForm>> -NativeBackendKWallet::DeserializeValue(const std::string& signon_realm, - const base::Pickle& pickle) { - base::PickleIterator iter(pickle); - - int version = -1; - if (!iter.ReadInt(&version) || - version < 0 || version > kPickleVersion) { - LOG(ERROR) << "Failed to deserialize KWallet entry " - << "(realm: " << signon_realm << ")"; - return std::vector<std::unique_ptr<PasswordForm>>(); - } - - std::vector<std::unique_ptr<PasswordForm>> forms; - bool success = true; - if (version > 0) { - // In current pickles, we expect 64-bit sizes. Failure is an error. - success = - DeserializeValueSize(signon_realm, iter, version, false, false, &forms); - return forms; - } - - const bool size_32 = sizeof(size_t) == sizeof(uint32_t); - if (!DeserializeValueSize( - signon_realm, iter, version, size_32, true, &forms)) { - // We failed to read the pickle using the native architecture of the system. - // Try again with the opposite architecture. Note that we do this even on - // 32-bit machines, in case we're reading a 64-bit pickle. (Probably rare, - // since mostly we expect upgrades, not downgrades, but both are possible.) - success = DeserializeValueSize( - signon_realm, iter, version, !size_32, false, &forms); - } - return forms; -} - -int NativeBackendKWallet::WalletHandle() { - DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence()); - - // Open the wallet. - // TODO(mdm): Are we leaking these handles? Find out. - int32_t handle = kInvalidKWalletHandle; - KWalletDBus::Error error = - kwallet_dbus_.Open(wallet_name_, app_name_, &handle); - if (error) - return kInvalidKWalletHandle; - if (handle == kInvalidKWalletHandle) { - LOG(ERROR) << "Error obtaining KWallet handle"; - return kInvalidKWalletHandle; - } - - // Check if our folder exists. - bool has_folder = false; - error = kwallet_dbus_.HasFolder(handle, folder_name_, app_name_, &has_folder); - if (error) - return kInvalidKWalletHandle; - - // Create it if it didn't. - if (!has_folder) { - bool success = false; - error = - kwallet_dbus_.CreateFolder(handle, folder_name_, app_name_, &success); - if (error) - return kInvalidKWalletHandle; - if (!success) { - LOG(ERROR) << "Error creating KWallet folder"; - return kInvalidKWalletHandle; - } - } - - return handle; -} - -std::string NativeBackendKWallet::GetProfileSpecificFolderName() const { - // Originally, the folder name was always just "Chrome Form Data". - // Now we use it to distinguish passwords for different profiles. - return base::StringPrintf("%s (%d)", kKWalletFolder, profile_id_); -}
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.h b/chrome/browser/password_manager/native_backend_kwallet_x.h deleted file mode 100644 index b26479b..0000000 --- a/chrome/browser/password_manager/native_backend_kwallet_x.h +++ /dev/null
@@ -1,145 +0,0 @@ -// Copyright (c) 2012 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 CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_KWALLET_X_H_ -#define CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_KWALLET_X_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/nix/xdg_util.h" -#include "base/sequenced_task_runner.h" -#include "base/time/time.h" -#include "chrome/browser/password_manager/password_store_factory.h" -#include "chrome/browser/password_manager/password_store_x.h" -#include "chrome/browser/profiles/profile.h" -#include "components/os_crypt/kwallet_dbus.h" - -namespace autofill { -struct PasswordForm; -} - -namespace base { -class Pickle; -class WaitableEvent; -} - -// NativeBackend implementation using KWallet. -class NativeBackendKWallet : public PasswordStoreX::NativeBackend { - public: - NativeBackendKWallet(LocalProfileId id, - base::nix::DesktopEnvironment desktop_env); - - ~NativeBackendKWallet() override; - - bool Init() override; - - // Implements NativeBackend interface. - password_manager::PasswordStoreChangeList AddLogin( - const autofill::PasswordForm& form) override; - bool UpdateLogin(const autofill::PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) override; - bool RemoveLogin(const autofill::PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) override; - bool RemoveLoginsCreatedBetween( - base::Time delete_begin, - base::Time delete_end, - password_manager::PasswordStoreChangeList* changes) override; - bool DisableAutoSignInForOrigins( - const base::Callback<bool(const GURL&)>& origin_filter, - password_manager::PasswordStoreChangeList* changes) override; - bool GetLogins( - const password_manager::PasswordStore::FormDigest& form, - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - bool GetAutofillableLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - bool GetBlacklistLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - bool GetAllLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner() override; - - protected: - // Invalid handle returned by WalletHandle(). - static const int kInvalidKWalletHandle = -1; - - // Internally used by Init(), but also for testing to provide a mock bus. - bool InitWithBus(scoped_refptr<dbus::Bus> optional_bus); - - // Deserializes a list of PasswordForms from the wallet. - static std::vector<std::unique_ptr<autofill::PasswordForm>> DeserializeValue( - const std::string& signon_realm, - const base::Pickle& pickle); - - private: - enum InitResult { - INIT_SUCCESS, // Init succeeded. - TEMPORARY_FAIL, // Init failed, but might succeed after StartKWalletd(). - PERMANENT_FAIL // Init failed, and is not likely to work later either. - }; - - enum class BlacklistOptions { AUTOFILLABLE, BLACKLISTED }; - - // Initialization. - InitResult InitWallet(); - void InitOnBackgroundTaskRunner(scoped_refptr<dbus::Bus> optional_bus, - base::WaitableEvent* event, - bool* success); - - // Overwrites |forms| with all credentials matching |signon_realm|. Returns - // true on success. - bool GetLoginsList(const std::string& signon_realm, - int wallet_handle, - std::vector<std::unique_ptr<autofill::PasswordForm>>* - forms) WARN_UNUSED_RESULT; - - // Overwrites |forms| with all credentials matching |options|. Returns true on - // success. - bool GetLoginsList(BlacklistOptions options, - int wallet_handle, - std::vector<std::unique_ptr<autofill::PasswordForm>>* - forms) WARN_UNUSED_RESULT; - - // Overwrites |forms| with all stored credentials. Returns true on success. - bool GetAllLoginsInternal( - int wallet_handle, - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) - WARN_UNUSED_RESULT; - - // Writes a list of PasswordForms to the wallet with the given signon_realm. - // Overwrites any existing list for this signon_realm. Removes the entry if - // |forms| is empty. Returns true on success. - bool SetLoginsList( - const std::vector<std::unique_ptr<autofill::PasswordForm>>& forms, - const std::string& signon_realm, - int wallet_handle); - - // Opens the wallet and ensures that the "Chrome Form Data" folder exists. - // Returns kInvalidWalletHandle on error. - int WalletHandle(); - - // Generates a profile-specific folder name based on profile_id_. - std::string GetProfileSpecificFolderName() const; - - // The local profile id, used to generate the folder name. - const LocalProfileId profile_id_; - - KWalletDBus kwallet_dbus_; - - // The KWallet folder name, possibly based on the local profile id. - std::string folder_name_; - - // The name of the wallet we've opened. Set during Init(). - std::string wallet_name_; - // The application name (e.g. "Chromium"), shown in KWallet auth dialogs. - const std::string app_name_; - - DISALLOW_COPY_AND_ASSIGN(NativeBackendKWallet); -}; - -#endif // CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_KWALLET_X_H_
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc deleted file mode 100644 index e5c01423..0000000 --- a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc +++ /dev/null
@@ -1,1382 +0,0 @@ -// Copyright (c) 2012 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 <stddef.h> -#include <stdint.h> - -#include <algorithm> -#include <map> -#include <set> -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/location.h" -#include "base/pickle.h" -#include "base/stl_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/task_runner_util.h" -#include "base/test/scoped_task_environment.h" -#include "chrome/browser/password_manager/native_backend_kwallet_x.h" -#include "chrome/test/base/testing_profile.h" -#include "components/autofill/core/common/password_form.h" -#include "components/password_manager/core/common/password_manager_pref_names.h" -#include "components/prefs/pref_service.h" -#include "dbus/message.h" -#include "dbus/mock_bus.h" -#include "dbus/mock_object_proxy.h" -#include "dbus/object_path.h" -#include "dbus/object_proxy.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using autofill::PasswordForm; -using base::UTF8ToUTF16; -using password_manager::PasswordStoreChange; -using password_manager::PasswordStoreChangeList; -using testing::_; -using testing::Invoke; -using testing::Pointee; -using testing::Return; -using testing::TestWithParam; -using testing::UnorderedElementsAre; -using testing::Values; - -namespace { - -// This class implements a very simple version of KWallet in memory. -// We only provide the parts we actually use; the real version has more. -class TestKWallet { - public: - typedef std::basic_string<uint8_t> Blob; // std::string is binary-safe. - - TestKWallet() : reject_local_folders_(false) {} - - void set_reject_local_folders(bool value) { reject_local_folders_ = value; } - - // NOTE: The method names here are the same as the corresponding DBus - // methods, and therefore have names that don't match our style guide. - - // Check for presence of a given password folder. - bool hasFolder(const std::string& folder) const { - return data_.find(folder) != data_.end(); - } - - // Check for presence of a given password in a given password folder. - bool hasEntry(const std::string& folder, const std::string& key) const { - auto it = data_.find(folder); - return it != data_.end() && it->second.find(key) != it->second.end(); - } - - // Get a list of password keys in a given password folder. - bool entryList(const std::string& folder, - std::vector<std::string>* entries) const { - auto it = data_.find(folder); - if (it == data_.end()) return false; - for (auto fit = it->second.begin(); fit != it->second.end(); ++fit) - entries->push_back(fit->first); - return true; - } - - // Read the password data for a given password in a given password folder. - bool readEntry(const std::string& folder, const std::string& key, - Blob* value) const { - auto it = data_.find(folder); - if (it == data_.end()) return false; - auto fit = it->second.find(key); - if (fit == it->second.end()) return false; - *value = fit->second; - return true; - } - - // Create the given password folder. - bool createFolder(const std::string& folder) { - if (reject_local_folders_ && folder.find('(') != std::string::npos) - return false; - return data_.insert(make_pair(folder, Folder())).second; - } - - // Remove the given password from the given password folder. - bool removeEntry(const std::string& folder, const std::string& key) { - auto it = data_.find(folder); - if (it == data_.end()) return false; - return it->second.erase(key) > 0; - } - - // Write the given password data to the given password folder. - bool writeEntry(const std::string& folder, const std::string& key, - const Blob& value) { - auto it = data_.find(folder); - if (it == data_.end()) return false; - it->second[key] = value; - return true; - } - - private: - typedef std::map<std::string, Blob> Folder; - typedef std::map<std::string, Folder> Data; - - Data data_; - // "Local" folders are folders containing local profile IDs in their names. We - // can reject attempts to create them in order to make it easier to create - // legacy shared passwords in these tests, for testing the migration code. - bool reject_local_folders_; - - // No need to disallow copy and assign. This class is safe to copy and assign. -}; - -// Runs |backend->GetAutofillableLogins(forms)| and expects that the return -// value is false. -void CheckGetAutofillableLoginsFails( - PasswordStoreX::NativeBackend* backend, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - EXPECT_FALSE(backend->GetAutofillableLogins(forms)); -} - -void CheckTrue(bool result) { - EXPECT_TRUE(result); -} - -void WriteHTMLAttributes(const PasswordForm& form, base::Pickle* pickle) { - pickle->WriteInt(static_cast<int>(form.scheme)); - pickle->WriteString(form.origin.spec()); - pickle->WriteString(form.action.spec()); - pickle->WriteString16(form.username_element); - pickle->WriteString16(form.username_value); - pickle->WriteString16(form.password_element); - pickle->WriteString16(form.password_value); - pickle->WriteString16(form.submit_element); -} - -void WritePreferenceMetadata(const PasswordForm& form, base::Pickle* pickle) { - pickle->WriteBool(form.preferred); - pickle->WriteBool(form.blacklisted_by_user); -} - -} // anonymous namespace - -// Obscure magic: we need to declare storage for this constant because we use it -// in ways that require its address in this test, but not in the actual code. -const int NativeBackendKWallet::kInvalidKWalletHandle; - -// Subclass NativeBackendKWallet to promote some members to public for testing. -class NativeBackendKWalletStub : public NativeBackendKWallet { - public: - NativeBackendKWalletStub(LocalProfileId id, - base::nix::DesktopEnvironment desktop_env) - : NativeBackendKWallet(id, desktop_env) {} - using NativeBackendKWallet::InitWithBus; - using NativeBackendKWallet::kInvalidKWalletHandle; - using NativeBackendKWallet::DeserializeValue; -}; - -// Provide some test forms to avoid having to set them up in each test. -class NativeBackendKWalletTestBase : - public testing::TestWithParam<base::nix::DesktopEnvironment> { - protected: - NativeBackendKWalletTestBase() { - old_form_google_.origin = GURL("http://www.google.com/"); - old_form_google_.action = GURL("http://www.google.com/login"); - old_form_google_.username_element = UTF8ToUTF16("user"); - old_form_google_.username_value = UTF8ToUTF16("joeschmoe"); - old_form_google_.password_element = UTF8ToUTF16("pass"); - old_form_google_.password_value = UTF8ToUTF16("seekrit"); - old_form_google_.submit_element = UTF8ToUTF16("submit"); - old_form_google_.signon_realm = "Google"; - old_form_google_.date_created = base::Time::Now(); - - form_google_ = old_form_google_; - form_google_.times_used = 3; - form_google_.type = PasswordForm::Type::kGenerated; - form_google_.form_data.name = UTF8ToUTF16("form_name"); - form_google_.date_synced = base::Time::Now(); - form_google_.date_created = old_form_google_.date_created; - form_google_.display_name = UTF8ToUTF16("Joe Schmoe"); - form_google_.icon_url = GURL("http://www.google.com/icon"); - form_google_.federation_origin = - url::Origin::Create(GURL("http://www.google.com/")); - form_google_.skip_zero_click = true; - form_google_.generation_upload_status = - PasswordForm::GenerationUploadStatus::kNegativeSignalSent; - - form_isc_.origin = GURL("http://www.isc.org/"); - form_isc_.action = GURL("http://www.isc.org/auth"); - form_isc_.username_element = UTF8ToUTF16("id"); - form_isc_.username_value = UTF8ToUTF16("janedoe"); - form_isc_.password_element = UTF8ToUTF16("passwd"); - form_isc_.password_value = UTF8ToUTF16("ihazabukkit"); - form_isc_.submit_element = UTF8ToUTF16("login"); - form_isc_.signon_realm = "ISC"; - form_isc_.date_synced = base::Time::Now(); - form_isc_.date_created = base::Time::Now(); - } - - static void CheckPasswordForm(const PasswordForm& expected, - const PasswordForm& actual, - bool check_date_created); - static void CheckPasswordChanges(const PasswordStoreChangeList& expected, - const PasswordStoreChangeList& actual); - static void CheckPasswordChangesWithResult( - const PasswordStoreChangeList* expected, - const PasswordStoreChangeList* actual, - bool result); - - base::test::ScopedTaskEnvironment scoped_task_environment_; - - PasswordForm old_form_google_; - PasswordForm form_google_; - PasswordForm form_isc_; -}; - -// static -void NativeBackendKWalletTestBase::CheckPasswordForm( - const PasswordForm& expected, - const PasswordForm& actual, - bool check_date_created) { - EXPECT_EQ(expected.origin, actual.origin); - EXPECT_EQ(expected.password_value, actual.password_value); - EXPECT_EQ(expected.action, actual.action); - EXPECT_EQ(expected.username_element, actual.username_element); - EXPECT_EQ(expected.username_value, actual.username_value); - EXPECT_EQ(expected.password_element, actual.password_element); - EXPECT_EQ(expected.submit_element, actual.submit_element); - EXPECT_EQ(expected.signon_realm, actual.signon_realm); - EXPECT_EQ(expected.preferred, actual.preferred); - if (check_date_created) { - EXPECT_EQ(expected.date_created, actual.date_created); - } - EXPECT_EQ(expected.blacklisted_by_user, actual.blacklisted_by_user); - EXPECT_EQ(expected.type, actual.type); - EXPECT_EQ(expected.times_used, actual.times_used); - EXPECT_EQ(expected.scheme, actual.scheme); - EXPECT_EQ(expected.date_synced, actual.date_synced); - EXPECT_EQ(expected.display_name, actual.display_name); - EXPECT_EQ(expected.icon_url, actual.icon_url); - EXPECT_EQ(expected.federation_origin.Serialize(), - actual.federation_origin.Serialize()); - EXPECT_EQ(expected.skip_zero_click, actual.skip_zero_click); - EXPECT_EQ(expected.generation_upload_status, actual.generation_upload_status); -} - -// static -void NativeBackendKWalletTestBase::CheckPasswordChanges( - const PasswordStoreChangeList& expected, - const PasswordStoreChangeList& actual) { - ASSERT_EQ(expected.size(), actual.size()); - for (size_t i = 0; i < expected.size(); ++i) { - EXPECT_EQ(expected[i].type(), actual[i].type()); - CheckPasswordForm(expected[i].form(), actual[i].form(), true); - } -} - -// static -void NativeBackendKWalletTestBase::CheckPasswordChangesWithResult( - const PasswordStoreChangeList* expected, - const PasswordStoreChangeList* actual, - bool result) { - EXPECT_TRUE(result); - CheckPasswordChanges(*expected, *actual); -} - -class NativeBackendKWalletTest : public NativeBackendKWalletTestBase { - protected: - NativeBackendKWalletTest() - : klauncher_ret_(0), - klauncher_contacted_(false), - kwallet_runnable_(true), - kwallet_running_(true), - kwallet_enabled_(true), - desktop_env_(GetParam()) {} - - void SetUp() override; - - // Utilities to help verify sets of expectations. - typedef std::vector< - std::pair<std::string, - std::vector<const PasswordForm*> > > ExpectationArray; - void CheckPasswordForms(const std::string& folder, - const ExpectationArray& sorted_expected); - - scoped_refptr<dbus::MockBus> mock_session_bus_; - scoped_refptr<dbus::MockObjectProxy> mock_klauncher_proxy_; - scoped_refptr<dbus::MockObjectProxy> mock_kwallet_proxy_; - - int klauncher_ret_; - std::string klauncher_error_; - bool klauncher_contacted_; - - bool kwallet_runnable_; - bool kwallet_running_; - bool kwallet_enabled_; - - // Used for switching between kwalletd and kwalletd5 - base::nix::DesktopEnvironment desktop_env_; - - TestKWallet wallet_; - - // For all method names contained in |failing_methods_|, the mocked KWallet - // will return a null response. - std::set<std::string> failing_methods_; - - private: - std::unique_ptr<dbus::Response> KLauncherMethodCall( - dbus::MethodCall* method_call, testing::Unused); - - std::unique_ptr<dbus::Response> KWalletMethodCall( - dbus::MethodCall* method_call, testing::Unused); -}; - -void NativeBackendKWalletTest::SetUp() { - dbus::Bus::Options options; - options.bus_type = dbus::Bus::SESSION; - mock_session_bus_ = new dbus::MockBus(options); - - mock_klauncher_proxy_ = - new dbus::MockObjectProxy(mock_session_bus_.get(), - "org.kde.klauncher", - dbus::ObjectPath("/KLauncher")); - EXPECT_CALL(*mock_klauncher_proxy_.get(), CallMethodAndBlock(_, _)) - .WillRepeatedly( - Invoke(this, &NativeBackendKWalletTest::KLauncherMethodCall)); - - if (desktop_env_ == base::nix::DESKTOP_ENVIRONMENT_KDE5) { - mock_kwallet_proxy_ = - new dbus::MockObjectProxy(mock_session_bus_.get(), - "org.kde.kwalletd5", - dbus::ObjectPath("/modules/kwalletd5")); - } else { - mock_kwallet_proxy_ = - new dbus::MockObjectProxy(mock_session_bus_.get(), - "org.kde.kwalletd", - dbus::ObjectPath("/modules/kwalletd")); - } - EXPECT_CALL(*mock_kwallet_proxy_.get(), CallMethodAndBlock(_, _)) - .WillRepeatedly( - Invoke(this, &NativeBackendKWalletTest::KWalletMethodCall)); - - EXPECT_CALL( - *mock_session_bus_.get(), - GetObjectProxy("org.kde.klauncher", dbus::ObjectPath("/KLauncher"))) - .WillRepeatedly(Return(mock_klauncher_proxy_.get())); - if (desktop_env_ == base::nix::DESKTOP_ENVIRONMENT_KDE5) { - EXPECT_CALL( - *mock_session_bus_.get(), - GetObjectProxy("org.kde.kwalletd5", - dbus::ObjectPath("/modules/kwalletd5"))) - .WillRepeatedly(Return(mock_kwallet_proxy_.get())); - } else { - EXPECT_CALL( - *mock_session_bus_.get(), - GetObjectProxy("org.kde.kwalletd", - dbus::ObjectPath("/modules/kwalletd"))) - .WillRepeatedly(Return(mock_kwallet_proxy_.get())); - } - - EXPECT_CALL(*mock_session_bus_.get(), ShutdownAndBlock()).WillOnce(Return()) - .WillRepeatedly(Return()); -} - -std::unique_ptr<dbus::Response> NativeBackendKWalletTest::KLauncherMethodCall( - dbus::MethodCall* method_call, testing::Unused) { - EXPECT_EQ("org.kde.KLauncher", method_call->GetInterface()); - EXPECT_EQ("start_service_by_desktop_name", method_call->GetMember()); - - klauncher_contacted_ = true; - - dbus::MessageReader reader(method_call); - std::string service_name; - std::vector<std::string> urls; - std::vector<std::string> envs; - std::string startup_id; - bool blind = false; - - EXPECT_TRUE(reader.PopString(&service_name)); - EXPECT_TRUE(reader.PopArrayOfStrings(&urls)); - EXPECT_TRUE(reader.PopArrayOfStrings(&envs)); - EXPECT_TRUE(reader.PopString(&startup_id)); - EXPECT_TRUE(reader.PopBool(&blind)); - - if (desktop_env_ == base::nix::DESKTOP_ENVIRONMENT_KDE5) - EXPECT_EQ("kwalletd5", service_name); - else - EXPECT_EQ("kwalletd", service_name); - EXPECT_TRUE(urls.empty()); - EXPECT_TRUE(envs.empty()); - EXPECT_TRUE(startup_id.empty()); - EXPECT_FALSE(blind); - - if (kwallet_runnable_) - kwallet_running_ = true; - - std::unique_ptr<dbus::Response> response(dbus::Response::CreateEmpty()); - dbus::MessageWriter writer(response.get()); - writer.AppendInt32(klauncher_ret_); - writer.AppendString(std::string()); // dbus_name - writer.AppendString(klauncher_error_); - writer.AppendInt32(1234); // pid - return response; -} - -std::unique_ptr<dbus::Response> NativeBackendKWalletTest::KWalletMethodCall( - dbus::MethodCall* method_call, testing::Unused) { - if (!kwallet_running_) - return nullptr; - EXPECT_EQ("org.kde.KWallet", method_call->GetInterface()); - - if (base::Contains(failing_methods_, method_call->GetMember())) - return nullptr; - std::unique_ptr<dbus::Response> response; - if (method_call->GetMember() == "isEnabled") { - response = dbus::Response::CreateEmpty(); - dbus::MessageWriter writer(response.get()); - writer.AppendBool(kwallet_enabled_); - } else if (method_call->GetMember() == "networkWallet") { - response = dbus::Response::CreateEmpty(); - dbus::MessageWriter writer(response.get()); - writer.AppendString("test_wallet"); // Should match |open| below. - } else if (method_call->GetMember() == "open") { - dbus::MessageReader reader(method_call); - std::string wallet_name; - int64_t wallet_id; - std::string app_name; - EXPECT_TRUE(reader.PopString(&wallet_name)); - EXPECT_TRUE(reader.PopInt64(&wallet_id)); - EXPECT_TRUE(reader.PopString(&app_name)); - EXPECT_EQ("test_wallet", wallet_name); // Should match |networkWallet|. - response = dbus::Response::CreateEmpty(); - dbus::MessageWriter writer(response.get()); - writer.AppendInt32(1); // Can be anything but kInvalidKWalletHandle. - } else if (method_call->GetMember() == "hasFolder" || - method_call->GetMember() == "createFolder") { - dbus::MessageReader reader(method_call); - int handle = NativeBackendKWalletStub::kInvalidKWalletHandle; - std::string folder_name; - std::string app_name; - EXPECT_TRUE(reader.PopInt32(&handle)); - EXPECT_TRUE(reader.PopString(&folder_name)); - EXPECT_TRUE(reader.PopString(&app_name)); - EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle); - response = dbus::Response::CreateEmpty(); - dbus::MessageWriter writer(response.get()); - if (method_call->GetMember() == "hasFolder") - writer.AppendBool(wallet_.hasFolder(folder_name)); - else - writer.AppendBool(wallet_.createFolder(folder_name)); - } else if (method_call->GetMember() == "hasEntry" || - method_call->GetMember() == "removeEntry") { - dbus::MessageReader reader(method_call); - int handle = NativeBackendKWalletStub::kInvalidKWalletHandle; - std::string folder_name; - std::string key; - std::string app_name; - EXPECT_TRUE(reader.PopInt32(&handle)); - EXPECT_TRUE(reader.PopString(&folder_name)); - EXPECT_TRUE(reader.PopString(&key)); - EXPECT_TRUE(reader.PopString(&app_name)); - EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle); - response = dbus::Response::CreateEmpty(); - dbus::MessageWriter writer(response.get()); - if (method_call->GetMember() == "hasEntry") - writer.AppendBool(wallet_.hasEntry(folder_name, key)); - else - writer.AppendInt32(wallet_.removeEntry(folder_name, key) ? 0 : 1); - } else if (method_call->GetMember() == "entryList") { - dbus::MessageReader reader(method_call); - int handle = NativeBackendKWalletStub::kInvalidKWalletHandle; - std::string folder_name; - std::string app_name; - EXPECT_TRUE(reader.PopInt32(&handle)); - EXPECT_TRUE(reader.PopString(&folder_name)); - EXPECT_TRUE(reader.PopString(&app_name)); - EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle); - std::vector<std::string> entries; - if (wallet_.entryList(folder_name, &entries)) { - response = dbus::Response::CreateEmpty(); - dbus::MessageWriter writer(response.get()); - writer.AppendArrayOfStrings(entries); - } - } else if (method_call->GetMember() == "readEntry") { - dbus::MessageReader reader(method_call); - int handle = NativeBackendKWalletStub::kInvalidKWalletHandle; - std::string folder_name; - std::string key; - std::string app_name; - EXPECT_TRUE(reader.PopInt32(&handle)); - EXPECT_TRUE(reader.PopString(&folder_name)); - EXPECT_TRUE(reader.PopString(&key)); - EXPECT_TRUE(reader.PopString(&app_name)); - EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle); - TestKWallet::Blob value; - if (wallet_.readEntry(folder_name, key, &value)) { - response = dbus::Response::CreateEmpty(); - dbus::MessageWriter writer(response.get()); - writer.AppendArrayOfBytes(value.data(), value.size()); - } - } else if (method_call->GetMember() == "writeEntry") { - dbus::MessageReader reader(method_call); - int handle = NativeBackendKWalletStub::kInvalidKWalletHandle; - std::string folder_name; - std::string key; - const uint8_t* bytes = nullptr; - size_t length = 0; - std::string app_name; - EXPECT_TRUE(reader.PopInt32(&handle)); - EXPECT_TRUE(reader.PopString(&folder_name)); - EXPECT_TRUE(reader.PopString(&key)); - EXPECT_TRUE(reader.PopArrayOfBytes(&bytes, &length)); - EXPECT_TRUE(reader.PopString(&app_name)); - EXPECT_NE(NativeBackendKWalletStub::kInvalidKWalletHandle, handle); - response = dbus::Response::CreateEmpty(); - dbus::MessageWriter writer(response.get()); - writer.AppendInt32( - wallet_.writeEntry(folder_name, key, - TestKWallet::Blob(bytes, length)) ? 0 : 1); - } - - EXPECT_TRUE(response); - return response; -} - -void NativeBackendKWalletTest::CheckPasswordForms( - const std::string& folder, const ExpectationArray& sorted_expected) { - EXPECT_TRUE(wallet_.hasFolder(folder)); - std::vector<std::string> entries; - EXPECT_TRUE(wallet_.entryList(folder, &entries)); - EXPECT_EQ(sorted_expected.size(), entries.size()); - std::sort(entries.begin(), entries.end()); - for (size_t i = 0; i < entries.size() && i < sorted_expected.size(); ++i) { - EXPECT_EQ(sorted_expected[i].first, entries[i]); - TestKWallet::Blob value; - EXPECT_TRUE(wallet_.readEntry(folder, entries[i], &value)); - base::Pickle pickle(reinterpret_cast<const char*>(value.data()), - value.size()); - std::vector<std::unique_ptr<PasswordForm>> forms = - NativeBackendKWalletStub::DeserializeValue(entries[i], pickle); - const std::vector<const PasswordForm*>& expect = sorted_expected[i].second; - EXPECT_EQ(expect.size(), forms.size()); - for (size_t j = 0; j < forms.size() && j < expect.size(); ++j) - CheckPasswordForm(*expect[j], *forms[j], true); - } -} - -TEST_P(NativeBackendKWalletTest, NotEnabled) { - NativeBackendKWalletStub kwallet(42, desktop_env_); - kwallet_enabled_ = false; - EXPECT_FALSE(kwallet.InitWithBus(mock_session_bus_)); - EXPECT_FALSE(klauncher_contacted_); -} - -TEST_P(NativeBackendKWalletTest, NotRunnable) { - NativeBackendKWalletStub kwallet(42, desktop_env_); - kwallet_runnable_ = false; - kwallet_running_ = false; - EXPECT_FALSE(kwallet.InitWithBus(mock_session_bus_)); - EXPECT_TRUE(klauncher_contacted_); -} - -TEST_P(NativeBackendKWalletTest, NotRunningOrEnabled) { - NativeBackendKWalletStub kwallet(42, desktop_env_); - kwallet_running_ = false; - kwallet_enabled_ = false; - EXPECT_FALSE(kwallet.InitWithBus(mock_session_bus_)); - EXPECT_TRUE(klauncher_contacted_); -} - -TEST_P(NativeBackendKWalletTest, NotRunning) { - NativeBackendKWalletStub kwallet(42, desktop_env_); - kwallet_running_ = false; - EXPECT_TRUE(kwallet.InitWithBus(mock_session_bus_)); - EXPECT_TRUE(klauncher_contacted_); -} - -TEST_P(NativeBackendKWalletTest, BasicStartup) { - NativeBackendKWalletStub kwallet(42, desktop_env_); - EXPECT_TRUE(kwallet.InitWithBus(mock_session_bus_)); - EXPECT_FALSE(klauncher_contacted_); -} - -TEST_P(NativeBackendKWalletTest, BasicAddLogin) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::AddLogin, - base::Unretained(&backend), form_google_), - base::Bind( - &CheckPasswordChanges, - PasswordStoreChangeList( - 1, PasswordStoreChange(PasswordStoreChange::ADD, form_google_)))); - - scoped_task_environment_.RunUntilIdle(); - - EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data")); - - std::vector<const PasswordForm*> forms; - forms.push_back(&form_google_); - ExpectationArray expected; - expected.push_back(make_pair(std::string(form_google_.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -TEST_P(NativeBackendKWalletTest, BasicUpdateLogin) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_google_)); - - scoped_task_environment_.RunUntilIdle(); - - PasswordForm new_form_google(form_google_); - new_form_google.times_used = 10; - new_form_google.action = GURL("http://www.google.com/different/login"); - - // Update login - PasswordStoreChangeList changes; - PasswordStoreChangeList expected_changes( - 1, PasswordStoreChange(PasswordStoreChange::UPDATE, new_form_google)); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::UpdateLogin, - base::Unretained(&backend), new_form_google, &changes), - base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes)); - - scoped_task_environment_.RunUntilIdle(); - - ASSERT_EQ(1u, changes.size()); - EXPECT_EQ(PasswordStoreChange::UPDATE, changes.front().type()); - EXPECT_EQ(new_form_google, changes.front().form()); - - std::vector<const PasswordForm*> forms; - forms.push_back(&new_form_google); - ExpectationArray expected; - expected.push_back(make_pair(std::string(form_google_.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -TEST_P(NativeBackendKWalletTest, BasicListLogins) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_google_)); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::GetAutofillableLogins, - base::Unretained(&backend), &form_list), - base::Bind(&CheckTrue)); - - scoped_task_environment_.RunUntilIdle(); - - // Quick check that we got something back. - EXPECT_EQ(1u, form_list.size()); - - EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data")); - - std::vector<const PasswordForm*> forms; - forms.push_back(&form_google_); - ExpectationArray expected; - expected.push_back(make_pair(std::string(form_google_.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -TEST_P(NativeBackendKWalletTest, BasicRemoveLogin) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_google_)); - - scoped_task_environment_.RunUntilIdle(); - - EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data")); - - std::vector<const PasswordForm*> forms; - forms.push_back(&form_google_); - ExpectationArray expected; - expected.push_back(make_pair(std::string(form_google_.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); - - PasswordStoreChangeList changes; - PasswordStoreChangeList expected_changes( - 1, PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_)); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::RemoveLogin, - base::Unretained(&backend), form_google_, &changes), - base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes)); - - scoped_task_environment_.RunUntilIdle(); - - expected.clear(); - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -TEST_P(NativeBackendKWalletTest, UpdateNonexistentLogin) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - // First add an unrelated login. - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_google_)); - - scoped_task_environment_.RunUntilIdle(); - - std::vector<const PasswordForm*> forms; - forms.push_back(&form_google_); - ExpectationArray expected; - expected.push_back(make_pair(std::string(form_google_.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); - - // Attempt to update a login that doesn't exist. - PasswordStoreChangeList changes; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::UpdateLogin, - base::Unretained(&backend), form_isc_, &changes), - base::Bind(&CheckPasswordChangesWithResult, - base::Owned(new PasswordStoreChangeList), &changes)); - - scoped_task_environment_.RunUntilIdle(); - - EXPECT_EQ(PasswordStoreChangeList(), changes); - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -TEST_P(NativeBackendKWalletTest, RemoveNonexistentLogin) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - // First add an unrelated login. - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_google_)); - - scoped_task_environment_.RunUntilIdle(); - - EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data")); - - std::vector<const PasswordForm*> forms; - forms.push_back(&form_google_); - ExpectationArray expected; - expected.push_back(make_pair(std::string(form_google_.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); - - // Attempt to remove a login that doesn't exist. - PasswordStoreChangeList changes; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::RemoveLogin, - base::Unretained(&backend), form_isc_, &changes), - base::Bind(&CheckPasswordChangesWithResult, - base::Owned(new PasswordStoreChangeList), &changes)); - - // Make sure we can still get the first form back. - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::GetAutofillableLogins, - base::Unretained(&backend), &form_list), - base::Bind(&CheckTrue)); - - scoped_task_environment_.RunUntilIdle(); - - // Quick check that we got something back. - EXPECT_EQ(1u, form_list.size()); - - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -TEST_P(NativeBackendKWalletTest, AddDuplicateLogin) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - PasswordStoreChangeList changes; - changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, - form_google_)); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::AddLogin, - base::Unretained(&backend), form_google_), - base::Bind(&NativeBackendKWalletTest::CheckPasswordChanges, changes)); - - changes.clear(); - changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, - form_google_)); - form_google_.times_used++; - form_google_.submit_element = UTF8ToUTF16("submit2"); - changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD, - form_google_)); - - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::AddLogin, - base::Unretained(&backend), form_google_), - base::Bind(&NativeBackendKWalletTest::CheckPasswordChanges, changes)); - - scoped_task_environment_.RunUntilIdle(); - - EXPECT_FALSE(wallet_.hasFolder("Chrome Form Data")); - - std::vector<const PasswordForm*> forms; - forms.push_back(&form_google_); - ExpectationArray expected; - expected.push_back(make_pair(std::string(form_google_.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -TEST_P(NativeBackendKWalletTest, AndroidCredentials) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - PasswordForm saved_android_form; - saved_android_form.scheme = PasswordForm::Scheme::kHtml; - saved_android_form.signon_realm = - "android://7x7IDboo8u9YKraUsbmVkuf1-@net.rateflix.app/"; - saved_android_form.username_value = base::UTF8ToUTF16("randomusername"); - saved_android_form.password_value = base::UTF8ToUTF16("password"); - - password_manager::PasswordStore::FormDigest observed_android_form( - saved_android_form); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::AddLogin, - base::Unretained(&backend), saved_android_form), - base::Bind(&CheckPasswordChanges, - PasswordStoreChangeList( - 1, PasswordStoreChange(PasswordStoreChange::ADD, - saved_android_form)))); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::GetLogins, - base::Unretained(&backend), observed_android_form, &form_list), - base::Bind(&CheckTrue)); - - scoped_task_environment_.RunUntilIdle(); - - EXPECT_EQ(1u, form_list.size()); - - std::vector<const PasswordForm*> forms; - forms.push_back(&saved_android_form); - ExpectationArray expected; - expected.push_back( - make_pair(std::string(saved_android_form.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -TEST_P(NativeBackendKWalletTest, RemoveLoginsCreatedBetween) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - form_google_.date_synced = base::Time(); - form_isc_.date_synced = base::Time(); - form_google_.date_created = base::Time(); - form_isc_.date_created = base::Time(); - base::Time now = base::Time::Now(); - base::Time next_day = now + base::TimeDelta::FromDays(1); - form_google_.date_created = now; - form_isc_.date_created = next_day; - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_google_)); - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_isc_)); - - PasswordStoreChangeList expected_changes; - expected_changes.emplace_back(PasswordStoreChange::REMOVE, form_google_); - PasswordStoreChangeList changes; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::BindOnce(&NativeBackendKWalletStub::RemoveLoginsCreatedBetween, - base::Unretained(&backend), base::Time(), next_day, - &changes), - base::BindOnce(&CheckPasswordChangesWithResult, &expected_changes, - &changes)); - - scoped_task_environment_.RunUntilIdle(); - - ExpectationArray expected = {{form_isc_.signon_realm, {&form_isc_}}}; - CheckPasswordForms("Chrome Form Data (42)", expected); - - // Remove form_isc_. - expected_changes.clear(); - expected_changes.emplace_back(PasswordStoreChange::REMOVE, form_isc_); - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::BindOnce(&NativeBackendKWalletStub::RemoveLoginsCreatedBetween, - base::Unretained(&backend), next_day, base::Time(), - &changes), - base::BindOnce(&CheckPasswordChangesWithResult, &expected_changes, - &changes)); - - scoped_task_environment_.RunUntilIdle(); - - CheckPasswordForms("Chrome Form Data (42)", ExpectationArray()); -} - -TEST_P(NativeBackendKWalletTest, DisableAutoSignInForOrigins) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - form_isc_.skip_zero_click = false; - form_google_.skip_zero_click = false; - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWallet::AddLogin), - base::Unretained(&backend), form_isc_)); - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWallet::AddLogin), - base::Unretained(&backend), form_google_)); - - scoped_task_environment_.RunUntilIdle(); - - // Set the canonical forms to the updated value for the following comparison. - form_google_.skip_zero_click = true; - PasswordStoreChangeList expected_changes; - expected_changes.push_back( - PasswordStoreChange(PasswordStoreChange::UPDATE, form_google_)); - - PasswordStoreChangeList changes; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind( - &NativeBackendKWallet::DisableAutoSignInForOrigins, - base::Unretained(&backend), - base::Bind( - static_cast<bool (*)(const GURL&, const GURL&)>(operator==), - form_google_.origin), - &changes), - base::Bind(&CheckPasswordChangesWithResult, &expected_changes, &changes)); - - scoped_task_environment_.RunUntilIdle(); - - std::vector<const PasswordForm*> forms; - forms.push_back(&form_google_); - ExpectationArray expected; - expected.push_back(make_pair(std::string(form_google_.signon_realm), forms)); - forms.clear(); - forms.push_back(&form_isc_); - expected.push_back(make_pair(std::string(form_isc_.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -TEST_P(NativeBackendKWalletTest, ReadDuplicateForms) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - // Add 2 slightly different password forms. - const char unique_string[] = "unique_unique_string"; - const char unique_string_replacement[] = "uniKue_unique_string"; - form_google_.origin = - GURL(std::string("http://www.google.com/") + unique_string); - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_google_)); - form_google_.origin = - GURL(std::string("http://www.google.com/") + unique_string_replacement); - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_google_)); - - scoped_task_environment_.RunUntilIdle(); - - // Read the raw value back. Change the |unique_string| to - // |unique_string_replacement| so the forms become unique. - TestKWallet::Blob value; - ASSERT_TRUE(wallet_.readEntry("Chrome Form Data (42)", - form_google_.signon_realm, &value)); - TestKWallet::Blob sample(reinterpret_cast<const uint8_t*>(unique_string)); - size_t position = value.find(sample); - ASSERT_NE(TestKWallet::Blob::npos, position); - value.replace(position, sample.length(), - reinterpret_cast<const uint8_t*>(unique_string_replacement)); - wallet_.writeEntry("Chrome Form Data (42)", form_google_.signon_realm, value); - - // Now test that GetAutofillableLogins returns only one form. - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::GetAutofillableLogins, - base::Unretained(&backend), &form_list), - base::Bind(&CheckTrue)); - - scoped_task_environment_.RunUntilIdle(); - - EXPECT_EQ(1u, form_list.size()); - EXPECT_EQ(form_google_, *form_list[0]); - - std::vector<const PasswordForm*> forms; - forms.push_back(&form_google_); - ExpectationArray expected; - expected.push_back(make_pair(std::string(form_google_.signon_realm), forms)); - CheckPasswordForms("Chrome Form Data (42)", expected); -} - -// Check that if KWallet fails to respond, the backend propagates the error. -TEST_P(NativeBackendKWalletTest, GetAllLoginsErrorHandling) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - // Make KWallet fail on calling readEntry. - failing_methods_.insert("readEntry"); - - // Store some non-blacklisted logins to be potentially returned. - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::AddLogin, - base::Unretained(&backend), form_google_), - base::Bind( - &CheckPasswordChanges, - PasswordStoreChangeList( - 1, PasswordStoreChange(PasswordStoreChange::ADD, form_google_)))); - - // Verify that nothing is in fact returned, because KWallet fails to respond. - std::vector<std::unique_ptr<PasswordForm>> form_list; - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&CheckGetAutofillableLoginsFails, - base::Unretained(&backend), &form_list)); - - scoped_task_environment_.RunUntilIdle(); - - EXPECT_EQ(0u, form_list.size()); -} - -TEST_P(NativeBackendKWalletTest, GetAllLogins) { - NativeBackendKWalletStub backend(42, desktop_env_); - EXPECT_TRUE(backend.InitWithBus(mock_session_bus_)); - - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_google_)); - backend.GetBackgroundTaskRunner()->PostTask( - FROM_HERE, - base::BindOnce(base::IgnoreResult(&NativeBackendKWalletStub::AddLogin), - base::Unretained(&backend), form_isc_)); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - base::PostTaskAndReplyWithResult( - backend.GetBackgroundTaskRunner().get(), FROM_HERE, - base::Bind(&NativeBackendKWalletStub::GetAllLogins, - base::Unretained(&backend), &form_list), - base::Bind(&CheckTrue)); - - scoped_task_environment_.RunUntilIdle(); - - EXPECT_EQ(2u, form_list.size()); - EXPECT_THAT(form_list, - UnorderedElementsAre(Pointee(form_google_), Pointee(form_isc_))); -} - -INSTANTIATE_TEST_SUITE_P( - , - NativeBackendKWalletTest, - ::testing::Values(base::nix::DESKTOP_ENVIRONMENT_KDE4, - base::nix::DESKTOP_ENVIRONMENT_KDE5)); - -// TODO(mdm): add more basic tests here at some point. -// (For example tests for storing >1 password per realm pickle.) - -class NativeBackendKWalletPickleTest : public NativeBackendKWalletTestBase { - protected: - // Based on |form|, fills |pickle| with data conforming to - // |effective_version|, but marking the pickle version as |stored_version|. In - // most cases the two versions should be the same. - void CreateVersion1PlusPickle(const PasswordForm& form, - base::Pickle* pickle, - int stored_version, - int effective_version); - // If |size_32| is true, stores the number of forms in the pickle as a 32bit - // uint, otherwise as 64 bit size_t. - void CreateVersion0Pickle(bool size_32, - const PasswordForm& form, - base::Pickle* pickle); - void CheckVersion9Pickle(); - void CheckVersion8Pickle(); - void CheckVersion7Pickle(); - // As explained in http://crbug.com/494229#c11, version 6 added a new optional - // field to version 5. This field became required in version 7. Depending on - // |with_optional_field|, this method checks deserialization with or without - // the optional field. - void CheckVersion6Pickle(bool with_optional_field); - void CheckVersion5Pickle(); - void CheckVersion3Pickle(); - void CheckVersion2Pickle(); - void CheckVersion1Pickle(); - void CheckVersion0Pickle(bool size_32, PasswordForm::Scheme scheme); -}; - -void NativeBackendKWalletPickleTest::CreateVersion1PlusPickle( - const PasswordForm& form, - base::Pickle* pickle, - int stored_version, - int effective_version) { - pickle->WriteInt(stored_version); - pickle->WriteUInt64(1); // Number of forms in the pickle. - WriteHTMLAttributes(form, pickle); - if (effective_version < 9) - pickle->WriteBool(true); // Unused flag. - WritePreferenceMetadata(form, pickle); - pickle->WriteInt64(form.date_created.ToInternalValue()); - if (effective_version < 2) - return; - pickle->WriteInt(static_cast<int>(form.type)); - pickle->WriteInt(form.times_used); - autofill::SerializeFormData(form.form_data, pickle); - if (effective_version < 3) - return; - pickle->WriteInt64(form.date_synced.ToInternalValue()); - if (effective_version < 4) - return; - pickle->WriteString16(form.display_name); - pickle->WriteString(form.icon_url.spec()); - pickle->WriteString(form.federation_origin.Serialize()); - pickle->WriteBool(form.skip_zero_click); - if (effective_version < 7) - return; - pickle->WriteInt(static_cast<int>(form.generation_upload_status)); -} - -void NativeBackendKWalletPickleTest::CreateVersion0Pickle( - bool size_32, - const PasswordForm& form, - base::Pickle* pickle) { - pickle->WriteInt(0); - // Write the number of forms in the pickle in the appopriate bit size. - if (size_32) - pickle->WriteUInt32(1); - else - pickle->WriteUInt64(1); - WriteHTMLAttributes(form, pickle); - pickle->WriteBool(true); // Unused flag. - WritePreferenceMetadata(form, pickle); - // Old way to store the date. - pickle->WriteInt64(form.date_created.ToTimeT()); -} - -void NativeBackendKWalletPickleTest::CheckVersion9Pickle() { - // Pickle 9+ dropped an old flag in the middle of PasswordForm. This test - // makes sure that the attributes after the dropped flag are deserialised - // correctly. - base::Pickle pickle; - PasswordForm default_values; - PasswordForm form = form_google_; - - CreateVersion1PlusPickle(form, &pickle, 9, 9); - std::vector<std::unique_ptr<PasswordForm>> form_list = - NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle); - EXPECT_EQ(1u, form_list.size()); - if (form_list.size() > 0) - CheckPasswordForm(form, *form_list[0], true); -} - -void NativeBackendKWalletPickleTest::CheckVersion8Pickle() { - base::Pickle pickle; - PasswordForm default_values; - PasswordForm form = form_google_; - - // Version 8 pickles deserialize with their own 'skip_zero_click' value. - form.skip_zero_click = false; - CreateVersion1PlusPickle(form, &pickle, 8, 8); - std::vector<std::unique_ptr<PasswordForm>> form_list = - NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle); - EXPECT_EQ(1u, form_list.size()); - if (form_list.size() > 0) - CheckPasswordForm(form, *form_list[0], true); -} - -void NativeBackendKWalletPickleTest::CheckVersion7Pickle() { - base::Pickle pickle; - PasswordForm default_values; - PasswordForm form = form_google_; - - // Version 7 pickles always deserialize with 'skip_zero_click' of 'true'. - form.skip_zero_click = false; - CreateVersion1PlusPickle(form, &pickle, 7, 7); - std::vector<std::unique_ptr<PasswordForm>> form_list = - NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle); - EXPECT_EQ(1u, form_list.size()); - form.skip_zero_click = true; - if (form_list.size() > 0) - CheckPasswordForm(form, *form_list[0], true); -} - -void NativeBackendKWalletPickleTest::CheckVersion6Pickle( - bool with_optional_field) { - base::Pickle pickle; - PasswordForm form = form_google_; - if (!with_optional_field) { - PasswordForm default_values; - form.generation_upload_status = default_values.generation_upload_status; - } - CreateVersion1PlusPickle(form, &pickle, 6, with_optional_field ? 7 : 5); - - std::vector<std::unique_ptr<PasswordForm>> form_list = - NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle); - - EXPECT_EQ(1u, form_list.size()); - if (form_list.size() > 0) - CheckPasswordForm(form, *form_list[0], true); -} - -void NativeBackendKWalletPickleTest::CheckVersion5Pickle() { - base::Pickle pickle; - PasswordForm default_values; - PasswordForm form = form_google_; - // Remove the field which was not present in version #5. - form.generation_upload_status = default_values.generation_upload_status; - CreateVersion1PlusPickle(form, &pickle, 6, 6); - - std::vector<std::unique_ptr<PasswordForm>> form_list = - NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle); - - EXPECT_EQ(1u, form_list.size()); - if (form_list.size() > 0) - CheckPasswordForm(form, *form_list[0], true); -} - -void NativeBackendKWalletPickleTest::CheckVersion3Pickle() { - base::Pickle pickle; - PasswordForm default_values; - PasswordForm form = form_google_; - // Remove the fields which were not present in version #3. - form.display_name = default_values.display_name; - form.icon_url = default_values.icon_url; - form.federation_origin = default_values.federation_origin; - form.skip_zero_click = default_values.skip_zero_click; - form.generation_upload_status = default_values.generation_upload_status; - CreateVersion1PlusPickle(form, &pickle, 3, 3); - - std::vector<std::unique_ptr<PasswordForm>> form_list = - NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle); - - EXPECT_EQ(1u, form_list.size()); - if (form_list.size() > 0) - CheckPasswordForm(form, *form_list[0], false); -} - -void NativeBackendKWalletPickleTest::CheckVersion2Pickle() { - base::Pickle pickle; - PasswordForm form = old_form_google_; - form.times_used = form_google_.times_used; - form.type = form_google_.type; - form.form_data = form_google_.form_data; - CreateVersion1PlusPickle(form, &pickle, 2, 2); - - std::vector<std::unique_ptr<PasswordForm>> form_list = - NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle); - - EXPECT_EQ(1u, form_list.size()); - if (form_list.size() > 0) - CheckPasswordForm(form, *form_list[0], false); -} - -// Make sure that we can still read version 1 pickles. -void NativeBackendKWalletPickleTest::CheckVersion1Pickle() { - base::Pickle pickle; - PasswordForm form = form_google_; - CreateVersion1PlusPickle(form, &pickle, 1, 1); - - std::vector<std::unique_ptr<PasswordForm>> form_list = - NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle); - - // This will match |old_form_google_| because not all the fields present in - // |form_google_| will be deserialized. - EXPECT_EQ(1u, form_list.size()); - if (form_list.size() > 0) - CheckPasswordForm(old_form_google_, *form_list[0], false); -} - -void NativeBackendKWalletPickleTest::CheckVersion0Pickle( - bool size_32, PasswordForm::Scheme scheme) { - base::Pickle pickle; - PasswordForm form = old_form_google_; - form.scheme = scheme; - CreateVersion0Pickle(size_32, form, &pickle); - std::vector<std::unique_ptr<PasswordForm>> form_list = - NativeBackendKWalletStub::DeserializeValue(form.signon_realm, pickle); - EXPECT_EQ(1u, form_list.size()); - if (form_list.size() > 0) - CheckPasswordForm(form, *form_list[0], false); -} - -// We try both SCHEME_HTML and SCHEME_BASIC since the scheme is stored right -// after the size in the pickle, so it's what gets read as part of the count -// when reading 32-bit pickles on 64-bit systems. SCHEME_HTML is 0 (so we'll -// detect errors later) while SCHEME_BASIC is 1 (so we'll detect it then). We -// try both 32-bit and 64-bit pickles since only one will be the "other" size -// for whatever architecture we're running on, but we want to make sure we can -// read all combinations in any event. - -TEST_F(NativeBackendKWalletPickleTest, ReadsOld32BitHTMLPickles) { - CheckVersion0Pickle(true, PasswordForm::Scheme::kHtml); -} - -TEST_F(NativeBackendKWalletPickleTest, ReadsOld32BitHTTPPickles) { - CheckVersion0Pickle(true, PasswordForm::Scheme::kBasic); -} - -TEST_F(NativeBackendKWalletPickleTest, ReadsOld64BitHTMLPickles) { - CheckVersion0Pickle(false, PasswordForm::Scheme::kHtml); -} - -TEST_F(NativeBackendKWalletPickleTest, ReadsOld64BitHTTPPickles) { - CheckVersion0Pickle(false, PasswordForm::Scheme::kBasic); -} - -TEST_F(NativeBackendKWalletPickleTest, CheckVersion1Pickle) { - CheckVersion1Pickle(); -} - -TEST_F(NativeBackendKWalletPickleTest, CheckVersion2Pickle) { - CheckVersion2Pickle(); -} - -TEST_F(NativeBackendKWalletPickleTest, CheckVersion3Pickle) { - CheckVersion3Pickle(); -} - -TEST_F(NativeBackendKWalletPickleTest, CheckVersion5Pickle) { - CheckVersion5Pickle(); -} - -TEST_F(NativeBackendKWalletPickleTest, CheckVersion6Pickle) { - CheckVersion6Pickle(false); - CheckVersion6Pickle(true); -} - -TEST_F(NativeBackendKWalletPickleTest, CheckVersion7Pickle) { - CheckVersion7Pickle(); -} - -TEST_F(NativeBackendKWalletPickleTest, CheckVersion8Pickle) { - CheckVersion8Pickle(); -} - -TEST_F(NativeBackendKWalletPickleTest, CheckVersion9Pickle) { - CheckVersion9Pickle(); -}
diff --git a/chrome/browser/password_manager/native_backend_libsecret.cc b/chrome/browser/password_manager/native_backend_libsecret.cc deleted file mode 100644 index 8122ce5..0000000 --- a/chrome/browser/password_manager/native_backend_libsecret.cc +++ /dev/null
@@ -1,517 +0,0 @@ -// Copyright (c) 2015 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/password_manager/native_backend_libsecret.h" - -#include <stddef.h> -#include <stdint.h> - -#include <libsecret/secret.h> - -#include <list> -#include <memory> -#include <utility> -#include <vector> - -#include "base/logging.h" -#include "base/metrics/histogram_macros.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/browser/password_manager/password_manager_util_linux.h" -#include "components/password_manager/core/browser/password_manager_metrics_util.h" -#include "components/password_manager/core/browser/password_manager_util.h" -#include "url/origin.h" - -using autofill::PasswordForm; -using base::UTF8ToUTF16; -using base::UTF16ToUTF8; -using password_manager::MatchResult; -using password_manager::PasswordStore; - -namespace { - -// Schema is analagous to the fields in PasswordForm. -const SecretSchema kLibsecretSchema = { - "chrome_libsecret_password_schema", - // We have to use SECRET_SCHEMA_DONT_MATCH_NAME in order to get old - // passwords stored with gnome_keyring. - SECRET_SCHEMA_DONT_MATCH_NAME, - {{"origin_url", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"action_url", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"username_element", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"username_value", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"password_element", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"submit_element", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"signon_realm", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"preferred", SECRET_SCHEMA_ATTRIBUTE_INTEGER}, - {"date_created", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"blacklisted_by_user", SECRET_SCHEMA_ATTRIBUTE_INTEGER}, - {"scheme", SECRET_SCHEMA_ATTRIBUTE_INTEGER}, - {"type", SECRET_SCHEMA_ATTRIBUTE_INTEGER}, - {"times_used", SECRET_SCHEMA_ATTRIBUTE_INTEGER}, - {"date_synced", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"display_name", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"avatar_url", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"federation_url", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {"should_skip_zero_click", SECRET_SCHEMA_ATTRIBUTE_INTEGER}, - {"generation_upload_status", SECRET_SCHEMA_ATTRIBUTE_INTEGER}, - {"form_data", SECRET_SCHEMA_ATTRIBUTE_STRING}, - // This field is always "chrome-profile_id" so that we can search for it. - {"application", SECRET_SCHEMA_ATTRIBUTE_STRING}, - {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING}}}; - -const char* GetStringFromAttributes(GHashTable* attrs, const char* keyname) { - gpointer value = g_hash_table_lookup(attrs, keyname); - return value ? static_cast<char*>(value) : ""; -} - -uint32_t GetUintFromAttributes(GHashTable* attrs, const char* keyname) { - gpointer value = g_hash_table_lookup(attrs, keyname); - if (!value) - return uint32_t(); - uint32_t result; - bool value_ok = base::StringToUint(static_cast<char*>(value), &result); - DCHECK(value_ok); - return result; -} - -// Convert the attributes into a new PasswordForm. -// Note: does *not* get the actual password, as that is not a key attribute! -// Returns nullptr if the attributes are for the wrong application. -std::unique_ptr<PasswordForm> FormOutOfAttributes(GHashTable* attrs) { - base::StringPiece app_value = GetStringFromAttributes(attrs, "application"); - if (!app_value.starts_with(kLibsecretAndGnomeAppString)) - return std::unique_ptr<PasswordForm>(); - - std::unique_ptr<PasswordForm> form(new PasswordForm()); - form->origin = GURL(GetStringFromAttributes(attrs, "origin_url")); - form->action = GURL(GetStringFromAttributes(attrs, "action_url")); - form->username_element = - UTF8ToUTF16(GetStringFromAttributes(attrs, "username_element")); - form->username_value = - UTF8ToUTF16(GetStringFromAttributes(attrs, "username_value")); - form->password_element = - UTF8ToUTF16(GetStringFromAttributes(attrs, "password_element")); - form->submit_element = - UTF8ToUTF16(GetStringFromAttributes(attrs, "submit_element")); - form->signon_realm = GetStringFromAttributes(attrs, "signon_realm"); - form->preferred = GetUintFromAttributes(attrs, "preferred"); - int64_t date_created = 0; - bool date_ok = base::StringToInt64( - GetStringFromAttributes(attrs, "date_created"), &date_created); - DCHECK(date_ok); - // In the past |date_created| was stored as time_t. Currently is stored as - // base::Time's internal value. We need to distinguish, which format the - // number in |date_created| was stored in. We use the fact that - // kMaxPossibleTimeTValue interpreted as the internal value corresponds to an - // unlikely date back in 17th century, and anything above - // kMaxPossibleTimeTValue clearly must be in the internal value format. - form->date_created = date_created < kMaxPossibleTimeTValue - ? base::Time::FromTimeT(date_created) - : base::Time::FromInternalValue(date_created); - form->blacklisted_by_user = - GetUintFromAttributes(attrs, "blacklisted_by_user"); - form->type = - static_cast<PasswordForm::Type>(GetUintFromAttributes(attrs, "type")); - form->times_used = GetUintFromAttributes(attrs, "times_used"); - form->scheme = - static_cast<PasswordForm::Scheme>(GetUintFromAttributes(attrs, "scheme")); - int64_t date_synced = 0; - base::StringToInt64(GetStringFromAttributes(attrs, "date_synced"), - &date_synced); - form->date_synced = base::Time::FromInternalValue(date_synced); - form->display_name = - UTF8ToUTF16(GetStringFromAttributes(attrs, "display_name")); - form->icon_url = GURL(GetStringFromAttributes(attrs, "avatar_url")); - form->federation_origin = url::Origin::Create( - GURL(GetStringFromAttributes(attrs, "federation_url"))); - form->skip_zero_click = - g_hash_table_lookup(attrs, "should_skip_zero_click") - ? GetUintFromAttributes(attrs, "should_skip_zero_click") - : true; - form->generation_upload_status = - static_cast<PasswordForm::GenerationUploadStatus>( - GetUintFromAttributes(attrs, "generation_upload_status")); - base::StringPiece encoded_form_data = - GetStringFromAttributes(attrs, "form_data"); - if (!encoded_form_data.empty()) { - bool success = DeserializeFormDataFromBase64String(encoded_form_data, - &form->form_data); - password_manager::metrics_util::FormDeserializationStatus status = - success ? password_manager::metrics_util::GNOME_SUCCESS - : password_manager::metrics_util::GNOME_FAILURE; - LogFormDataDeserializationStatus(status); - } - return form; -} - -} // namespace - -NativeBackendLibsecret::NativeBackendLibsecret(LocalProfileId id) - : app_string_(GetProfileSpecificAppString(id)), - ensured_keyring_unlocked_(false) {} - -NativeBackendLibsecret::~NativeBackendLibsecret() { -} - -bool NativeBackendLibsecret::Init() { - return LibsecretLoader::EnsureLibsecretLoaded(); -} - -password_manager::PasswordStoreChangeList NativeBackendLibsecret::AddLogin( - const PasswordForm& form) { - // Based on LoginDatabase::AddLogin(), we search for an existing match based - // on origin_url, username_element, username_value, password_element and - // signon_realm first, remove that, and then add the new entry. - password_manager::PasswordStoreChangeList changes; - std::vector<std::unique_ptr<PasswordForm>> forms; - if (!AddUpdateLoginSearch(form, &forms)) - return changes; - - if (forms.size() > 0) { - password_manager::PasswordStoreChangeList temp_changes; - if (forms.size() > 1) { - LOG(WARNING) << "Adding login when there are " << forms.size() - << " matching logins already!"; - } - for (const auto& old_form : forms) { - if (!RemoveLogin(*old_form, &temp_changes)) - return changes; - } - changes.push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::REMOVE, *forms[0])); - } - if (RawAddLogin(form)) { - changes.push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::ADD, form)); - } - return changes; -} - -bool NativeBackendLibsecret::UpdateLogin( - const PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) { - // Based on LoginDatabase::UpdateLogin(), we search for forms to update by - // origin_url, username_element, username_value, password_element, and - // signon_realm. We then compare the result to the updated form. If they - // differ in any of the mutable fields, then we remove the original, and - // then add the new entry. We'd add the new one first, and then delete the - // original, but then the delete might actually delete the newly-added entry! - DCHECK(changes); - std::vector<std::unique_ptr<PasswordForm>> forms; - if (!AddUpdateLoginSearch(form, &forms)) - return false; - if (forms.empty()) - return true; - if (forms.size() == 1 && *forms.front() == form) - return true; - - password_manager::PasswordStoreChangeList temp_changes; - for (const auto& keychain_form : forms) { - // Remove all the obsolete forms. Note that RemoveLogin can remove any form - // matching the unique key. Thus, it's important to call it the right number - // of times. - if (!RemoveLogin(*keychain_form, &temp_changes)) - return false; - } - - if (RawAddLogin(form)) { - password_manager::PasswordStoreChange change( - password_manager::PasswordStoreChange::UPDATE, form); - changes->push_back(change); - return true; - } - return false; -} - -bool NativeBackendLibsecret::RemoveLogin( - const PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) { - DCHECK(changes); - GError* error = nullptr; - if (LibsecretLoader::secret_password_clear_sync( - &kLibsecretSchema, nullptr, &error, "origin_url", - form.origin.spec().c_str(), "username_element", - UTF16ToUTF8(form.username_element).c_str(), "username_value", - UTF16ToUTF8(form.username_value).c_str(), "password_element", - UTF16ToUTF8(form.password_element).c_str(), "signon_realm", - form.signon_realm.c_str(), "application", app_string_.c_str(), - nullptr)) { - changes->push_back(password_manager::PasswordStoreChange( - password_manager::PasswordStoreChange::REMOVE, form)); - } - - if (error) { - LOG(ERROR) << "Libsecret delete failed: " << error->message; - g_error_free(error); - return false; - } - return true; -} - -bool NativeBackendLibsecret::RemoveLoginsCreatedBetween( - base::Time delete_begin, - base::Time delete_end, - password_manager::PasswordStoreChangeList* changes) { - changes->clear(); - std::vector<std::unique_ptr<PasswordForm>> all_forms; - if (!GetLoginsList(nullptr, ALL_LOGINS, &all_forms)) - return false; - - for (const auto& saved_form : all_forms) { - if (delete_begin <= saved_form->date_created && - (delete_end.is_null() || saved_form->date_created < delete_end) && - !RemoveLogin(*saved_form, changes)) { - return false; - } - } - - return true; -} - -bool NativeBackendLibsecret::DisableAutoSignInForOrigins( - const base::Callback<bool(const GURL&)>& origin_filter, - password_manager::PasswordStoreChangeList* changes) { - std::vector<std::unique_ptr<PasswordForm>> all_forms; - if (!GetLoginsList(nullptr, ALL_LOGINS, &all_forms)) - return false; - - for (const std::unique_ptr<PasswordForm>& form : all_forms) { - if (origin_filter.Run(form->origin) && !form->skip_zero_click) { - form->skip_zero_click = true; - if (!UpdateLogin(*form, changes)) - return false; - } - } - - return true; -} - -bool NativeBackendLibsecret::GetLogins( - const PasswordStore::FormDigest& form, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - return GetLoginsList(&form, ALL_LOGINS, forms); -} - -bool NativeBackendLibsecret::AddUpdateLoginSearch( - const PasswordForm& lookup_form, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - if (!ensured_keyring_unlocked_) { - LibsecretLoader::EnsureKeyringUnlocked(); - ensured_keyring_unlocked_ = true; - } - - LibsecretAttributesBuilder attrs; - attrs.Append("origin_url", lookup_form.origin.spec()); - attrs.Append("username_element", UTF16ToUTF8(lookup_form.username_element)); - attrs.Append("username_value", UTF16ToUTF8(lookup_form.username_value)); - attrs.Append("password_element", UTF16ToUTF8(lookup_form.password_element)); - attrs.Append("signon_realm", lookup_form.signon_realm); - attrs.Append("application", app_string_); - - LibsecretLoader::SearchHelper helper; - helper.Search(&kLibsecretSchema, attrs.Get(), - SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK); - if (!helper.success()) - return false; - - PasswordStore::FormDigest form(lookup_form); - *forms = ConvertFormList(helper.results(), &form); - return true; -} - -bool NativeBackendLibsecret::RawAddLogin(const PasswordForm& form) { - int64_t date_created = form.date_created.ToInternalValue(); - // If we are asked to save a password with 0 date, use the current time. - // We don't want to actually save passwords as though on January 1, 1601. - if (!date_created) - date_created = base::Time::Now().ToInternalValue(); - int64_t date_synced = form.date_synced.ToInternalValue(); - std::string form_data; - SerializeFormDataToBase64String(form.form_data, &form_data); - GError* error = nullptr; - // clang-format off - LibsecretLoader::secret_password_store_sync( - &kLibsecretSchema, - nullptr, // Default collection. - form.origin.spec().c_str(), // Display name. - UTF16ToUTF8(form.password_value).c_str(), - nullptr, // no cancellable ojbect - &error, - "origin_url", form.origin.spec().c_str(), - "action_url", form.action.spec().c_str(), - "username_element", UTF16ToUTF8(form.username_element).c_str(), - "username_value", UTF16ToUTF8(form.username_value).c_str(), - "password_element", UTF16ToUTF8(form.password_element).c_str(), - "submit_element", UTF16ToUTF8(form.submit_element).c_str(), - "signon_realm", form.signon_realm.c_str(), - "preferred", form.preferred, - "date_created", base::NumberToString(date_created).c_str(), - "blacklisted_by_user", form.blacklisted_by_user, - "type", form.type, - "times_used", form.times_used, - "scheme", form.scheme, - "date_synced", base::NumberToString(date_synced).c_str(), - "display_name", UTF16ToUTF8(form.display_name).c_str(), - "avatar_url", form.icon_url.spec().c_str(), - // We serialize unique origins as "", in order to make other systems that - // read from the login database happy. https://crbug.com/591310 - "federation_url", form.federation_origin.opaque() - ? "" - : form.federation_origin.Serialize().c_str(), - "should_skip_zero_click", form.skip_zero_click, - "generation_upload_status", form.generation_upload_status, - "form_data", form_data.c_str(), - "application", app_string_.c_str(), - nullptr); - // clang-format on - - if (error) { - LOG(ERROR) << "Libsecret add raw login failed: " << error->message; - g_error_free(error); - return false; - } - return true; -} - -bool NativeBackendLibsecret::GetAutofillableLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - return GetLoginsList(nullptr, AUTOFILLABLE_LOGINS, forms); -} - -bool NativeBackendLibsecret::GetBlacklistLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - return GetLoginsList(nullptr, BLACKLISTED_LOGINS, forms); -} - -bool NativeBackendLibsecret::GetAllLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) { - return GetLoginsList(nullptr, ALL_LOGINS, forms); -} - -scoped_refptr<base::SequencedTaskRunner> -NativeBackendLibsecret::GetBackgroundTaskRunner() { - return nullptr; -} - -bool NativeBackendLibsecret::GetLoginsList( - const PasswordStore::FormDigest* lookup_form, - GetLoginsListOptions options, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - if (!ensured_keyring_unlocked_) { - LibsecretLoader::EnsureKeyringUnlocked(); - ensured_keyring_unlocked_ = true; - } - - LibsecretAttributesBuilder attrs; - attrs.Append("application", app_string_); - if (options != ALL_LOGINS) - attrs.Append("blacklisted_by_user", options == BLACKLISTED_LOGINS); - if (lookup_form && - !password_manager::ShouldPSLDomainMatchingApply( - password_manager::GetRegistryControlledDomain( - GURL(lookup_form->signon_realm))) && - lookup_form->scheme != PasswordForm::Scheme::kHtml) - attrs.Append("signon_realm", lookup_form->signon_realm); - - LibsecretLoader::SearchHelper helper; - helper.Search(&kLibsecretSchema, attrs.Get(), - SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK); - if (!helper.success()) - return false; - - *forms = ConvertFormList(helper.results(), lookup_form); - if (lookup_form) - return true; - - // Get rid of the forms with the same sync tags. - std::vector<std::unique_ptr<PasswordForm>> duplicates; - std::vector<std::vector<PasswordForm*>> tag_groups; - password_manager_util::FindDuplicates(forms, &duplicates, &tag_groups); - if (duplicates.empty()) - return true; - for (const auto& group : tag_groups) { - if (group.size() > 1) { - // There are duplicates. Readd the first form. AddLogin() is smart enough - // to clean the previous ones. - password_manager::PasswordStoreChangeList changes = AddLogin(*group[0]); - if (changes.empty() || - changes.back().type() != password_manager::PasswordStoreChange::ADD) - return false; - } - } - return true; -} - -std::vector<std::unique_ptr<PasswordForm>> -NativeBackendLibsecret::ConvertFormList( - GList* found, - const PasswordStore::FormDigest* lookup_form) { - std::vector<std::unique_ptr<PasswordForm>> forms; - password_manager::PSLDomainMatchMetric psl_domain_match_metric = - password_manager::PSL_DOMAIN_MATCH_NONE; - GError* error = nullptr; - for (GList* element = g_list_first(found); element != nullptr; - element = g_list_next(element)) { - SecretItem* secretItem = static_cast<SecretItem*>(element->data); - GHashTable* attrs = LibsecretLoader::secret_item_get_attributes(secretItem); - std::unique_ptr<PasswordForm> form(FormOutOfAttributes(attrs)); - g_hash_table_unref(attrs); - if (!form) { - VLOG(1) << "Could not initialize PasswordForm from attributes!"; - continue; - } - - if (lookup_form) { - switch (GetMatchResult(*form, *lookup_form)) { - case MatchResult::NO_MATCH: - continue; - case MatchResult::EXACT_MATCH: - break; - case MatchResult::PSL_MATCH: - psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; - form->is_public_suffix_match = true; - break; - case MatchResult::FEDERATED_MATCH: - break; - case MatchResult::FEDERATED_PSL_MATCH: - psl_domain_match_metric = - password_manager::PSL_DOMAIN_MATCH_FOUND_FEDERATED; - form->is_public_suffix_match = true; - break; - } - } - - LibsecretLoader::secret_item_load_secret_sync(secretItem, nullptr, &error); - if (error) { - LOG(ERROR) << "Unable to load secret item" << error->message; - g_error_free(error); - error = nullptr; - continue; - } - - SecretValue* secretValue = - LibsecretLoader::secret_item_get_secret(secretItem); - if (secretValue) { - form->password_value = - UTF8ToUTF16(LibsecretLoader::secret_value_get_text(secretValue)); - LibsecretLoader::secret_value_unref(secretValue); - } else { - LOG(WARNING) << "Unable to access password from list element!"; - } - forms.push_back(std::move(form)); - } - - if (lookup_form) { - const bool allow_psl_match = password_manager::ShouldPSLDomainMatchingApply( - password_manager::GetRegistryControlledDomain( - GURL(lookup_form->signon_realm))); - UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", - allow_psl_match - ? psl_domain_match_metric - : password_manager::PSL_DOMAIN_MATCH_NOT_USED, - password_manager::PSL_DOMAIN_MATCH_COUNT); - } - return forms; -}
diff --git a/chrome/browser/password_manager/native_backend_libsecret.h b/chrome/browser/password_manager/native_backend_libsecret.h deleted file mode 100644 index 5cb318c1f..0000000 --- a/chrome/browser/password_manager/native_backend_libsecret.h +++ /dev/null
@@ -1,98 +0,0 @@ -// Copyright (c) 2015 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 CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_LIBSECRET_H_ -#define CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_LIBSECRET_H_ - -#include <memory> -#include <string> -#include <vector> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/sequenced_task_runner.h" -#include "base/time/time.h" -#include "chrome/browser/password_manager/password_store_factory.h" -#include "chrome/browser/password_manager/password_store_x.h" -#include "chrome/browser/profiles/profile.h" -#include "components/os_crypt/libsecret_util_linux.h" - -namespace autofill { -struct PasswordForm; -} - -class NativeBackendLibsecret : public PasswordStoreX::NativeBackend { - public: - explicit NativeBackendLibsecret(LocalProfileId id); - - ~NativeBackendLibsecret() override; - - bool Init() override; - - // Implements NativeBackend interface. - password_manager::PasswordStoreChangeList AddLogin( - const autofill::PasswordForm& form) override; - bool UpdateLogin(const autofill::PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) override; - bool RemoveLogin(const autofill::PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) override; - bool RemoveLoginsCreatedBetween( - base::Time delete_begin, - base::Time delete_end, - password_manager::PasswordStoreChangeList* changes) override; - bool DisableAutoSignInForOrigins( - const base::Callback<bool(const GURL&)>& origin_filter, - password_manager::PasswordStoreChangeList* changes) override; - bool GetLogins( - const password_manager::PasswordStore::FormDigest& form, - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - bool GetAutofillableLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - bool GetBlacklistLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - bool GetAllLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner() override; - - private: - // Returns credentials matching |lookup_form| via |forms|. - bool AddUpdateLoginSearch( - const autofill::PasswordForm& lookup_form, - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms); - - // Adds a login form without checking for one to replace first. - bool RawAddLogin(const autofill::PasswordForm& form); - - enum GetLoginsListOptions { - ALL_LOGINS, - AUTOFILLABLE_LOGINS, - BLACKLISTED_LOGINS, - }; - - // Retrieves credentials matching |options| from the keyring into |forms|, - // overwriting the original contents of |forms|. If |lookup_form| is not NULL, - // only retrieves credentials PSL-matching it. Returns true on success. - bool GetLoginsList( - const password_manager::PasswordStore::FormDigest* lookup_form, - GetLoginsListOptions options, - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) - WARN_UNUSED_RESULT; - - // Convert data get from Libsecret to Passwordform. Uses |lookup_form| for - // additional (PSL) matching, if present. - std::vector<std::unique_ptr<autofill::PasswordForm>> ConvertFormList( - GList* found, - const password_manager::PasswordStore::FormDigest* lookup_form); - - // The app string, possibly based on the local profile id. - std::string app_string_; - - // True if we're already ensured that the default keyring has been unlocked - // once. - bool ensured_keyring_unlocked_; - - DISALLOW_COPY_AND_ASSIGN(NativeBackendLibsecret); -}; - -#endif // CHROME_BROWSER_PASSWORD_MANAGER_NATIVE_BACKEND_LIBSECRET_H_
diff --git a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc deleted file mode 100644 index 21372cf7..0000000 --- a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc +++ /dev/null
@@ -1,1018 +0,0 @@ -// Copyright (c) 2015 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 <stdarg.h> -#include <stddef.h> -#include <stdint.h> - -#include "base/bind.h" -#include "base/location.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/string_util.h" -#include "base/strings/utf_string_conversions.h" -#include "base/test/scoped_task_environment.h" -#include "base/time/time.h" -#include "chrome/browser/password_manager/native_backend_libsecret.h" -#include "chrome/test/base/testing_profile.h" -#include "components/autofill/core/common/password_form.h" -#include "components/password_manager/core/browser/psl_matching_helper.h" -#include "components/password_manager/core/common/password_manager_pref_names.h" -#include "components/prefs/pref_service.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using autofill::PasswordForm; -using base::UTF8ToUTF16; -using base::UTF16ToUTF8; -using password_manager::PasswordStore; -using password_manager::PasswordStoreChange; -using password_manager::PasswordStoreChangeList; -using testing::Pointee; -using testing::UnorderedElementsAre; - -namespace { - -// What follows is a very simple implementation of the subset of the Libsecret -// API that we actually use. It gets substituted for the real one by -// MockLibsecretLoader, which hooks into the facility normally used to load -// the libsecret library at runtime to avoid a static dependency on it. - -struct MockSecretValue { - gchar* password; - explicit MockSecretValue(gchar* password) : password(password) {} - ~MockSecretValue() { g_free(password); } -}; - -struct MockSecretItem { - std::unique_ptr<MockSecretValue> value; - GHashTable* attributes; - - MockSecretItem(std::unique_ptr<MockSecretValue> value, GHashTable* attributes) - : value(std::move(value)), attributes(attributes) {} - ~MockSecretItem() { - g_hash_table_destroy(attributes); - } - - void RemoveAttribute(const char* keyname) { - g_hash_table_remove(attributes, keyname); - } -}; - -bool Matches(MockSecretItem* item, GHashTable* query) { - GHashTable* attributes = item->attributes; - GHashTableIter iter; - gchar* name; - gchar* query_value; - g_hash_table_iter_init(&iter, query); - - while (g_hash_table_iter_next(&iter, reinterpret_cast<gpointer*>(&name), - reinterpret_cast<gpointer*>(&query_value))) { - gchar* value = static_cast<gchar*>(g_hash_table_lookup(attributes, name)); - if (value == nullptr || strcmp(value, query_value) != 0) - return false; - } - return true; -} - -bool IsStringAttribute(const SecretSchema* schema, const std::string& name) { - for (size_t i = 0; schema->attributes[i].name; ++i) - if (name == schema->attributes[i].name) - return schema->attributes[i].type == SECRET_SCHEMA_ATTRIBUTE_STRING; - NOTREACHED() << "Requested type of nonexistent attribute"; - return false; -} - -// The list of all libsecret items we have stored. -std::vector<std::unique_ptr<MockSecretItem>>* global_mock_libsecret_items; -std::unordered_map<GObject*, MockSecretItem*>* global_map_object_to_secret_item; -bool global_mock_libsecret_reject_local_ids = false; - -GObject* MakeNewObject(MockSecretItem* item) { - // Create an object with a ref-count of 2. The caller is expected to release - // one reference, and the second reference is released during test tear down - // along with checks that the ref count is correct. - GObject* o = static_cast<GObject*>(g_object_new(G_TYPE_OBJECT, nullptr)); - g_object_ref(o); - (*global_map_object_to_secret_item)[o] = item; - return o; -} - -gboolean mock_secret_password_store_sync(const SecretSchema* schema, - const gchar* collection, - const gchar* label, - const gchar* password, - GCancellable* cancellable, - GError** error, - ...) { - // TODO(crbug.com/660005) We don't read the dummy we store to unlock keyring. - if (strcmp("_chrome_dummy_schema_for_unlocking", schema->name) == 0) - return true; - - GHashTable* attributes = - g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - va_list ap; - va_start(ap, error); - char* name; - while ((name = va_arg(ap, gchar*))) { - char* value; - if (IsStringAttribute(schema, name)) { - value = g_strdup(va_arg(ap, gchar*)); - VLOG(1) << "Adding item attribute " << name << ", value '" << value - << "'"; - } else { - uint32_t intvalue = va_arg(ap, uint32_t); - VLOG(1) << "Adding item attribute " << name << ", value " << intvalue; - value = g_strdup_printf("%u", intvalue); - } - g_hash_table_insert(attributes, g_strdup(name), value); - } - va_end(ap); - global_mock_libsecret_items->push_back(std::make_unique<MockSecretItem>( - std::make_unique<MockSecretValue>(g_strdup(password)), attributes)); - return true; -} - -GList* mock_secret_service_search_sync(SecretService* service, - const SecretSchema* schema, - GHashTable* attributes, - SecretSearchFlags flags, - GCancellable* cancellable, - GError** error) { - EXPECT_TRUE(flags & SECRET_SEARCH_UNLOCK); - GList* result = nullptr; - for (std::unique_ptr<MockSecretItem>& item : *global_mock_libsecret_items) { - if (Matches(item.get(), attributes)) { - result = g_list_append(result, MakeNewObject(item.get())); - } - } - return result; -} - -gboolean mock_secret_password_clear_sync(const SecretSchema* schema, - GCancellable* cancellable, - GError** error, - ...) { - GHashTable* attributes = - g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); - va_list ap; - va_start(ap, error); - char* name; - while ((name = va_arg(ap, gchar*))) { - char* value; - if (IsStringAttribute(schema, name)) { - value = g_strdup(va_arg(ap, gchar*)); - VLOG(1) << "Adding item attribute " << name << ", value '" << value - << "'"; - } else { - uint32_t intvalue = va_arg(ap, uint32_t); - VLOG(1) << "Adding item attribute " << name << ", value " << intvalue; - value = g_strdup_printf("%u", intvalue); - } - g_hash_table_insert(attributes, g_strdup(name), value); - } - va_end(ap); - - std::vector<std::unique_ptr<MockSecretItem>> kept_mock_libsecret_items; - kept_mock_libsecret_items.reserve(global_mock_libsecret_items->size()); - for (std::unique_ptr<MockSecretItem>& item : *global_mock_libsecret_items) { - if (!Matches(item.get(), attributes)) { - kept_mock_libsecret_items.push_back(std::move(item)); - } - } - global_mock_libsecret_items->swap(kept_mock_libsecret_items); - - g_hash_table_unref(attributes); - return - global_mock_libsecret_items->size() != kept_mock_libsecret_items.size(); -} - -SecretValue* mock_secret_item_get_secret(SecretItem* self) { - GObject* o = reinterpret_cast<GObject*>(self); - MockSecretValue* mock_value = - (*global_map_object_to_secret_item)[o]->value.get(); - return reinterpret_cast<SecretValue*>(mock_value); -} - -const gchar* mock_secret_value_get_text(SecretValue* value) { - return reinterpret_cast<MockSecretValue*>(value)->password; -} - -GHashTable* mock_secret_item_get_attributes(SecretItem* self) { - // Libsecret backend will make unreference of received attributes, so in - // order to save them we need to increase their reference number. - GObject* o = reinterpret_cast<GObject*>(self); - MockSecretItem* mock_ptr = (*global_map_object_to_secret_item)[o]; - g_hash_table_ref(mock_ptr->attributes); - return mock_ptr->attributes; -} - -gboolean mock_secret_item_load_secret_sync(SecretItem* self, - GCancellable* cancellable, - GError** error) { - return true; -} - -void mock_secret_value_unref(gpointer value) { -} - -// Inherit to get access to protected fields. -class MockLibsecretLoader : public LibsecretLoader { - public: - static bool LoadMockLibsecret() { - secret_password_store_sync = &mock_secret_password_store_sync; - secret_service_search_sync = &mock_secret_service_search_sync; - secret_password_clear_sync = &mock_secret_password_clear_sync; - secret_item_get_secret = &mock_secret_item_get_secret; - secret_value_get_text = &mock_secret_value_get_text; - secret_item_get_attributes = &mock_secret_item_get_attributes; - secret_item_load_secret_sync = &mock_secret_item_load_secret_sync; - secret_value_unref = &mock_secret_value_unref; - libsecret_loaded_ = true; - // Reset the state of the mock library. - global_mock_libsecret_items->clear(); - global_map_object_to_secret_item->clear(); - global_mock_libsecret_reject_local_ids = false; - return true; - } -}; - -void CheckPasswordChanges(const PasswordStoreChangeList& expected_list, - const PasswordStoreChangeList& actual_list) { - ASSERT_EQ(expected_list.size(), actual_list.size()); - for (size_t i = 0; i < expected_list.size(); ++i) { - EXPECT_EQ(expected_list[i].type(), actual_list[i].type()); - EXPECT_EQ(expected_list[i].form(), actual_list[i].form()); - } -} - -void VerifiedAdd(NativeBackendLibsecret* backend, const PasswordForm& form) { - SCOPED_TRACE("VerifiedAdd"); - PasswordStoreChangeList changes = backend->AddLogin(form); - PasswordStoreChangeList expected(1, - PasswordStoreChange(PasswordStoreChange::ADD, - form)); - CheckPasswordChanges(expected, changes); -} - -void VerifiedUpdate(NativeBackendLibsecret* backend, const PasswordForm& form) { - SCOPED_TRACE("VerifiedUpdate"); - PasswordStoreChangeList changes; - EXPECT_TRUE(backend->UpdateLogin(form, &changes)); - PasswordStoreChangeList expected(1, PasswordStoreChange( - PasswordStoreChange::UPDATE, form)); - CheckPasswordChanges(expected, changes); -} - -void VerifiedRemove(NativeBackendLibsecret* backend, const PasswordForm& form) { - SCOPED_TRACE("VerifiedRemove"); - PasswordStoreChangeList changes; - EXPECT_TRUE(backend->RemoveLogin(form, &changes)); - CheckPasswordChanges(PasswordStoreChangeList(1, PasswordStoreChange( - PasswordStoreChange::REMOVE, form)), changes); -} - -} // anonymous namespace - -class NativeBackendLibsecretTest : public testing::Test { - protected: - enum UpdateType { // Used in CheckPSLUpdate(). - UPDATE_BY_UPDATELOGIN, - UPDATE_BY_ADDLOGIN, - }; - - NativeBackendLibsecretTest() - : scoped_task_environment_( - base::test::ScopedTaskEnvironment::MainThreadType::UI) {} - - void SetUp() override { - ASSERT_FALSE(global_mock_libsecret_items); - ASSERT_FALSE(global_map_object_to_secret_item); - global_mock_libsecret_items = &mock_libsecret_items_; - global_map_object_to_secret_item = &mock_map_object_to_secret_item_; - - ASSERT_TRUE(MockLibsecretLoader::LoadMockLibsecret()); - - form_google_.origin = GURL("http://www.google.com/"); - form_google_.action = GURL("http://www.google.com/login"); - form_google_.username_element = UTF8ToUTF16("user"); - form_google_.username_value = UTF8ToUTF16("joeschmoe"); - form_google_.password_element = UTF8ToUTF16("pass"); - form_google_.password_value = UTF8ToUTF16("seekrit"); - form_google_.submit_element = UTF8ToUTF16("submit"); - form_google_.signon_realm = "http://www.google.com/"; - form_google_.type = PasswordForm::Type::kGenerated; - form_google_.date_created = base::Time::Now(); - form_google_.date_synced = base::Time::Now(); - form_google_.display_name = UTF8ToUTF16("Joe Schmoe"); - form_google_.icon_url = GURL("http://www.google.com/icon"); - form_google_.federation_origin = - url::Origin::Create(GURL("http://www.google.com/")); - form_google_.skip_zero_click = true; - form_google_.generation_upload_status = - PasswordForm::GenerationUploadStatus::kPositiveSignalSent; - form_google_.form_data.name = UTF8ToUTF16("form_name"); - - form_facebook_.origin = GURL("http://www.facebook.com/"); - form_facebook_.action = GURL("http://www.facebook.com/login"); - form_facebook_.username_element = UTF8ToUTF16("user"); - form_facebook_.username_value = UTF8ToUTF16("a"); - form_facebook_.password_element = UTF8ToUTF16("password"); - form_facebook_.password_value = UTF8ToUTF16("b"); - form_facebook_.submit_element = UTF8ToUTF16("submit"); - form_facebook_.signon_realm = "http://www.facebook.com/"; - form_facebook_.date_created = base::Time::Now(); - form_facebook_.date_synced = base::Time::Now(); - form_facebook_.display_name = UTF8ToUTF16("Joe Schmoe"); - form_facebook_.icon_url = GURL("http://www.facebook.com/icon"); - form_facebook_.federation_origin = - url::Origin::Create(GURL("http://www.facebook.com/")); - form_facebook_.skip_zero_click = true; - form_facebook_.generation_upload_status = - PasswordForm::GenerationUploadStatus::kNoSignalSent; - - form_isc_.origin = GURL("http://www.isc.org/"); - form_isc_.action = GURL("http://www.isc.org/auth"); - form_isc_.username_element = UTF8ToUTF16("id"); - form_isc_.username_value = UTF8ToUTF16("janedoe"); - form_isc_.password_element = UTF8ToUTF16("passwd"); - form_isc_.password_value = UTF8ToUTF16("ihazabukkit"); - form_isc_.submit_element = UTF8ToUTF16("login"); - form_isc_.signon_realm = "http://www.isc.org/"; - form_isc_.date_created = base::Time::Now(); - form_isc_.date_synced = base::Time::Now(); - - other_auth_.origin = GURL("http://www.example.com/"); - other_auth_.username_value = UTF8ToUTF16("username"); - other_auth_.password_value = UTF8ToUTF16("pass"); - other_auth_.signon_realm = "http://www.example.com/Realm"; - other_auth_.date_created = base::Time::Now(); - other_auth_.date_synced = base::Time::Now(); - } - - void TearDown() override { - scoped_task_environment_.RunUntilIdle(); - ASSERT_TRUE(global_mock_libsecret_items); - global_mock_libsecret_items = nullptr; - for (auto& pair : *global_map_object_to_secret_item) { - ASSERT_EQ(pair.first->ref_count, 1u); - g_object_unref(pair.first); - } - global_map_object_to_secret_item->clear(); - global_map_object_to_secret_item = nullptr; - } - - void CheckUint32Attribute(const MockSecretItem* item, - const std::string& attribute, - uint32_t value) { - gpointer item_value = - g_hash_table_lookup(item->attributes, attribute.c_str()); - EXPECT_TRUE(item_value) << " in attribute " << attribute; - if (item_value) { - uint32_t int_value; - bool conversion_ok = - base::StringToUint(static_cast<char*>(item_value), &int_value); - EXPECT_TRUE(conversion_ok); - EXPECT_EQ(value, int_value); - } - } - - void CheckStringAttribute(const MockSecretItem* item, - const std::string& attribute, - const std::string& value) { - gpointer item_value = - g_hash_table_lookup(item->attributes, attribute.c_str()); - EXPECT_TRUE(item_value) << " in attribute " << attribute; - if (item_value) { - EXPECT_EQ(value, static_cast<char*>(item_value)); - } - } - - void CheckMockSecretItem(const MockSecretItem* item, - const PasswordForm& form, - const std::string& app_string) { - EXPECT_EQ(UTF16ToUTF8(form.password_value), item->value->password); - EXPECT_EQ(21u, g_hash_table_size(item->attributes)); - CheckStringAttribute(item, "origin_url", form.origin.spec()); - CheckStringAttribute(item, "action_url", form.action.spec()); - CheckStringAttribute(item, "username_element", - UTF16ToUTF8(form.username_element)); - CheckStringAttribute(item, "username_value", - UTF16ToUTF8(form.username_value)); - CheckStringAttribute(item, "password_element", - UTF16ToUTF8(form.password_element)); - CheckStringAttribute(item, "submit_element", - UTF16ToUTF8(form.submit_element)); - CheckStringAttribute(item, "signon_realm", form.signon_realm); - CheckUint32Attribute(item, "preferred", form.preferred); - // We don't check the date created. It varies. - CheckUint32Attribute(item, "blacklisted_by_user", form.blacklisted_by_user); - CheckUint32Attribute(item, "type", static_cast<uint32_t>(form.type)); - CheckUint32Attribute(item, "times_used", form.times_used); - CheckUint32Attribute(item, "scheme", static_cast<uint32_t>(form.scheme)); - CheckStringAttribute( - item, "date_synced", - base::NumberToString(form.date_synced.ToInternalValue())); - CheckStringAttribute(item, "display_name", UTF16ToUTF8(form.display_name)); - CheckStringAttribute(item, "avatar_url", form.icon_url.spec()); - // We serialize unique origins as "", in order to make other systems that - // read from the login database happy. https://crbug.com/591310 - CheckStringAttribute(item, "federation_url", - form.federation_origin.opaque() - ? "" - : form.federation_origin.Serialize()); - CheckUint32Attribute(item, "should_skip_zero_click", form.skip_zero_click); - CheckUint32Attribute(item, "generation_upload_status", - static_cast<uint32_t>(form.generation_upload_status)); - CheckStringAttribute(item, "application", app_string); - autofill::FormData actual; - DeserializeFormDataFromBase64String( - static_cast<char*>(g_hash_table_lookup(item->attributes, "form_data")), - &actual); - EXPECT_TRUE(form.form_data.SameFormAs(actual)); - } - - // Saves |credentials| and then gets logins matching |url| and |scheme|. - // Returns true when something is found, and in such case copies the result to - // |result| when |result| is not nullptr. (Note that there can be max. 1 - // result derived from |credentials|.) - bool CheckCredentialAvailability(const PasswordForm& credentials, - const GURL& url, - const PasswordForm::Scheme& scheme, - PasswordForm* result) { - NativeBackendLibsecret backend(321); - - VerifiedAdd(&backend, credentials); - - PasswordStore::FormDigest target_form = {PasswordForm::Scheme::kHtml, - url.spec(), url}; - if (scheme != PasswordForm::Scheme::kHtml) { - // For non-HTML forms, the realm used for authentication - // (http://tools.ietf.org/html/rfc1945#section-10.2) is appended to the - // signon_realm. Just use a default value for now. - target_form.signon_realm.append("Realm"); - } - std::vector<std::unique_ptr<PasswordForm>> form_list; - EXPECT_TRUE(backend.GetLogins(target_form, &form_list)); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), credentials, - "chrome-321"); - global_mock_libsecret_items->clear(); - - if (form_list.empty()) - return false; - EXPECT_EQ(1u, form_list.size()); - if (result) - *result = *form_list[0]; - return true; - } - - // Test that updating does not use PSL matching: Add a www.facebook.com - // password, then use PSL matching to get a copy of it for m.facebook.com, and - // add that copy as well. Now update the www.facebook.com password -- the - // m.facebook.com password should not get updated. Depending on the argument, - // the credential update is done via UpdateLogin or AddLogin. - void CheckPSLUpdate(UpdateType update_type) { - NativeBackendLibsecret backend(321); - - VerifiedAdd(&backend, form_facebook_); - - // Get the PSL-matched copy of the saved login for m.facebook. - const GURL kMobileURL("http://m.facebook.com/"); - PasswordStore::FormDigest m_facebook_lookup = { - PasswordForm::Scheme::kHtml, kMobileURL.spec(), kMobileURL}; - std::vector<std::unique_ptr<PasswordForm>> form_list; - EXPECT_TRUE(backend.GetLogins(m_facebook_lookup, &form_list)); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - EXPECT_EQ(1u, form_list.size()); - PasswordForm m_facebook = *form_list[0]; - form_list.clear(); - m_facebook.origin = kMobileURL; - m_facebook.signon_realm = kMobileURL.spec(); - - // Add the PSL-matched copy to saved logins. - VerifiedAdd(&backend, m_facebook); - EXPECT_EQ(2u, global_mock_libsecret_items->size()); - - // Update www.facebook.com login. - PasswordForm new_facebook(form_facebook_); - const base::string16 kOldPassword(form_facebook_.password_value); - const base::string16 kNewPassword(UTF8ToUTF16("new_b")); - EXPECT_NE(kOldPassword, kNewPassword); - new_facebook.password_value = kNewPassword; - switch (update_type) { - case UPDATE_BY_UPDATELOGIN: - VerifiedUpdate(&backend, new_facebook); - break; - case UPDATE_BY_ADDLOGIN: - // This is an overwrite call. - backend.AddLogin(new_facebook); - break; - } - - EXPECT_EQ(2u, global_mock_libsecret_items->size()); - - // Check that m.facebook.com login was not modified by the update. - EXPECT_TRUE(backend.GetLogins(m_facebook_lookup, &form_list)); - - // There should be two results -- the exact one, and the PSL-matched one. - EXPECT_EQ(2u, form_list.size()); - size_t index_non_psl = 0; - if (form_list[index_non_psl]->is_public_suffix_match) - index_non_psl = 1; - EXPECT_EQ(kMobileURL, form_list[index_non_psl]->origin); - EXPECT_EQ(kMobileURL.spec(), form_list[index_non_psl]->signon_realm); - EXPECT_EQ(kOldPassword, form_list[index_non_psl]->password_value); - form_list.clear(); - - // Check that www.facebook.com login was modified by the update. - EXPECT_TRUE(backend.GetLogins(PasswordStore::FormDigest(form_facebook_), - &form_list)); - // There should be two results -- the exact one, and the PSL-matched one. - EXPECT_EQ(2u, form_list.size()); - index_non_psl = 0; - if (form_list[index_non_psl]->is_public_suffix_match) - index_non_psl = 1; - EXPECT_EQ(form_facebook_.origin, form_list[index_non_psl]->origin); - EXPECT_EQ(form_facebook_.signon_realm, - form_list[index_non_psl]->signon_realm); - EXPECT_EQ(kNewPassword, form_list[index_non_psl]->password_value); - form_list.clear(); - } - - // Checks various types of matching for forms with a non-HTML |scheme|. - void CheckMatchingWithScheme(const PasswordForm::Scheme& scheme) { - ASSERT_NE(PasswordForm::Scheme::kHtml, scheme); - other_auth_.scheme = scheme; - - // Don't match a non-HTML form with an HTML form. - EXPECT_FALSE( - CheckCredentialAvailability(other_auth_, GURL("http://www.example.com"), - PasswordForm::Scheme::kHtml, nullptr)); - // Don't match an HTML form with non-HTML auth form. - EXPECT_FALSE(CheckCredentialAvailability( - form_google_, GURL("http://www.google.com/"), scheme, nullptr)); - // Don't match two different non-HTML auth forms with different origin. - EXPECT_FALSE(CheckCredentialAvailability( - other_auth_, GURL("http://first.example.com"), scheme, nullptr)); - // Do match non-HTML forms from the same origin. - EXPECT_TRUE(CheckCredentialAvailability( - other_auth_, GURL("http://www.example.com/"), scheme, nullptr)); - } - - base::test::ScopedTaskEnvironment scoped_task_environment_; - - // Provide some test forms to avoid having to set them up in each test. - PasswordForm form_google_; - PasswordForm form_facebook_; - PasswordForm form_isc_; - PasswordForm other_auth_; - - std::vector<std::unique_ptr<MockSecretItem>> mock_libsecret_items_; - std::unordered_map<GObject*, MockSecretItem*> mock_map_object_to_secret_item_; -}; - -TEST_F(NativeBackendLibsecretTest, BasicAddLogin) { - NativeBackendLibsecret backend(42); - - VerifiedAdd(&backend, form_google_); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); -} - -TEST_F(NativeBackendLibsecretTest, BasicListLogins) { - NativeBackendLibsecret backend(42); - - VerifiedAdd(&backend, form_google_); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - EXPECT_TRUE(backend.GetAutofillableLogins(&form_list)); - - ASSERT_EQ(1u, form_list.size()); - EXPECT_EQ(form_google_, *form_list[0]); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); -} - -TEST_F(NativeBackendLibsecretTest, GetAllLogins) { - NativeBackendLibsecret backend(42); - - VerifiedAdd(&backend, form_google_); - VerifiedAdd(&backend, form_facebook_); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - EXPECT_TRUE(backend.GetAllLogins(&form_list)); - - ASSERT_EQ(2u, form_list.size()); - EXPECT_THAT(form_list, UnorderedElementsAre(Pointee(form_google_), - Pointee(form_facebook_))); -} - -// Save a password for www.facebook.com and see it suggested for m.facebook.com. -TEST_F(NativeBackendLibsecretTest, PSLMatchingPositive) { - PasswordForm result; - const GURL kMobileURL("http://m.facebook.com/"); - EXPECT_TRUE(CheckCredentialAvailability( - form_facebook_, kMobileURL, PasswordForm::Scheme::kHtml, &result)); - EXPECT_EQ(form_facebook_.origin, result.origin); - EXPECT_EQ(form_facebook_.signon_realm, result.signon_realm); -} - -// Save a password for www.facebook.com and see it not suggested for -// m-facebook.com. -TEST_F(NativeBackendLibsecretTest, PSLMatchingNegativeDomainMismatch) { - EXPECT_FALSE(CheckCredentialAvailability( - form_facebook_, GURL("http://m-facebook.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -// Test PSL matching is off for domains excluded from it. -TEST_F(NativeBackendLibsecretTest, PSLMatchingDisabledDomains) { - EXPECT_FALSE( - CheckCredentialAvailability(form_google_, GURL("http://one.google.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -// Make sure PSL matches aren't available for non-HTML forms. -TEST_F(NativeBackendLibsecretTest, PSLMatchingDisabledForNonHTMLForms) { - CheckMatchingWithScheme(PasswordForm::Scheme::kBasic); - CheckMatchingWithScheme(PasswordForm::Scheme::kDigest); - CheckMatchingWithScheme(PasswordForm::Scheme::kOther); -} - -TEST_F(NativeBackendLibsecretTest, PSLUpdatingStrictUpdateLogin) { - CheckPSLUpdate(UPDATE_BY_UPDATELOGIN); -} - -TEST_F(NativeBackendLibsecretTest, PSLUpdatingStrictAddLogin) { - CheckPSLUpdate(UPDATE_BY_ADDLOGIN); -} - -TEST_F(NativeBackendLibsecretTest, FetchFederatedCredentialOnHTTPS) { - other_auth_.signon_realm = "federation://www.example.com/google.com"; - other_auth_.origin = GURL("https://www.example.com/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_TRUE( - CheckCredentialAvailability(other_auth_, GURL("https://www.example.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendLibsecretTest, FetchFederatedCredentialOnLocalhost) { - other_auth_.signon_realm = "federation://localhost/google.com"; - other_auth_.origin = GURL("http://localhost:8080/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_TRUE( - CheckCredentialAvailability(other_auth_, GURL("http://localhost:8080/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendLibsecretTest, DontFetchFederatedCredentialOnHTTP) { - other_auth_.signon_realm = "federation://www.example.com/google.com"; - other_auth_.origin = GURL("https://www.example.com/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_FALSE( - CheckCredentialAvailability(other_auth_, GURL("http://www.example.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendLibsecretTest, FetchPSLMatchedFederatedCredentialOnHTTPS) { - other_auth_.signon_realm = "federation://www.sub.example.com/google.com"; - other_auth_.origin = GURL("https://www.sub.example.com/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_TRUE( - CheckCredentialAvailability(other_auth_, GURL("https://www.example.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendLibsecretTest, - DontFetchPSLMatchedFederatedCredentialOnHTTP) { - other_auth_.signon_realm = "federation://www.sub.example.com/google.com"; - other_auth_.origin = GURL("https://www.sub.example.com/"); - other_auth_.federation_origin = - url::Origin::Create(GURL("https://google.com/")); - EXPECT_FALSE( - CheckCredentialAvailability(other_auth_, GURL("http://www.example.com/"), - PasswordForm::Scheme::kHtml, nullptr)); -} - -TEST_F(NativeBackendLibsecretTest, BasicUpdateLogin) { - NativeBackendLibsecret backend(42); - - VerifiedAdd(&backend, form_google_); - - PasswordForm new_form_google(form_google_); - new_form_google.times_used = 1; - new_form_google.action = GURL("http://www.google.com/different/login"); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) { - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); - } - - // Update login - VerifiedUpdate(&backend, new_form_google); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), - new_form_google, "chrome-42"); -} - -TEST_F(NativeBackendLibsecretTest, BasicRemoveLogin) { - NativeBackendLibsecret backend(42); - - VerifiedAdd(&backend, form_google_); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); - - VerifiedRemove(&backend, form_google_); - - EXPECT_TRUE(global_mock_libsecret_items->empty()); -} - -// Verify fix for http://crbug.com/408783. -TEST_F(NativeBackendLibsecretTest, RemoveLoginActionMismatch) { - NativeBackendLibsecret backend(42); - - VerifiedAdd(&backend, form_google_); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); - - // Action url match not required for removal. - form_google_.action = GURL("https://some.other.url.com/path"); - VerifiedRemove(&backend, form_google_); - - EXPECT_TRUE(global_mock_libsecret_items->empty()); -} - -TEST_F(NativeBackendLibsecretTest, RemoveNonexistentLogin) { - NativeBackendLibsecret backend(42); - - // First add an unrelated login. - VerifiedAdd(&backend, form_google_); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); - - // Attempt to remove a login that doesn't exist. - PasswordStoreChangeList changes; - EXPECT_TRUE(backend.RemoveLogin(form_isc_, &changes)); - CheckPasswordChanges(PasswordStoreChangeList(), changes); - - // Make sure we can still get the first form back. - std::vector<std::unique_ptr<PasswordForm>> form_list; - EXPECT_TRUE(backend.GetAutofillableLogins(&form_list)); - - // Quick check that we got something back. - EXPECT_EQ(1u, form_list.size()); - form_list.clear(); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); -} - -TEST_F(NativeBackendLibsecretTest, UpdateNonexistentLogin) { - NativeBackendLibsecret backend(42); - - // First add an unrelated login. - VerifiedAdd(&backend, form_google_); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) { - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); - } - - // Attempt to update a login that doesn't exist. - PasswordStoreChangeList changes; - EXPECT_TRUE(backend.UpdateLogin(form_isc_, &changes)); - CheckPasswordChanges(PasswordStoreChangeList(), changes); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); -} - -TEST_F(NativeBackendLibsecretTest, UpdateSameLogin) { - NativeBackendLibsecret backend(42); - - VerifiedAdd(&backend, form_google_); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) { - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); - } - - // Attempt to update the same login without changing anything. - PasswordStoreChangeList changes; - EXPECT_TRUE(backend.UpdateLogin(form_google_, &changes)); - CheckPasswordChanges(PasswordStoreChangeList(), changes); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) { - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); - } -} - -TEST_F(NativeBackendLibsecretTest, AddDuplicateLogin) { - NativeBackendLibsecret backend(42); - - VerifiedAdd(&backend, form_google_); - - PasswordStoreChangeList expected_changes; - expected_changes.push_back( - PasswordStoreChange(PasswordStoreChange::REMOVE, form_google_)); - form_google_.times_used++; - form_google_.submit_element = UTF8ToUTF16("submit2"); - expected_changes.push_back( - PasswordStoreChange(PasswordStoreChange::ADD, form_google_)); - - PasswordStoreChangeList actual_changes = backend.AddLogin(form_google_); - CheckPasswordChanges(expected_changes, actual_changes); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); -} - -TEST_F(NativeBackendLibsecretTest, AndroidCredentials) { - NativeBackendLibsecret backend(42); - backend.Init(); - - PasswordForm observed_android_form; - observed_android_form.scheme = PasswordForm::Scheme::kHtml; - observed_android_form.signon_realm = - "android://7x7IDboo8u9YKraUsbmVkuf1-@net.rateflix.app/"; - PasswordForm saved_android_form = observed_android_form; - saved_android_form.username_value = base::UTF8ToUTF16("randomusername"); - saved_android_form.password_value = base::UTF8ToUTF16("password"); - saved_android_form.date_created = base::Time::Now(); - - VerifiedAdd(&backend, saved_android_form); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - EXPECT_TRUE(backend.GetAutofillableLogins(&form_list)); - - EXPECT_EQ(1u, form_list.size()); - EXPECT_EQ(saved_android_form, *form_list[0]); -} - -TEST_F(NativeBackendLibsecretTest, RemoveLoginsCreatedBetween) { - NativeBackendLibsecret backend(42); - - base::Time now = base::Time::Now(); - base::Time next_day = now + base::TimeDelta::FromDays(1); - form_google_.date_created = now; - form_isc_.date_created = next_day; - - VerifiedAdd(&backend, form_google_); - VerifiedAdd(&backend, form_isc_); - - PasswordStoreChangeList expected_changes; - expected_changes.emplace_back(PasswordStoreChange::REMOVE, form_google_); - PasswordStoreChangeList changes; - EXPECT_TRUE( - backend.RemoveLoginsCreatedBetween(base::Time(), next_day, &changes)); - CheckPasswordChanges(expected_changes, changes); - - ASSERT_EQ(1u, global_mock_libsecret_items->size()); - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_isc_, - "chrome-42"); - - // Remove form_isc_. - expected_changes.clear(); - expected_changes.emplace_back(PasswordStoreChange::REMOVE, form_isc_); - - EXPECT_TRUE( - backend.RemoveLoginsCreatedBetween(next_day, base::Time(), &changes)); - CheckPasswordChanges(expected_changes, changes); - - EXPECT_TRUE(global_mock_libsecret_items->empty()); -} - -TEST_F(NativeBackendLibsecretTest, DisableAutoSignInForOrigins) { - NativeBackendLibsecret backend(42); - backend.Init(); - form_google_.skip_zero_click = false; - form_facebook_.skip_zero_click = false; - - VerifiedAdd(&backend, form_google_); - VerifiedAdd(&backend, form_facebook_); - - EXPECT_EQ(2u, global_mock_libsecret_items->size()); - for (const auto& item : *global_mock_libsecret_items) - CheckUint32Attribute(item.get(), "should_skip_zero_click", 0); - - // Set the canonical forms to the updated value for the following comparison. - form_google_.skip_zero_click = true; - form_facebook_.skip_zero_click = true; - PasswordStoreChangeList expected_changes; - expected_changes.push_back( - PasswordStoreChange(PasswordStoreChange::UPDATE, form_facebook_)); - - PasswordStoreChangeList changes; - EXPECT_TRUE(backend.DisableAutoSignInForOrigins( - base::Bind(static_cast<bool (*)(const GURL&, const GURL&)>(operator==), - form_facebook_.origin), - &changes)); - CheckPasswordChanges(expected_changes, changes); - - EXPECT_EQ(2u, global_mock_libsecret_items->size()); - CheckStringAttribute((*global_mock_libsecret_items)[0].get(), "origin_url", - form_google_.origin.spec()); - CheckUint32Attribute((*global_mock_libsecret_items)[0].get(), - "should_skip_zero_click", 0); - CheckStringAttribute((*global_mock_libsecret_items)[1].get(), "origin_url", - form_facebook_.origin.spec()); - CheckUint32Attribute((*global_mock_libsecret_items)[1].get(), - "should_skip_zero_click", 1); -} - -TEST_F(NativeBackendLibsecretTest, SomeKeyringAttributesAreMissing) { - // Absent attributes should be filled with default values. - NativeBackendLibsecret backend(42); - - VerifiedAdd(&backend, form_google_); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - // Remove a string attribute. - (*global_mock_libsecret_items)[0]->RemoveAttribute("avatar_url"); - // Remove an integer attribute. - (*global_mock_libsecret_items)[0]->RemoveAttribute("times_used"); - - std::vector<std::unique_ptr<PasswordForm>> form_list; - EXPECT_TRUE(backend.GetAutofillableLogins(&form_list)); - - EXPECT_EQ(1u, form_list.size()); - EXPECT_EQ(GURL(""), form_list[0]->icon_url); - EXPECT_EQ(0, form_list[0]->times_used); -} - -TEST_F(NativeBackendLibsecretTest, ReadDuplicateForms) { - NativeBackendLibsecret backend(42); - - // Add 2 slightly different password forms. - const char unique_string[] = "unique_unique_string"; - const char unique_string_replacement[] = "uniKue_unique_string"; - form_google_.origin = - GURL(std::string("http://www.google.com/") + unique_string); - VerifiedAdd(&backend, form_google_); - form_google_.origin = - GURL(std::string("http://www.google.com/") + unique_string_replacement); - VerifiedAdd(&backend, form_google_); - - // Read the raw value back. Change the |unique_string| to - // |unique_string_replacement| so the forms become unique. - ASSERT_EQ(2u, global_mock_libsecret_items->size()); - gpointer item_value = g_hash_table_lookup( - global_mock_libsecret_items->front()->attributes, "origin_url"); - ASSERT_TRUE(item_value); - char* substr = strstr(static_cast<char*>(item_value), unique_string); - ASSERT_TRUE(substr); - ASSERT_EQ(strlen(unique_string), strlen(unique_string_replacement)); - strncpy(substr, unique_string_replacement, strlen(unique_string)); - - // Now test that GetAutofillableLogins returns only one form. - std::vector<std::unique_ptr<PasswordForm>> form_list; - EXPECT_TRUE(backend.GetAutofillableLogins(&form_list)); - - EXPECT_EQ(1u, form_list.size()); - EXPECT_EQ(form_google_, *form_list[0]); - - EXPECT_EQ(1u, global_mock_libsecret_items->size()); - if (!global_mock_libsecret_items->empty()) { - CheckMockSecretItem((*global_mock_libsecret_items)[0].get(), form_google_, - "chrome-42"); - } -} - -// TODO(mdm): add more basic tests here at some point.
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc index bd13e93f..702478e 100644 --- a/chrome/browser/password_manager/password_store_factory.cc +++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -48,14 +48,6 @@ #elif defined(OS_CHROMEOS) || defined(OS_ANDROID) // Don't do anything. We're going to use the default store. #elif defined(USE_X11) -#include "components/os_crypt/key_storage_util_linux.h" -#if defined(USE_GNOME_KEYRING) -#include "chrome/browser/password_manager/native_backend_gnome_x.h" -#endif -#if defined(USE_LIBSECRET) -#include "chrome/browser/password_manager/native_backend_libsecret.h" -#endif -#include "chrome/browser/password_manager/native_backend_kwallet_x.h" #include "chrome/browser/password_manager/password_store_x.h" #endif @@ -179,96 +171,9 @@ #if defined(OS_WIN) ps = new password_manager::PasswordStoreDefault(std::move(login_db)); #elif defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_MACOSX) - // For now, we use PasswordStoreDefault. We might want to make a native - // backend for PasswordStoreX (see below) in the future though. ps = new password_manager::PasswordStoreDefault(std::move(login_db)); #elif defined(USE_X11) - // On POSIX systems, we try to use the "native" password management system of - // the desktop environment currently running, allowing GNOME Keyring in XFCE. - // (In all cases we fall back on the basic store in case of failure.) - base::nix::DesktopEnvironment desktop_env = GetDesktopEnvironment(); - std::string store_type = - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kPasswordStore); - LinuxBackendUsed used_backend = PLAINTEXT; - - PrefService* prefs = profile->GetPrefs(); - LocalProfileId id = GetLocalProfileId(prefs); - - bool use_preference = base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableEncryptionSelection); - bool use_backend = true; - if (use_preference) { - base::FilePath user_data_dir; - chrome::GetDefaultUserDataDirectory(&user_data_dir); - use_backend = os_crypt::GetBackendUse(user_data_dir); - } - - os_crypt::SelectedLinuxBackend selected_backend = - os_crypt::SelectBackend(store_type, use_backend, desktop_env); - - std::unique_ptr<PasswordStoreX::NativeBackend> backend; - if (selected_backend == os_crypt::SelectedLinuxBackend::KWALLET || - selected_backend == os_crypt::SelectedLinuxBackend::KWALLET5) { - VLOG(1) << "Trying KWallet for password storage."; - base::nix::DesktopEnvironment used_desktop_env = - selected_backend == os_crypt::SelectedLinuxBackend::KWALLET - ? base::nix::DESKTOP_ENVIRONMENT_KDE4 - : base::nix::DESKTOP_ENVIRONMENT_KDE5; - backend.reset(new NativeBackendKWallet(id, used_desktop_env)); - if (backend->Init()) { - VLOG(1) << "Using KWallet for password storage."; - used_backend = KWALLET; - } else { - backend.reset(); - } - } else if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY || - selected_backend == - os_crypt::SelectedLinuxBackend::GNOME_KEYRING || - selected_backend == - os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) { -#if defined(USE_LIBSECRET) - if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY || - selected_backend == os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) { - VLOG(1) << "Trying libsecret for password storage."; - backend.reset(new NativeBackendLibsecret(id)); - if (backend->Init()) { - VLOG(1) << "Using libsecret keyring for password storage."; - used_backend = LIBSECRET; - } else { - backend.reset(); - } - } -#endif // defined(USE_LIBSECRET) -#if defined(USE_GNOME_KEYRING) - if (!backend.get() && - (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY || - selected_backend == os_crypt::SelectedLinuxBackend::GNOME_KEYRING)) { - VLOG(1) << "Trying GNOME keyring for password storage."; - backend.reset(new NativeBackendGnome(id)); - if (backend->Init()) { - VLOG(1) << "Using GNOME keyring for password storage."; - used_backend = GNOME_KEYRING; - } else { - backend.reset(); - } - } -#endif // defined(USE_GNOME_KEYRING) - } - - if (!backend.get()) { - LOG(WARNING) << "Using basic (unencrypted) store for password storage. " - "See " - "https://chromium.googlesource.com/chromium/src/+/master/docs/linux_password_storage.md" - " for more information about password storage options."; - } - - ps = new PasswordStoreX( - std::move(login_db), - profile->GetPath().Append(password_manager::kLoginDataFileName), - profile->GetPath().Append(password_manager::kSecondLoginDataFileName), - std::move(backend), prefs); - RecordBackendStatistics(desktop_env, store_type, used_backend); + ps = new PasswordStoreX(std::move(login_db), profile->GetPrefs()); #elif defined(USE_OZONE) ps = new password_manager::PasswordStoreDefault(std::move(login_db)); #else
diff --git a/chrome/browser/password_manager/password_store_x.cc b/chrome/browser/password_manager/password_store_x.cc index 6b8ea98..1aab9a6 100644 --- a/chrome/browser/password_manager/password_store_x.cc +++ b/chrome/browser/password_manager/password_store_x.cc
@@ -32,48 +32,6 @@ using password_manager::PasswordStoreDefault; namespace { - -bool AddLoginToBackend( - const std::unique_ptr<PasswordStoreX::NativeBackend>& backend, - const PasswordForm& form, - PasswordStoreChangeList* changes) { - *changes = backend->AddLogin(form); - return (!changes->empty() && - changes->back().type() == PasswordStoreChange::ADD); -} - -bool RemoveLoginsByURLAndTimeFromBackend( - PasswordStoreX::NativeBackend* backend, - const base::Callback<bool(const GURL&)>& url_filter, - base::Time delete_begin, - base::Time delete_end, - PasswordStoreChangeList* changes) { - std::vector<std::unique_ptr<PasswordForm>> forms; - if (!backend->GetAllLogins(&forms)) - return false; - - for (const auto& form : forms) { - if (url_filter.Run(form->origin) && form->date_created >= delete_begin && - (delete_end.is_null() || form->date_created < delete_end) && - !backend->RemoveLogin(*form, changes)) - return false; - } - - return true; -} - -// Disables encryption on |login_db|, if the migration to encryption has not -// been performed yet. -std::unique_ptr<password_manager::LoginDatabase> DisableEncryption( - std::unique_ptr<password_manager::LoginDatabase> login_db, - PrefService* prefs) { - if (prefs->GetInteger(password_manager::prefs::kMigrationToLoginDBStep) != - PasswordStoreX::LOGIN_DB_REPLACED) { - login_db->disable_encryption(); - } - return login_db; -} - // Returns the password_manager::metrics_util::LinuxBackendMigrationStatus // equivalent for |step|. password_manager::metrics_util::LinuxBackendMigrationStatus StepForMetrics( @@ -109,47 +67,12 @@ return LinuxBackendMigrationStatus::kNotAttempted; } -// Remove |forms| from |backend|. If |forms| is empty, |backend| will be cleared -// entirely. This must be called on |runner|, which has to be the same as -// |backend|'s. -void ClearNativeBackend(scoped_refptr<base::SequencedTaskRunner> runner, - std::unique_ptr<PasswordStoreX::NativeBackend> backend, - std::vector<std::unique_ptr<PasswordForm>> forms) { - if (forms.empty()) { - if (!backend->GetAllLogins(&forms)) - return; - } - - if (!forms.empty()) { - PasswordStoreChangeList changes; - backend->RemoveLogin(*forms.back(), &changes); - forms.pop_back(); - if (!forms.empty()) { - // We yield on the task runner between deletes, because this is a - // background cleanup which has to happen on the native backend's - // preferred thread, and in the case of gnome-keyring it's the main - // thread. - runner->PostTask(FROM_HERE, - base::BindOnce(&ClearNativeBackend, runner, - std::move(backend), std::move(forms))); - } - } -} - } // namespace PasswordStoreX::PasswordStoreX( std::unique_ptr<password_manager::LoginDatabase> login_db, - base::FilePath login_db_file, - base::FilePath encrypted_login_db_file, - std::unique_ptr<NativeBackend> backend, PrefService* prefs) - : PasswordStoreDefault(DisableEncryption(std::move(login_db), prefs)), - backend_(std::move(backend)), - login_db_file_(std::move(login_db_file)), - encrypted_login_db_file_(std::move(encrypted_login_db_file)), - migration_checked_(false), - allow_fallback_(false) { + : PasswordStoreDefault(std::move(login_db)), migration_checked_(false) { migration_step_pref_.Init(password_manager::prefs::kMigrationToLoginDBStep, prefs); migration_to_login_db_step_ = @@ -158,57 +81,33 @@ base::UmaHistogramEnumeration( "PasswordManager.LinuxBackendMigration.Adoption", StepForMetrics(migration_to_login_db_step_)); - - // No |backend_| means serving from PasswordStoreDefault. - if (migration_to_login_db_step_ == LOGIN_DB_REPLACED) - backend_.reset(); } PasswordStoreX::~PasswordStoreX() {} scoped_refptr<base::SequencedTaskRunner> PasswordStoreX::CreateBackgroundTaskRunner() const { - scoped_refptr<base::SequencedTaskRunner> result = - backend_ ? backend_->GetBackgroundTaskRunner() : nullptr; - return result ? result : PasswordStoreDefault::CreateBackgroundTaskRunner(); + return PasswordStoreDefault::CreateBackgroundTaskRunner(); } PasswordStoreChangeList PasswordStoreX::AddLoginImpl( const PasswordForm& form, password_manager::AddLoginError* error) { CheckMigration(); - PasswordStoreChangeList changes; - if (use_native_backend() && AddLoginToBackend(backend_, form, &changes)) { - allow_fallback_ = false; - } else if (allow_default_store()) { - changes = PasswordStoreDefault::AddLoginImpl(form, error); - } - return changes; + return PasswordStoreDefault::AddLoginImpl(form, error); } PasswordStoreChangeList PasswordStoreX::UpdateLoginImpl( const PasswordForm& form, password_manager::UpdateLoginError* error) { CheckMigration(); - PasswordStoreChangeList changes; - if (use_native_backend() && backend_->UpdateLogin(form, &changes)) { - allow_fallback_ = false; - } else if (allow_default_store()) { - changes = PasswordStoreDefault::UpdateLoginImpl(form, error); - } - return changes; + return PasswordStoreDefault::UpdateLoginImpl(form, error); } PasswordStoreChangeList PasswordStoreX::RemoveLoginImpl( const PasswordForm& form) { CheckMigration(); - PasswordStoreChangeList changes; - if (use_native_backend() && backend_->RemoveLogin(form, &changes)) { - allow_fallback_ = false; - } else if (allow_default_store()) { - changes = PasswordStoreDefault::RemoveLoginImpl(form); - } - return changes; + return PasswordStoreDefault::RemoveLoginImpl(form); } PasswordStoreChangeList PasswordStoreX::RemoveLoginsByURLAndTimeImpl( @@ -216,303 +115,63 @@ base::Time delete_begin, base::Time delete_end) { CheckMigration(); - - PasswordStoreChangeList changes; - if (use_native_backend() && - RemoveLoginsByURLAndTimeFromBackend(backend_.get(), url_filter, - delete_begin, delete_end, &changes)) { - allow_fallback_ = false; - } else if (allow_default_store()) { - changes = PasswordStoreDefault::RemoveLoginsByURLAndTimeImpl( - url_filter, delete_begin, delete_end); - } - - return changes; + return PasswordStoreDefault::RemoveLoginsByURLAndTimeImpl( + url_filter, delete_begin, delete_end); } PasswordStoreChangeList PasswordStoreX::RemoveLoginsCreatedBetweenImpl( base::Time delete_begin, base::Time delete_end) { CheckMigration(); - PasswordStoreChangeList changes; - if (use_native_backend() && - backend_->RemoveLoginsCreatedBetween( - delete_begin, delete_end, &changes)) { - allow_fallback_ = false; - } else if (allow_default_store()) { - changes = PasswordStoreDefault::RemoveLoginsCreatedBetweenImpl(delete_begin, - delete_end); - } - return changes; + return PasswordStoreDefault::RemoveLoginsCreatedBetweenImpl(delete_begin, + delete_end); } PasswordStoreChangeList PasswordStoreX::DisableAutoSignInForOriginsImpl( const base::Callback<bool(const GURL&)>& origin_filter) { CheckMigration(); - PasswordStoreChangeList changes; - if (use_native_backend() && - backend_->DisableAutoSignInForOrigins(origin_filter, &changes)) { - allow_fallback_ = false; - } else if (allow_default_store()) { - changes = - PasswordStoreDefault::DisableAutoSignInForOriginsImpl(origin_filter); - } - return changes; + return PasswordStoreDefault::DisableAutoSignInForOriginsImpl(origin_filter); } -namespace { - -// Sorts |list| by origin, like the ORDER BY clause in login_database.cc. -void SortLoginsByOrigin(std::vector<std::unique_ptr<PasswordForm>>* list) { - std::sort(list->begin(), list->end(), - [](const std::unique_ptr<PasswordForm>& a, - const std::unique_ptr<PasswordForm>& b) { - return a->origin < b->origin; - }); -} - -} // anonymous namespace - std::vector<std::unique_ptr<PasswordForm>> PasswordStoreX::FillMatchingLogins( const FormDigest& form) { CheckMigration(); - std::vector<std::unique_ptr<PasswordForm>> matched_forms; - if (use_native_backend() && backend_->GetLogins(form, &matched_forms)) { - SortLoginsByOrigin(&matched_forms); - // The native backend may succeed and return no data even while locked, if - // the query did not match anything stored. So we continue to allow fallback - // until we perform a write operation, or until a read returns actual data. - if (!matched_forms.empty()) - allow_fallback_ = false; - return matched_forms; - } - if (allow_default_store()) return PasswordStoreDefault::FillMatchingLogins(form); - return std::vector<std::unique_ptr<PasswordForm>>(); } bool PasswordStoreX::FillAutofillableLogins( std::vector<std::unique_ptr<PasswordForm>>* forms) { CheckMigration(); - if (use_native_backend() && backend_->GetAutofillableLogins(forms)) { - SortLoginsByOrigin(forms); - // See GetLoginsImpl() for why we disallow fallback conditionally here. - if (!forms->empty()) - allow_fallback_ = false; - return true; - } - if (allow_default_store()) return PasswordStoreDefault::FillAutofillableLogins(forms); - return false; } bool PasswordStoreX::FillBlacklistLogins( std::vector<std::unique_ptr<PasswordForm>>* forms) { CheckMigration(); - if (use_native_backend() && backend_->GetBlacklistLogins(forms)) { - // See GetLoginsImpl() for why we disallow fallback conditionally here. - SortLoginsByOrigin(forms); - if (!forms->empty()) - allow_fallback_ = false; - return true; - } - if (allow_default_store()) return PasswordStoreDefault::FillBlacklistLogins(forms); - return false; } void PasswordStoreX::CheckMigration() { DCHECK(background_task_runner()->RunsTasksInCurrentSequence()); - if (migration_checked_ || !backend_.get()) + if (migration_checked_) return; + migration_checked_ = true; - DCHECK_NE(migration_to_login_db_step_, LOGIN_DB_REPLACED); - - base::Time migration_to_native_started = base::Time::Now(); - - ssize_t migrated = MigrateToNativeBackend(); - if (migrated > 0) { - VLOG(1) << "Migrated " << migrated << " passwords to native store."; - } else if (migrated == 0) { - // As long as we are able to migrate some passwords, we know the native - // store is working. But if there is nothing to migrate, the "migration" - // can succeed even when the native store would fail. In this case we - // allow a later fallback to the default store. Once any later operation - // succeeds on the native store, we will no longer allow fallback. - allow_fallback_ = true; - } else { - LOG(WARNING) << "Native password store migration failed! " - << "Falling back on default (unencrypted) store."; - backend_.reset(); - } - - base::UmaHistogramLongTimes( - "PasswordManager.LinuxBackendMigration.TimeIntoNative", - base::Time::Now() - migration_to_native_started); - - if (base::FeatureList::IsEnabled( - password_manager::features::kMigrateLinuxToLoginDB)) { - // Copy passwords from the backend into the login database, using - // encryption. - if (backend_) { - UpdateMigrationToLoginDBStep(STARTED); - MigrateToEncryptedLoginDB(); - } else { - UpdateMigrationToLoginDBStep(POSTPONED); - } - - base::UmaHistogramEnumeration( - "PasswordManager.LinuxBackendMigration.AttemptResult", - StepForMetrics(migration_to_login_db_step_)); - } -} - -bool PasswordStoreX::allow_default_store() { - if (allow_fallback_) { - LOG(WARNING) << "Native password store failed! " << - "Falling back on default (unencrypted) store."; - backend_.reset(); - // Don't warn again. We'll use the default store because backend_ is NULL. - allow_fallback_ = false; - } - return !backend_.get(); -} - -ssize_t PasswordStoreX::MigrateToNativeBackend() { - DCHECK(backend_.get()); - std::vector<std::unique_ptr<PasswordForm>> forms; - std::vector<std::unique_ptr<PasswordForm>> blacklist_forms; - bool ok = PasswordStoreDefault::FillAutofillableLogins(&forms) && - PasswordStoreDefault::FillBlacklistLogins(&blacklist_forms); - const size_t autofillable_forms_count = forms.size(); - forms.resize(autofillable_forms_count + blacklist_forms.size()); - std::move(blacklist_forms.begin(), blacklist_forms.end(), - forms.begin() + autofillable_forms_count); - if (ok) { - // We add all the passwords (and blacklist entries) to the native backend - // before attempting to remove any from the login database, to make sure we - // don't somehow end up with some of the passwords in one store and some in - // another. We'll always have at least one intact store this way. - for (size_t i = 0; i < forms.size(); ++i) { - PasswordStoreChangeList changes; - if (!AddLoginToBackend(backend_, *forms[i], &changes)) { - ok = false; - break; - } - } - if (ok) { - for (size_t i = 0; i < forms.size(); ++i) { - // If even one of these calls to RemoveLoginImpl() succeeds, then we - // should prefer the native backend to the now-incomplete login - // database. Thus we want to return a success status even in the case - // where some fail. The only real problem with this is that we might - // leave passwords in the login database and never come back to clean - // them out if any of these calls do fail. - PasswordStoreDefault::RemoveLoginImpl(*forms[i]); - } - // Finally, delete the database file itself. We remove the passwords from - // it before deleting the file just in case there is some problem deleting - // the file (e.g. directory is not writable, but file is), which would - // otherwise cause passwords to re-migrate next (or maybe every) time. - DeleteAndRecreateDatabaseFile(); - } - } - ssize_t result = ok ? forms.size() : -1; - return result; -} - -void PasswordStoreX::MigrateToEncryptedLoginDB() { - base::Time migration_to_encrypted_started = base::Time::Now(); - - // Initialise the temporary database. - auto encrypted_login_db = std::make_unique<password_manager::LoginDatabase>( - encrypted_login_db_file_); - if (!encrypted_login_db->Init()) { - VLOG(1) << "Failed to init the encrypted database file. Migration " - "aborted."; - UpdateMigrationToLoginDBStep(FAILED_INIT_ENCRYPTED); - return; // Serve from the native backend. - } - - // Copy everything from the backend to the temporary database. - VLOG(1) << "Migrating all passwords to the encrypted database. Last status: " - << migration_to_login_db_step_; - UpdateMigrationToLoginDBStep(CopyBackendToLoginDB(encrypted_login_db.get())); - if (migration_to_login_db_step_ != COPIED_ALL) { - VLOG(1) << "Migration to encryption failed."; - base::DeleteFile(encrypted_login_db_file_, false); + if (migration_to_login_db_step_ == LOGIN_DB_REPLACED) { return; } - - base::UmaHistogramLongTimes( - "PasswordManager.LinuxBackendMigration.TimeIntoEncrypted", - base::Time::Now() - migration_to_encrypted_started); - - // Dispose of the databases, so that we release the databases' locks. - PasswordStoreDefault::SetLoginDB(nullptr); - encrypted_login_db.reset(); - // Move the new database onto the old. - if (!base::Move(encrypted_login_db_file_, login_db_file_)) { - LOG(ERROR) << "Could not replace login database."; - UpdateMigrationToLoginDBStep(FAILED_REPLACE); - base::DeleteFile(encrypted_login_db_file_, false); - return; // Serve from the native backend. + // If the db is empty, there are no records to migrate, and we then can call + // it a completed migration. + if (login_db()->IsEmpty()) { + UpdateMigrationToLoginDBStep(LOGIN_DB_REPLACED); + return; } - UpdateMigrationToLoginDBStep(LOGIN_DB_REPLACED); - - auto login_db = - std::make_unique<password_manager::LoginDatabase>(login_db_file_); - if (login_db->Init()) { - PasswordStoreDefault::SetLoginDB(std::move(login_db)); - } else { - // The password manager is disabled because PasswordStoreDefault is left - // with no LoginDatabase and |backend_| will be disposed of. - LOG(ERROR) << "Could not initialise database after migration. Password " - "Manager is disabled."; - } - - // Cleanup the native backend on the background, while we serve from - // PasswordStoreDefault. PasswordStoreX will use the PasswordStoreDefault - // behaviour, because we move |backend_|. - auto task_runner = CreateBackgroundTaskRunner(); - task_runner->PostTask( - FROM_HERE, - base::BindOnce(&ClearNativeBackend, task_runner, std::move(backend_), - std::vector<std::unique_ptr<autofill::PasswordForm>>())); -} - -PasswordStoreX::MigrationToLoginDBStep PasswordStoreX::CopyBackendToLoginDB( - password_manager::LoginDatabase* login_db) { - DCHECK(backend_); - DCHECK(login_db); - - if (!login_db->DeleteAndRecreateDatabaseFile()) { - LOG(ERROR) << "Failed to create the encrypted login database file"; - return FAILED_RECREATE_ENCRYPTED; - } - - std::vector<std::unique_ptr<PasswordForm>> forms; - if (!backend_->GetAllLogins(&forms)) - return FAILED_ACCESS_NATIVE; - - for (auto& form : forms) { - PasswordStoreChangeList changes = login_db->AddLogin(*form); - if (changes.empty() || changes.back().type() != PasswordStoreChange::ADD) { - // AddLogin() would fail if the form has empty |origin|, empty - // |signon_realm|, is a duplicate blacklisting or there was an IO error. - // All of these cases are not supported and can be dropped. - if (form->signon_realm.empty() || form->origin.is_empty() || - form->blacklisted_by_user) { - LOG(WARNING) << "Dropped a credential during migration away from the " - "native backend"; - } else { - return FAILED_WRITE_TO_ENCRYPTED; - } - } - } - - return COPIED_ALL; + // The migration hasn't completed yes. The records in the database aren't + // encrypted, so we must disable the encryption. + // TODO(crbug/950267): Handle users who have unencrypted entries in the + // database. + login_db()->disable_encryption(); } void PasswordStoreX::UpdateMigrationToLoginDBStep(MigrationToLoginDBStep step) { @@ -534,36 +193,18 @@ password_manager::FormRetrievalResult PasswordStoreX::ReadAllLogins( password_manager::PrimaryKeyToFormMap* key_to_form_map) { - // This method is called from the PasswordSyncBridge which supports only - // PasswordStoreDefault. Therefore, on Linux, it should be called only if the - // client is using LogainDatabase instead of the NativeBackend's. It's the - // responsibility of the caller to guarantee that. - if (use_native_backend()) { - NOTREACHED(); - } + CheckMigration(); return PasswordStoreDefault::ReadAllLogins(key_to_form_map); } PasswordStoreChangeList PasswordStoreX::RemoveLoginByPrimaryKeySync( int primary_key) { - // This method is called from the PasswordSyncBridge which supports only - // PasswordStoreDefault. Therefore, on Linux, it should be called only if the - // client is using LogainDatabase instead of the NativeBackend's. It's the - // responsibility of the caller to guarantee that. - if (use_native_backend()) { - NOTREACHED(); - } + CheckMigration(); return PasswordStoreDefault::RemoveLoginByPrimaryKeySync(primary_key); } password_manager::PasswordStoreSync::MetadataStore* PasswordStoreX::GetMetadataStore() { - // This method is called from the PasswordSyncBridge which supports only - // PasswordStoreDefault. Therefore, on Linux, it should be called only if the - // client is using LogainDatabase instead of the NativeBackend's. It's the - // responsibility of the caller to guarantee that. - if (use_native_backend()) { - NOTREACHED(); - } + CheckMigration(); return PasswordStoreDefault::GetMetadataStore(); }
diff --git a/chrome/browser/password_manager/password_store_x.h b/chrome/browser/password_manager/password_store_x.h index f2e1028..7f59e36 100644 --- a/chrome/browser/password_manager/password_store_x.h +++ b/chrome/browser/password_manager/password_store_x.h
@@ -21,13 +21,10 @@ class LoginDatabase; } -// PasswordStoreX is used on Linux and other non-Windows, non-Mac OS X -// operating systems. It uses a "native backend" to actually store the password -// data when such a backend is available, and otherwise falls back to using the -// login database like PasswordStoreDefault. It also handles automatically -// migrating password data to a native backend from the login database. -// -// There are currently native backends for GNOME Keyring and KWallet. +// PasswordStoreX is used on Linux and other non-Windows, non-Mac OS X operating +// systems. It is used as a proxy for the PasswordStoreDefault that basically +// takes care of migrating the passwords of the users to login database. Once +// all users are migrated we should delete this class. class PasswordStoreX : public password_manager::PasswordStoreDefault { public: // The state of the migration from native backends and an unencrypted loginDB @@ -61,73 +58,7 @@ FAILED_WRITE_TO_ENCRYPTED, }; - // NativeBackends more or less implement the PaswordStore interface, but - // with return values rather than implicit consumer notification. - class NativeBackend { - public: - virtual ~NativeBackend() {} - - virtual bool Init() = 0; - - virtual password_manager::PasswordStoreChangeList AddLogin( - const autofill::PasswordForm& form) = 0; - // Updates |form| and appends the changes to |changes|. |changes| shouldn't - // be null. Returns false iff the operation failed due to a system backend - // error. - virtual bool UpdateLogin( - const autofill::PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) = 0; - // Removes |form| and appends the changes to |changes|. |changes| shouldn't - // be null. Returns false iff the operation failed due to a system backend - // error. - virtual bool RemoveLogin( - const autofill::PasswordForm& form, - password_manager::PasswordStoreChangeList* changes) = 0; - - // Removes all logins created/synced from |delete_begin| onwards (inclusive) - // and before |delete_end|. You may use a null Time value to do an unbounded - // delete in either direction. - virtual bool RemoveLoginsCreatedBetween( - base::Time delete_begin, - base::Time delete_end, - password_manager::PasswordStoreChangeList* changes) = 0; - - // Sets the 'skip_zero_click' flag to 'true' for all logins in the database - // that match |origin_filter|. - virtual bool DisableAutoSignInForOrigins( - const base::Callback<bool(const GURL&)>& origin_filter, - password_manager::PasswordStoreChangeList* changes) = 0; - - // The three methods below overwrite |forms| with all stored credentials - // matching |form|, all stored non-blacklisted credentials, and all stored - // blacklisted credentials, respectively. On success, they return true. - virtual bool GetLogins(const FormDigest& form, - std::vector<std::unique_ptr<autofill::PasswordForm>>* - forms) WARN_UNUSED_RESULT = 0; - virtual bool GetAutofillableLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) - WARN_UNUSED_RESULT = 0; - virtual bool GetBlacklistLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) - WARN_UNUSED_RESULT = 0; - virtual bool GetAllLogins( - std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) - WARN_UNUSED_RESULT = 0; - - // Returns the background thread in case the backend uses one, or null. - virtual scoped_refptr<base::SequencedTaskRunner> - GetBackgroundTaskRunner() = 0; - }; - - // |backend| may be NULL in which case this PasswordStoreX will act the same - // as PasswordStoreDefault. |login_db| is the default location and does not - // use encryption. |login_db_file| is the location of |login_db|. - // |encrypted_login_db_file| is a separate file and is used for the migration - // to encryption. PasswordStoreX(std::unique_ptr<password_manager::LoginDatabase> login_db, - base::FilePath login_db_file, - base::FilePath encrypted_login_db_file, - std::unique_ptr<NativeBackend> backend, PrefService* prefs); // RefcountedKeyedService: @@ -143,8 +74,6 @@ override; private: - friend class PasswordStoreXTest; - ~PasswordStoreX() override; // Implements PasswordStore interface. @@ -174,38 +103,9 @@ bool FillBlacklistLogins( std::vector<std::unique_ptr<autofill::PasswordForm>>* forms) override; - // Check to see whether migration from the unencrypted loginDB is necessary, - // and perform it if so. Additionally, if the migration to encryption is - // enabled, then the passwords will also be copied into the encrypted login - // database and PasswordStoreX will serve from there. If this migration was - // completed in a previous run, CheckMigration will simply enable serving from - // the encrypted login database. + // Checks whether the login database is encrypted or not. void CheckMigration(); - // Return true if we should try using the native backend. - bool use_native_backend() { return !!backend_.get(); } - - // Return true if we can fall back on the default store, warning the first - // time we call it when falling back is necessary. See |allow_fallback_|. - bool allow_default_store(); - - // Synchronously migrates all the passwords stored in the login database - // (PasswordStoreDefault) to the native backend. If successful, the login - // database will be left with no stored passwords, and the number of passwords - // migrated will be returned. (This might be 0 if migration was not - // necessary.) Returns < 0 on failure. - ssize_t MigrateToNativeBackend(); - - // Moves the passwords from the backend to a temporary login database, using - // encryption, and then moves them over to the standard location. This - // operation can take a significant amount of time. - void MigrateToEncryptedLoginDB(); - - // Synchronously copies everything from the |backend_| to |login_db|. Returns - // COPIED_ALL on success and FAILED on error. - MigrationToLoginDBStep CopyBackendToLoginDB( - password_manager::LoginDatabase* login_db); - // Update |migration_to_login_db_step_| and |migration_step_pref_|. void UpdateMigrationToLoginDBStep(MigrationToLoginDBStep step); @@ -213,19 +113,8 @@ // thread. void UpdateMigrationPref(MigrationToLoginDBStep step); - // The native backend in use, or NULL if none. - std::unique_ptr<NativeBackend> backend_; - // The location of the PasswordStoreDefault's database. - const base::FilePath login_db_file_; - // A second login database, which will hold encrypted values during migration. - const base::FilePath encrypted_login_db_file_; // Whether we have already attempted migration to the native store. bool migration_checked_; - // Whether we should allow falling back to the default store. If there is - // nothing to migrate, then the first attempt to use the native store will - // be the first time we try to use it and we should allow falling back. If - // we have migrated successfully, then we do not allow falling back. - bool allow_fallback_; // Tracks the last completed step in the migration from the native backends to // LoginDB. IntegerPrefMember migration_step_pref_;
diff --git a/chrome/browser/password_manager/password_store_x_unittest.cc b/chrome/browser/password_manager/password_store_x_unittest.cc index 2ed7679..3383d9cd 100644 --- a/chrome/browser/password_manager/password_store_x_unittest.cc +++ b/chrome/browser/password_manager/password_store_x_unittest.cc
@@ -37,8 +37,10 @@ #include "testing/gtest/include/gtest/gtest.h" using autofill::PasswordForm; +using password_manager::FormRetrievalResult; using password_manager::PasswordStoreChange; using password_manager::PasswordStoreChangeList; +using password_manager::PrimaryKeyToFormMap; using password_manager::UnorderedPasswordFormElementsAre; using password_manager::metrics_util::LinuxBackendMigrationStatus; using testing::ElementsAreArray; @@ -48,6 +50,9 @@ namespace { +const char kPassword[] = "password_value"; +const char kUsername[] = "username_value"; +const char kAnotherUsername[] = "another_username_value"; class MockPasswordStoreConsumer : public password_manager::PasswordStoreConsumer { public: @@ -61,701 +66,73 @@ } }; -class FailingBackend : public PasswordStoreX::NativeBackend { - public: - bool Init() override { return true; } - - PasswordStoreChangeList AddLogin(const PasswordForm& form) override { - return PasswordStoreChangeList(); - } - bool UpdateLogin(const PasswordForm& form, - PasswordStoreChangeList* changes) override { - return false; - } - bool RemoveLogin(const PasswordForm& form, - PasswordStoreChangeList* changes) override { - return false; - } - - bool RemoveLoginsCreatedBetween( - base::Time delete_begin, - base::Time delete_end, - password_manager::PasswordStoreChangeList* changes) override { - return false; - } - - bool DisableAutoSignInForOrigins( - const base::Callback<bool(const GURL&)>& origin_filter, - password_manager::PasswordStoreChangeList* changes) override { - return false; - } - - // Use this as a landmine to check whether results of failed Get*Logins calls - // get ignored. - static std::vector<std::unique_ptr<PasswordForm>> CreateTrashForms() { - std::vector<std::unique_ptr<PasswordForm>> forms; - PasswordForm trash; - trash.username_element = base::ASCIIToUTF16("trash u. element"); - trash.username_value = base::ASCIIToUTF16("trash u. value"); - trash.password_element = base::ASCIIToUTF16("trash p. element"); - trash.password_value = base::ASCIIToUTF16("trash p. value"); - for (size_t i = 0; i < 3; ++i) { - trash.origin = GURL(base::StringPrintf("http://trash%zu.com", i)); - forms.push_back(std::make_unique<PasswordForm>(trash)); - } - return forms; - } - - bool GetLogins(const PasswordStore::FormDigest& form, - std::vector<std::unique_ptr<PasswordForm>>* forms) override { - *forms = CreateTrashForms(); - return false; - } - - bool GetAutofillableLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) override { - *forms = CreateTrashForms(); - return false; - } - - bool GetBlacklistLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) override { - *forms = CreateTrashForms(); - return false; - } - - bool GetAllLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) override { - *forms = CreateTrashForms(); - return false; - } - - scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner() override { - return nullptr; - } -}; - -class MockBackend : public PasswordStoreX::NativeBackend { - public: - ~MockBackend() override { - if (save_on_destruct_) { - *save_on_destruct_ = std::move(all_forms_); - } - } - - bool Init() override { return true; } - - PasswordStoreChangeList AddLogin(const PasswordForm& form) override { - all_forms_.push_back(form); - PasswordStoreChange change(PasswordStoreChange::ADD, form); - return PasswordStoreChangeList(1, change); - } - - bool UpdateLogin(const PasswordForm& form, - PasswordStoreChangeList* changes) override { - for (size_t i = 0; i < all_forms_.size(); ++i) { - if (ArePasswordFormUniqueKeysEqual(all_forms_[i], form)) { - all_forms_[i] = form; - changes->push_back( - PasswordStoreChange(PasswordStoreChange::UPDATE, form)); - } - } - return true; - } - - bool RemoveLogin(const PasswordForm& form, - PasswordStoreChangeList* changes) override { - for (size_t i = 0; i < all_forms_.size(); ++i) { - if (ArePasswordFormUniqueKeysEqual(all_forms_[i], form)) { - changes->push_back( - PasswordStoreChange(PasswordStoreChange::REMOVE, form)); - erase(i--); - } - } - return true; - } - - bool RemoveLoginsCreatedBetween( - base::Time delete_begin, - base::Time delete_end, - password_manager::PasswordStoreChangeList* changes) override { - for (size_t i = 0; i < all_forms_.size(); ++i) { - if (delete_begin <= all_forms_[i].date_created && - (delete_end.is_null() || all_forms_[i].date_created < delete_end)) - erase(i--); - } - return true; - } - - bool DisableAutoSignInForOrigins( - const base::Callback<bool(const GURL&)>& origin_filter, - password_manager::PasswordStoreChangeList* changes) override { - return true; - } - - bool GetLogins(const PasswordStore::FormDigest& form, - std::vector<std::unique_ptr<PasswordForm>>* forms) override { - for (size_t i = 0; i < all_forms_.size(); ++i) - if (all_forms_[i].signon_realm == form.signon_realm) - forms->push_back(std::make_unique<PasswordForm>(all_forms_[i])); - return true; - } - - bool GetAutofillableLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) override { - for (size_t i = 0; i < all_forms_.size(); ++i) - if (!all_forms_[i].blacklisted_by_user) - forms->push_back(std::make_unique<PasswordForm>(all_forms_[i])); - return true; - } - - bool GetBlacklistLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) override { - for (size_t i = 0; i < all_forms_.size(); ++i) - if (all_forms_[i].blacklisted_by_user) - forms->push_back(std::make_unique<PasswordForm>(all_forms_[i])); - return true; - } - - bool GetAllLogins( - std::vector<std::unique_ptr<PasswordForm>>* forms) override { - for (size_t i = 0; i < all_forms_.size(); ++i) - forms->push_back(std::make_unique<PasswordForm>(all_forms_[i])); - return true; - } - - scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner() override { - return nullptr; - } - - void SaveFormsOnDestruct(std::vector<PasswordForm>* forms) { - save_on_destruct_ = forms; - } - - private: - void erase(size_t index) { - if (index < all_forms_.size() - 1) - all_forms_[index] = all_forms_.back(); - all_forms_.pop_back(); - } - - std::vector<PasswordForm>* save_on_destruct_ = nullptr; - std::vector<PasswordForm> all_forms_; -}; - -class MockLoginDatabaseReturn { - public: - MOCK_METHOD1(OnLoginDatabaseQueryDone, - void(const std::vector<std::unique_ptr<PasswordForm>>&)); -}; - -void LoginDatabaseQueryCallback(password_manager::LoginDatabase* login_db, - MockLoginDatabaseReturn* mock_return) { - password_manager::PrimaryKeyToFormMap key_to_form_map; - EXPECT_EQ(password_manager::FormRetrievalResult::kSuccess, - login_db->GetAllLogins(&key_to_form_map)); - std::vector<std::unique_ptr<PasswordForm>> results; - results.reserve(key_to_form_map.size()); - for (auto& key_to_form : key_to_form_map) - results.push_back(std::move(key_to_form.second)); - mock_return->OnLoginDatabaseQueryDone(results); -} - -// Generate |count| expected logins, either auto-fillable or blacklisted. -void InitExpectedForms(bool autofillable, - size_t count, - std::vector<std::unique_ptr<PasswordForm>>* forms) { - const char* domain = autofillable ? "example" : "blacklisted"; - for (size_t i = 0; i < count; ++i) { - std::string realm = base::StringPrintf("http://%zu.%s.com", i, domain); - std::string origin = - base::StringPrintf("http://%zu.%s.com/origin", i, domain); - std::string action = - base::StringPrintf("http://%zu.%s.com/action", i, domain); - password_manager::PasswordFormData data = { - PasswordForm::Scheme::kHtml, - realm.c_str(), - origin.c_str(), - action.c_str(), - L"submit_element", - L"username_element", - L"password_element", - autofillable ? L"username_value" : nullptr, - autofillable ? L"password_value" : nullptr, - autofillable, - static_cast<double>(i + 1)}; - forms->push_back(FillPasswordFormWithData(data)); - } -} - -PasswordStoreChangeList AddChangeForForm(const PasswordForm& form) { - return PasswordStoreChangeList( - 1, PasswordStoreChange(PasswordStoreChange::ADD, form)); -} - -enum BackendType { NO_BACKEND, FAILING_BACKEND, WORKING_BACKEND }; - -std::unique_ptr<PasswordStoreX::NativeBackend> GetBackend( - BackendType backend_type) { - switch (backend_type) { - case FAILING_BACKEND: - return std::make_unique<FailingBackend>(); - case WORKING_BACKEND: - return std::make_unique<MockBackend>(); - default: - return std::unique_ptr<PasswordStoreX::NativeBackend>(); - } -} - -class PasswordStoreXTestDelegate { - public: - PasswordStoreX* store() { return store_.get(); } - - void FinishAsyncProcessing(); - - protected: - explicit PasswordStoreXTestDelegate(BackendType backend_type); - ~PasswordStoreXTestDelegate(); - - private: - void SetupTempDir(); - - base::FilePath test_login_db_file_path() const; - base::FilePath test_encrypted_login_db_file_path() const; - - base::test::ScopedTaskEnvironment task_environment_; - base::ScopedTempDir temp_dir_; - BackendType backend_type_; - scoped_refptr<PasswordStoreX> store_; - TestingPrefServiceSimple fake_pref_service; - - DISALLOW_COPY_AND_ASSIGN(PasswordStoreXTestDelegate); -}; - -PasswordStoreXTestDelegate::PasswordStoreXTestDelegate(BackendType backend_type) - : backend_type_(backend_type) { - SetupTempDir(); - auto login_db = std::make_unique<password_manager::LoginDatabase>( - test_login_db_file_path()); - fake_pref_service.registry()->RegisterIntegerPref( - password_manager::prefs::kMigrationToLoginDBStep, - PasswordStoreX::NOT_ATTEMPTED); - store_ = new PasswordStoreX(std::move(login_db), test_login_db_file_path(), - test_encrypted_login_db_file_path(), - GetBackend(backend_type_), &fake_pref_service); - store_->Init(syncer::SyncableService::StartSyncFlare(), nullptr); -} - -PasswordStoreXTestDelegate::~PasswordStoreXTestDelegate() { - store_->ShutdownOnUIThread(); -} - -void PasswordStoreXTestDelegate::FinishAsyncProcessing() { - task_environment_.RunUntilIdle(); -} - -void PasswordStoreXTestDelegate::SetupTempDir() { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); -} - -base::FilePath PasswordStoreXTestDelegate::test_login_db_file_path() const { - return temp_dir_.GetPath().Append(FILE_PATH_LITERAL("login_test")); -} - -base::FilePath PasswordStoreXTestDelegate::test_encrypted_login_db_file_path() - const { - return temp_dir_.GetPath().Append(FILE_PATH_LITERAL("encrypted_login_test")); -} - -class PasswordStoreXNoBackendTestDelegate : public PasswordStoreXTestDelegate { - public: - PasswordStoreXNoBackendTestDelegate() - : PasswordStoreXTestDelegate(NO_BACKEND) {} -}; - -class PasswordStoreXWorkingBackendTestDelegate - : public PasswordStoreXTestDelegate { - public: - PasswordStoreXWorkingBackendTestDelegate() - : PasswordStoreXTestDelegate(WORKING_BACKEND) { - // Working backends are switched for LoginDatabase with encryption. - OSCryptMocker::SetUp(); - } - ~PasswordStoreXWorkingBackendTestDelegate() { OSCryptMocker::TearDown(); } -}; - -std::vector<std::unique_ptr<PasswordForm>> ReadLoginDB( - const base::FilePath& path, - bool encrypted) { - password_manager::LoginDatabase login_db(path); - if (!encrypted) - login_db.disable_encryption(); - EXPECT_TRUE(login_db.Init()); - std::vector<std::unique_ptr<PasswordForm>> stored_forms; - EXPECT_TRUE(login_db.GetAutofillableLogins(&stored_forms)); - return stored_forms; +PasswordForm MakePasswordForm() { + PasswordForm form; + form.origin = GURL("http://www.origin.com"); + form.username_element = base::UTF8ToUTF16("username_element"); + form.username_value = base::UTF8ToUTF16(kUsername); + form.password_element = base::UTF8ToUTF16("password_element"); + form.username_value = base::UTF8ToUTF16(kPassword); + form.signon_realm = form.origin.GetOrigin().spec(); + return form; } } // namespace -namespace password_manager { - -INSTANTIATE_TYPED_TEST_SUITE_P(XNoBackend, - PasswordStoreOriginTest, - PasswordStoreXNoBackendTestDelegate); - -INSTANTIATE_TYPED_TEST_SUITE_P(XWorkingBackend, - PasswordStoreOriginTest, - PasswordStoreXWorkingBackendTestDelegate); -} // namespace password_manager - -class PasswordStoreXTest : public testing::TestWithParam<BackendType> { - protected: - PasswordStoreXTest() = default; - - void SetUp() override { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); +class PasswordStoreXTest : public testing::Test { + public: + PasswordStoreXTest() { + ignore_result(temp_dir_.CreateUniqueTempDir()); fake_pref_service_.registry()->RegisterIntegerPref( password_manager::prefs::kMigrationToLoginDBStep, PasswordStoreX::NOT_ATTEMPTED); OSCryptMocker::SetUp(); } - void TearDown() override { OSCryptMocker::TearDown(); } + ~PasswordStoreXTest() override { OSCryptMocker::TearDown(); } + + PrefService* fake_pref_service() { return &fake_pref_service_; } base::FilePath test_login_db_file_path() const { return temp_dir_.GetPath().Append(FILE_PATH_LITERAL("login_test")); } - base::FilePath test_encrypted_login_db_file_path() const { - return temp_dir_.GetPath().Append( - FILE_PATH_LITERAL("encrypted_login_test")); - } - void WaitForPasswordStore() { task_environment_.RunUntilIdle(); } - protected: - TestingPrefServiceSimple fake_pref_service_; - base::HistogramTester histogram_tester_; - private: + TestingPrefServiceSimple fake_pref_service_; base::test::ScopedTaskEnvironment task_environment_; base::ScopedTempDir temp_dir_; DISALLOW_COPY_AND_ASSIGN(PasswordStoreXTest); }; -TEST_P(PasswordStoreXTest, Notifications) { - std::unique_ptr<password_manager::LoginDatabase> login_db( - new password_manager::LoginDatabase(test_login_db_file_path())); - scoped_refptr<PasswordStoreX> store( - new PasswordStoreX(std::move(login_db), test_login_db_file_path(), - test_encrypted_login_db_file_path(), - GetBackend(GetParam()), &fake_pref_service_)); - store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); - - password_manager::PasswordFormData form_data = { - PasswordForm::Scheme::kHtml, - "http://bar.example.com", - "http://bar.example.com/origin", - "http://bar.example.com/action", - L"submit_element", - L"username_element", - L"password_element", - L"username_value", - L"password_value", - true, - 1}; - std::unique_ptr<PasswordForm> form = FillPasswordFormWithData(form_data); - - password_manager::MockPasswordStoreObserver observer; - store->AddObserver(&observer); - - const PasswordStoreChange expected_add_changes[] = { - PasswordStoreChange(PasswordStoreChange::ADD, *form), - }; - - EXPECT_CALL(observer, - OnLoginsChanged(ElementsAreArray(expected_add_changes))); - - // Adding a login should trigger a notification. - store->AddLogin(*form); - - WaitForPasswordStore(); - - // Change the password. - form->password_value = base::ASCIIToUTF16("a different password"); - - const PasswordStoreChange expected_update_changes[] = { - PasswordStoreChange(PasswordStoreChange::UPDATE, *form), - }; - - EXPECT_CALL(observer, - OnLoginsChanged(ElementsAreArray(expected_update_changes))); - - // Updating the login with the new password should trigger a notification. - store->UpdateLogin(*form); - - WaitForPasswordStore(); - - const PasswordStoreChange expected_delete_changes[] = { - PasswordStoreChange(PasswordStoreChange::REMOVE, *form), - }; - - EXPECT_CALL(observer, - OnLoginsChanged(ElementsAreArray(expected_delete_changes))); - - // Deleting the login should trigger a notification. - store->RemoveLogin(*form); - - WaitForPasswordStore(); - - store->RemoveObserver(&observer); - - store->ShutdownOnUIThread(); -} - -TEST_P(PasswordStoreXTest, NativeMigration) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndDisableFeature( - password_manager::features::kMigrateLinuxToLoginDB); - - std::vector<std::unique_ptr<PasswordForm>> expected_forms; - InitExpectedForms(true, 5, &expected_forms); - InitExpectedForms(false, 5, &expected_forms); - - const base::FilePath login_db_file = test_login_db_file_path(); - std::unique_ptr<password_manager::LoginDatabase> login_db( - new password_manager::LoginDatabase(login_db_file)); - login_db->disable_encryption(); - ASSERT_TRUE(login_db->Init()); - - // Get the initial size of the login DB file, before we populate it. - // This will be used later to make sure it gets back to this size. - base::File::Info db_file_start_info; - ASSERT_TRUE(base::GetFileInfo(login_db_file, &db_file_start_info)); - - // Populate the login DB with logins that should be migrated. - for (const auto& form : expected_forms) { - EXPECT_EQ(AddChangeForForm(*form), login_db->AddLogin(*form)); - } - - // Get the new size of the login DB file. We expect it to be larger. - base::File::Info db_file_full_info; - ASSERT_TRUE(base::GetFileInfo(login_db_file, &db_file_full_info)); - EXPECT_GT(db_file_full_info.size, db_file_start_info.size); - - // Initializing the PasswordStore shouldn't trigger a native migration (yet). - login_db.reset(new password_manager::LoginDatabase(login_db_file)); - scoped_refptr<PasswordStoreX> store( - new PasswordStoreX(std::move(login_db), test_login_db_file_path(), - test_encrypted_login_db_file_path(), - GetBackend(GetParam()), &fake_pref_service_)); - store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); - - MockPasswordStoreConsumer consumer; - - // All forms should have been migrated to the native backend. - EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef( - UnorderedPasswordFormElementsAre(&expected_forms))); - store->GetAllLogins(&consumer); - WaitForPasswordStore(); - - MockLoginDatabaseReturn ld_return; - - if (GetParam() == WORKING_BACKEND) { - // No logins should be left in the login DB. - EXPECT_CALL(ld_return, OnLoginDatabaseQueryDone(IsEmpty())); - } else { - // All logins should still be in the login DB. - EXPECT_CALL(ld_return, - OnLoginDatabaseQueryDone( - UnorderedPasswordFormElementsAre(&expected_forms))); - } - - LoginDatabaseQueryCallback(store->login_db(), &ld_return); - WaitForPasswordStore(); - - if (GetParam() == WORKING_BACKEND) { - // If the migration succeeded, then not only should there be no logins left - // in the login DB, but also the file should have been deleted and then - // recreated. We approximate checking for this by checking that the file - // size is equal to the size before we populated it, even though it was - // larger after populating it. - base::File::Info db_file_end_info; - ASSERT_TRUE(base::GetFileInfo(login_db_file, &db_file_end_info)); - EXPECT_EQ(db_file_start_info.size, db_file_end_info.size); - } - - store->ShutdownOnUIThread(); -} - -TEST_P(PasswordStoreXTest, MigrationToEncryption) { +TEST_F(PasswordStoreXTest, MigrationCompleted) { IntegerPrefMember migration_step_pref_; migration_step_pref_.Init(password_manager::prefs::kMigrationToLoginDBStep, - &fake_pref_service_); - - EXPECT_EQ(PasswordStoreX::NOT_ATTEMPTED, migration_step_pref_.GetValue()); - - // Add existing credentials into the backend. - std::vector<std::unique_ptr<PasswordForm>> old_credentials; - InitExpectedForms(true, 6, &old_credentials); - std::unique_ptr<PasswordStoreX::NativeBackend> backend = - GetBackend(GetParam()); - std::vector<PasswordForm> native_backend_last_state; - if (GetParam() == WORKING_BACKEND) { - static_cast<MockBackend*>(backend.get()) - ->SaveFormsOnDestruct(&native_backend_last_state); - } - if (GetParam() != NO_BACKEND) { - for (int i = 0; i < 3; i++) - backend->AddLogin(*old_credentials[i]); - } - - // Add existing credentials into the unencrypted loginDB. - auto login_db = std::make_unique<password_manager::LoginDatabase>( - test_login_db_file_path()); - login_db->disable_encryption(); - ASSERT_TRUE(login_db->Init()); - for (int i = 3; i < 6; i++) - ignore_result(login_db->AddLogin(*old_credentials[i])); - - login_db = std::make_unique<password_manager::LoginDatabase>( - test_login_db_file_path()); - scoped_refptr<PasswordStoreX> store( - new PasswordStoreX(std::move(login_db), test_login_db_file_path(), - test_encrypted_login_db_file_path(), - std::move(backend), &fake_pref_service_)); - store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); - - // Make modifications, so that we trigger the migration and so that we can - // verify where the store serves from. The migration is triggered - // opportunistically during access to the store. - const auto new_form = password_manager::FillPasswordFormWithData( - {PasswordForm::Scheme::kHtml, "https://www.fakebook.com", - "https://www.fakebook.com/li", "https://www.fakebook.com/a", - L"submit_element", L"username_element", L"password_element", - L"username_value", L"password_value", true, 1.0}); - store->RemoveLogin(*old_credentials[0]); - store->AddLogin(*new_form); - - MockPasswordStoreConsumer consumer; - if (GetParam() == WORKING_BACKEND) { - // The store has the native backend data, the initial unencrypted loginDB - // data and modifications. - EXPECT_CALL( - consumer, - OnGetPasswordStoreResultsConstRef(UnorderedElementsAre( - Pointee(*new_form), Pointee(*old_credentials[1]), - Pointee(*old_credentials[2]), Pointee(*old_credentials[3]), - Pointee(*old_credentials[4]), Pointee(*old_credentials[5])))); - } else { - // The has the initial unencrypted loginDB data and modifications. - EXPECT_CALL( - consumer, - OnGetPasswordStoreResultsConstRef(UnorderedElementsAre( - Pointee(*new_form), Pointee(*old_credentials[3]), - Pointee(*old_credentials[4]), Pointee(*old_credentials[5])))); - } - store->GetAutofillableLogins(&consumer); - - WaitForPasswordStore(); - store->ShutdownOnUIThread(); - store.reset(); - WaitForPasswordStore(); - - // This will report that it was migrated on the next run. - histogram_tester_.ExpectBucketCount( - "PasswordManager.LinuxBackendMigration.Adoption", - LinuxBackendMigrationStatus::kNotAttempted, 1); - - if (GetParam() == WORKING_BACKEND) { - // Verify that the login database contains all the values, now encrypted. - std::vector<std::unique_ptr<PasswordForm>> stored_forms = - ReadLoginDB(test_login_db_file_path(), true); - EXPECT_EQ(6u, stored_forms.size()); - EXPECT_THAT( - stored_forms, - UnorderedElementsAre( - Pointee(*new_form), Pointee(*old_credentials[1]), - Pointee(*old_credentials[2]), Pointee(*old_credentials[3]), - Pointee(*old_credentials[4]), Pointee(*old_credentials[5]))); - EXPECT_TRUE(native_backend_last_state.empty()); - - stored_forms = ReadLoginDB(test_encrypted_login_db_file_path(), false); - EXPECT_TRUE(stored_forms.empty()); - EXPECT_EQ(PasswordStoreX::LOGIN_DB_REPLACED, - migration_step_pref_.GetValue()); - - histogram_tester_.ExpectBucketCount( - "PasswordManager.LinuxBackendMigration.AttemptResult", - LinuxBackendMigrationStatus::kLoginDBReplaced, 1); - } else if (GetParam() == FAILING_BACKEND) { - // No values should be written if we can't read the backend. - auto stored_forms = ReadLoginDB(test_encrypted_login_db_file_path(), true); - EXPECT_TRUE(stored_forms.empty()); - EXPECT_THAT(migration_step_pref_.GetValue(), PasswordStoreX::POSTPONED); - - histogram_tester_.ExpectBucketCount( - "PasswordManager.LinuxBackendMigration.AttemptResult", - LinuxBackendMigrationStatus::kPostponed, 1); - } else { // NO_BACKEND - // No values should be moved without a working backend. - auto stored_forms = ReadLoginDB(test_encrypted_login_db_file_path(), true); - EXPECT_TRUE(stored_forms.empty()); - EXPECT_THAT(migration_step_pref_.GetValue(), PasswordStoreX::NOT_ATTEMPTED); - } -} - -// Once the migration is performed, don't port anything else into the new -// location. -TEST_P(PasswordStoreXTest, MigrationToEncryption_OnlyOnce) { - if (GetParam() != WORKING_BACKEND) - return; - - IntegerPrefMember migration_step_pref_; - migration_step_pref_.Init(password_manager::prefs::kMigrationToLoginDBStep, - &fake_pref_service_); + fake_pref_service()); // Signal that the migration has been completed. migration_step_pref_.SetValue(PasswordStoreX::LOGIN_DB_REPLACED); - // We add new credentials into a backend. They should be completely ignored by - // the store. - std::vector<std::unique_ptr<PasswordForm>> old_credentials; - InitExpectedForms(true, 6, &old_credentials); - auto backend = GetBackend(GetParam()); - for (int i = 0; i < 3; i++) - backend->AddLogin(*old_credentials[i]); - - // Add existing credentials into loginDB. They should be the only thing that's + // Add existing credential into loginDB. It should be the only thing that's // available in the store. auto login_db = std::make_unique<password_manager::LoginDatabase>( test_login_db_file_path()); ASSERT_TRUE(login_db->Init()); - for (int i = 3; i < 6; i++) - ignore_result(login_db->AddLogin(*old_credentials[i])); + ignore_result(login_db->AddLogin(MakePasswordForm())); login_db.reset(); // Create the store. login_db = std::make_unique<password_manager::LoginDatabase>( test_login_db_file_path()); scoped_refptr<PasswordStoreX> store = - new PasswordStoreX(std::move(login_db), test_login_db_file_path(), - test_encrypted_login_db_file_path(), - std::move(backend), &fake_pref_service_); + new PasswordStoreX(std::move(login_db), fake_pref_service()); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); - // Make modifications and check the contents. + // Check the contents are still around. MockPasswordStoreConsumer consumer; - EXPECT_CALL(consumer, - OnGetPasswordStoreResultsConstRef(UnorderedElementsAre( - Pointee(*old_credentials[3]), Pointee(*old_credentials[4]), - Pointee(*old_credentials[5])))); - store->GetAutofillableLogins(&consumer); - store->RemoveLogin(*old_credentials[3]); - EXPECT_CALL(consumer, - OnGetPasswordStoreResultsConstRef(UnorderedElementsAre( - Pointee(*old_credentials[4]), Pointee(*old_credentials[5])))); + EXPECT_CALL(consumer, OnGetPasswordStoreResultsConstRef( + ElementsAre(Pointee(MakePasswordForm())))); store->GetAutofillableLogins(&consumer); WaitForPasswordStore(); @@ -763,87 +140,107 @@ store.reset(); WaitForPasswordStore(); - // The previous results were served from an encrypted login database. - std::vector<std::unique_ptr<PasswordForm>> stored_forms = - ReadLoginDB(test_login_db_file_path(), true); - EXPECT_EQ(2u, stored_forms.size()); - EXPECT_EQ(PasswordStoreX::LOGIN_DB_REPLACED, migration_step_pref_.GetValue()); - EXPECT_THAT(stored_forms, UnorderedElementsAre(Pointee(*old_credentials[4]), - Pointee(*old_credentials[5]))); - - histogram_tester_.ExpectBucketCount( - "PasswordManager.LinuxBackendMigration.Adoption", - LinuxBackendMigrationStatus::kLoginDBReplaced, 1); - histogram_tester_.ExpectTotalCount( - "PasswordManager.LinuxBackendMigration.AttemptResult", 0); + // Check if the database is encrypted. + password_manager::LoginDatabase login_db2(test_login_db_file_path()); + // Disable encryption. + login_db2.disable_encryption(); + EXPECT_TRUE(login_db2.Init()); + // Read the password again. + std::vector<std::unique_ptr<PasswordForm>> stored_forms; + EXPECT_TRUE(login_db2.GetAutofillableLogins(&stored_forms)); + EXPECT_EQ(1U, stored_forms.size()); + // Password values don't match because they have been stored encrypted and + // read unencrypted. + EXPECT_NE(kPassword, base::UTF16ToUTF8(stored_forms[0]->password_value)); } -TEST_P(PasswordStoreXTest, MigrationToEncryption_DropIllegalEntries) { - if (GetParam() != WORKING_BACKEND) - return; - +TEST_F(PasswordStoreXTest, MigrationNotAttemptedEmptyDB) { IntegerPrefMember migration_step_pref_; migration_step_pref_.Init(password_manager::prefs::kMigrationToLoginDBStep, - &fake_pref_service_); + fake_pref_service()); + // Signal that the migration has not been attempted. + migration_step_pref_.SetValue(PasswordStoreX::NOT_ATTEMPTED); - EXPECT_EQ(PasswordStoreX::NOT_ATTEMPTED, migration_step_pref_.GetValue()); - - // Add existing credentials into the backend. - std::vector<std::unique_ptr<PasswordForm>> old_credentials; - InitExpectedForms(true, 4, &old_credentials); - // Create illegal entries. - old_credentials[1]->origin = GURL(); - old_credentials[3]->signon_realm.clear(); - - std::unique_ptr<PasswordStoreX::NativeBackend> backend = - GetBackend(GetParam()); - std::vector<PasswordForm> native_backend_last_state; - static_cast<MockBackend*>(backend.get()) - ->SaveFormsOnDestruct(&native_backend_last_state); - for (int i = 0; i < 3; i++) - backend->AddLogin(*old_credentials[i]); - + // Create the store with an empty database. auto login_db = std::make_unique<password_manager::LoginDatabase>( test_login_db_file_path()); - scoped_refptr<PasswordStoreX> store( - new PasswordStoreX(std::move(login_db), test_login_db_file_path(), - test_encrypted_login_db_file_path(), - std::move(backend), &fake_pref_service_)); + password_manager::LoginDatabase* login_db_ptr = login_db.get(); + + scoped_refptr<PasswordStoreX> store = + new PasswordStoreX(std::move(login_db), fake_pref_service()); store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); - - MockPasswordStoreConsumer consumer; - // The store has the native backend data, minus the illegal entries. - // The call to GetAutofillableLogins() both triggers the opportunistic - // migration and returns the data for the test. - EXPECT_CALL(consumer, - OnGetPasswordStoreResultsConstRef(UnorderedElementsAre( - Pointee(*old_credentials[0]), Pointee(*old_credentials[2])))); - store->GetAutofillableLogins(&consumer); - WaitForPasswordStore(); + + // Add a password to the db. + PasswordStoreChangeList changes = login_db_ptr->AddLogin(MakePasswordForm()); + EXPECT_EQ(1U, changes.size()); + store->ShutdownOnUIThread(); store.reset(); WaitForPasswordStore(); - // Verify that the login database contains all the values, now encrypted. - std::vector<std::unique_ptr<PasswordForm>> stored_forms = - ReadLoginDB(test_login_db_file_path(), true); - EXPECT_EQ(2u, stored_forms.size()); - EXPECT_THAT(stored_forms, UnorderedElementsAre(Pointee(*old_credentials[0]), - Pointee(*old_credentials[2]))); - EXPECT_EQ(PasswordStoreX::LOGIN_DB_REPLACED, migration_step_pref_.GetValue()); - - histogram_tester_.ExpectBucketCount( - "PasswordManager.LinuxBackendMigration.AttemptResult", - LinuxBackendMigrationStatus::kLoginDBReplaced, 1); + // Check if the database is encrypted. + password_manager::LoginDatabase login_db2(test_login_db_file_path()); + login_db2.disable_encryption(); + EXPECT_TRUE(login_db2.Init()); + // Read the password again. + std::vector<std::unique_ptr<PasswordForm>> stored_forms; + EXPECT_TRUE(login_db2.GetAutofillableLogins(&stored_forms)); + EXPECT_EQ(1U, stored_forms.size()); + // Password values don't match because they have been stored encrypted and + // read unencrypted. + EXPECT_NE(kPassword, base::UTF16ToUTF8(stored_forms[0]->password_value)); } -INSTANTIATE_TEST_SUITE_P(NoBackend, - PasswordStoreXTest, - testing::Values(NO_BACKEND)); -INSTANTIATE_TEST_SUITE_P(FailingBackend, - PasswordStoreXTest, - testing::Values(FAILING_BACKEND)); -INSTANTIATE_TEST_SUITE_P(WorkingBackend, - PasswordStoreXTest, - testing::Values(WORKING_BACKEND)); +TEST_F(PasswordStoreXTest, MigrationNotAttemptedNonEmptyDB) { + IntegerPrefMember migration_step_pref_; + migration_step_pref_.Init(password_manager::prefs::kMigrationToLoginDBStep, + fake_pref_service()); + // Signal that the migration has not been attempted. + migration_step_pref_.SetValue(PasswordStoreX::NOT_ATTEMPTED); + + // Add existing credential into loginDB. + auto login_db = std::make_unique<password_manager::LoginDatabase>( + test_login_db_file_path()); + ASSERT_TRUE(login_db->Init()); + ignore_result(login_db->AddLogin(MakePasswordForm())); + login_db.reset(); + + // Create the store with a non-empty database. + login_db = std::make_unique<password_manager::LoginDatabase>( + test_login_db_file_path()); + password_manager::LoginDatabase* login_db_ptr = login_db.get(); + + scoped_refptr<PasswordStoreX> store = + new PasswordStoreX(std::move(login_db), fake_pref_service()); + store->Init(syncer::SyncableService::StartSyncFlare(), nullptr); + WaitForPasswordStore(); + + // Add another password to the db. + PasswordForm form = MakePasswordForm(); + form.username_value = base::UTF8ToUTF16(kAnotherUsername); + PasswordStoreChangeList changes = login_db_ptr->AddLogin(form); + EXPECT_EQ(1U, changes.size()); + + store->ShutdownOnUIThread(); + store.reset(); + WaitForPasswordStore(); + + // Check if the database is unencrypted. + password_manager::LoginDatabase login_db2(test_login_db_file_path()); + // Disable encryption. + login_db2.disable_encryption(); + EXPECT_TRUE(login_db2.Init()); + // Read the password again. + std::vector<std::unique_ptr<PasswordForm>> stored_forms; + EXPECT_TRUE(login_db2.GetAutofillableLogins(&stored_forms)); + EXPECT_EQ(2U, stored_forms.size()); + for (const std::unique_ptr<PasswordForm>& stored_form : stored_forms) { + if (base::UTF16ToUTF8(stored_forms[0]->username_value) == + kAnotherUsername) { + // Password values match because they have been stored unencrypted and + // read unencrypted. + EXPECT_EQ(kPassword, base::UTF16ToUTF8(stored_form->password_value)); + } + } +}
diff --git a/chrome/browser/platform_util.cc b/chrome/browser/platform_util.cc index 43f63c1..b3300f13 100644 --- a/chrome/browser/platform_util.cc +++ b/chrome/browser/platform_util.cc
@@ -62,8 +62,14 @@ OpenItemType item_type, const OpenOperationCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + // TaskPriority::USER_BLOCKING because this is usually opened as a result of a + // user action (e.g. open-downloaded-file or show-item-in-folder). + // TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN because this doesn't need global + // state and can hang shutdown without this trait as it may result in an + // interactive dialog. base::PostTaskWithTraits(FROM_HERE, - {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + {base::MayBlock(), base::TaskPriority::USER_BLOCKING, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, base::BindOnce(&VerifyAndOpenItemOnBlockingThread, full_path, item_type, callback)); }
diff --git a/chrome/browser/platform_util_internal.h b/chrome/browser/platform_util_internal.h index 0b93b7dcd..3c6f02c 100644 --- a/chrome/browser/platform_util_internal.h +++ b/chrome/browser/platform_util_internal.h
@@ -16,8 +16,9 @@ // Called by platform_util.cc on desktop platforms to invoke platform specific // logic to open |path| using a suitable handler. |path| has been verified to be -// of type |type|. -// Always called on the blocking pool. +// of type |type|. Called on the thread pool with +// base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN semantics (and thus can't +// use global state torn down during shutdown). void PlatformOpenVerifiedItem(const base::FilePath& path, OpenItemType type); // Prevent shell or external applications from being invoked during testing.
diff --git a/chrome/browser/platform_util_linux.cc b/chrome/browser/platform_util_linux.cc index 9fb1a7a..f16d0eb 100644 --- a/chrome/browser/platform_util_linux.cc +++ b/chrome/browser/platform_util_linux.cc
@@ -12,6 +12,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/task/post_task.h" +#include "base/threading/scoped_blocking_call.h" #include "base/version.h" #include "chrome/browser/platform_util_internal.h" #include "content/public/browser/browser_thread.h" @@ -136,6 +137,9 @@ namespace internal { void PlatformOpenVerifiedItem(const base::FilePath& path, OpenItemType type) { + // May result in an interactive dialog. + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); switch (type) { case OPEN_FILE: XDGOpen(path.DirName(), path.value());
diff --git a/chrome/browser/platform_util_win.cc b/chrome/browser/platform_util_win.cc index 9d15886..3cb79b0 100644 --- a/chrome/browser/platform_util_win.cc +++ b/chrome/browser/platform_util_win.cc
@@ -122,6 +122,9 @@ namespace internal { void PlatformOpenVerifiedItem(const base::FilePath& path, OpenItemType type) { + // May result in an interactive dialog. + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); switch (type) { case OPEN_FILE: ui::win::OpenFileViaShell(path);
diff --git a/chrome/browser/policy/policy_conversions.cc b/chrome/browser/policy/policy_conversions.cc index 0d79ed2..f8d158b 100644 --- a/chrome/browser/policy/policy_conversions.cc +++ b/chrome/browser/policy/policy_conversions.cc
@@ -53,67 +53,17 @@ namespace em = enterprise_management; namespace policy { - -// Fills |policy_dump| with device specific information if this device is -// enterprise managed. -void FillIdentityFields(Value* policy_dump); - namespace { -// Maps known policy names to their schema. If a policy is not present, it is -// not known (either through policy_templates.json or through an extenion's -// managed storage schema). -using PolicyToSchemaMap = base::flat_map<std::string, Schema>; - -// Utility function that returns a JSON serialization of the given |dict|. -std::string DictionaryToJSONString(const Value& dict, bool is_pretty_print) { - std::string json_string; - base::JSONWriter::WriteWithOptions( - dict, (is_pretty_print ? base::JSONWriter::OPTIONS_PRETTY_PRINT : 0), - &json_string); - return json_string; -} - -// Returns a copy of |value|. If necessary (which is specified by -// |convert_values|), converts some values to a representation that -// i18n_template.js will display. -Value CopyAndMaybeConvert(const Value& value, - bool convert_values, - const base::Optional<Schema>& schema, - bool is_pretty_print) { - Value value_copy = value.Clone(); - if (schema.has_value()) - schema->MaskSensitiveValues(&value_copy); - if (!convert_values) - return value_copy; - if (value_copy.is_dict()) - return Value(DictionaryToJSONString(value_copy, is_pretty_print)); - - if (!value_copy.is_list()) { - return value_copy; - } - - Value result(Value::Type::LIST); - for (const auto& element : value_copy.GetList()) { - if (element.is_dict()) { - result.GetList().emplace_back( - Value(DictionaryToJSONString(element, is_pretty_print))); - } else { - result.GetList().push_back(element.Clone()); - } - } - return result; -} - -PolicyService* GetPolicyService(content::BrowserContext* context) { - Profile* profile = Profile::FromBrowserContext(context); +PolicyService* GetPolicyService(Profile* profile) { return profile->GetProfilePolicyConnector()->policy_service(); } // Returns the Schema for |policy_name| if that policy is known. If the policy // is unknown, returns |base::nullopt|. base::Optional<Schema> GetKnownPolicySchema( - const base::Optional<PolicyToSchemaMap>& known_policy_schemas, + const base::Optional<PolicyConversions::PolicyToSchemaMap>& + known_policy_schemas, const std::string& policy_name) { if (!known_policy_schemas.has_value()) return base::nullopt; @@ -123,30 +73,307 @@ return known_policy_iterator->second; } -// Create a description of the policy |policy_name| using |policy| and the -// optional errors in |errors| to determine the status of each policy. If -// |convert_values| is true, converts the values to show them in javascript. -// |known_policy_schemas| contains |Schema|s for known policies in the same -// policy namespace of |map|. A policy without an entry in -// |known_policy_schemas| is an unknown policy. -// When |convert_types| is true, policy types are converted into string. For -// example, POLICY_SCOPE_USER is converted to 'user'. Otherwise, policy types -// are returned as integers. -Value GetPolicyValue( +base::Optional<PolicyConversions::PolicyToSchemaMap> GetKnownPolicies( + const scoped_refptr<SchemaMap> schema_map, + const PolicyNamespace& policy_namespace) { + const Schema* schema = schema_map->GetSchema(policy_namespace); + // There is no policy name verification without valid schema. + if (!schema || !schema->valid()) + return base::nullopt; + + // Build a vector first and construct the PolicyToSchemaMap (which is a + // |flat_map|) from that. The reason is that insertion into a |flat_map| is + // O(n), which would make the loop O(n^2), but constructing from a + // pre-populated vector is less expensive. + std::vector<std::pair<std::string, Schema>> policy_to_schema_entries; + for (auto it = schema->GetPropertiesIterator(); !it.IsAtEnd(); it.Advance()) { + policy_to_schema_entries.push_back(std::make_pair(it.key(), it.schema())); + } + return PolicyConversions::PolicyToSchemaMap( + std::move(policy_to_schema_entries)); +} + +} // namespace + +const LocalizedString kPolicySources[POLICY_SOURCE_COUNT] = { + {"sourceEnterpriseDefault", IDS_POLICY_SOURCE_ENTERPRISE_DEFAULT}, + {"cloud", IDS_POLICY_SOURCE_CLOUD}, + {"sourceActiveDirectory", IDS_POLICY_SOURCE_ACTIVE_DIRECTORY}, + {"sourceDeviceLocalAccountOverride", + IDS_POLICY_SOURCE_DEVICE_LOCAL_ACCOUNT_OVERRIDE}, + {"platform", IDS_POLICY_SOURCE_PLATFORM}, + {"priorityCloud", IDS_POLICY_SOURCE_CLOUD}, + {"merged", IDS_POLICY_SOURCE_MERGED}, +}; + +PolicyConversions::PolicyConversions() = default; +PolicyConversions::~PolicyConversions() = default; + +PolicyConversions& PolicyConversions::WithBrowserContext( + content::BrowserContext* context) { + profile_ = Profile::FromBrowserContext( + chrome::GetBrowserContextRedirectedInIncognito(context)); + return *this; +} + +PolicyConversions& PolicyConversions::EnableConvertTypes(bool enabled) { + convert_types_enabled_ = enabled; + return *this; +} + +PolicyConversions& PolicyConversions::EnableConvertValues(bool enabled) { + convert_values_enabled_ = enabled; + return *this; +} + +PolicyConversions& PolicyConversions::EnableDevicePolicies(bool enabled) { + device_policies_enabled_ = enabled; + return *this; +} + +PolicyConversions& PolicyConversions::EnableDeviceInfo(bool enabled) { + device_info_enabled_ = enabled; + return *this; +} + +PolicyConversions& PolicyConversions::EnablePrettyPrint(bool enabled) { + pretty_print_enabled_ = enabled; + return *this; +} + +PolicyConversions& PolicyConversions::EnableUserPolicies(bool enabled) { + user_policies_enabled_ = enabled; + return *this; +} + +std::string PolicyConversions::ToJSON() { + return ConvertValueToJSON(ToValue()); +} + +Value PolicyConversions::GetChromePolicies() { + PolicyService* policy_service = GetPolicyService(profile_); + PolicyMap map; + + auto* schema_registry_service = profile_->GetPolicySchemaRegistryService(); + if (!schema_registry_service || !schema_registry_service->registry()) { + LOG(ERROR) << "Can not dump Chrome policies, no schema registry service"; + return Value(Value::Type::DICTIONARY); + } + + const scoped_refptr<SchemaMap> schema_map = + schema_registry_service->registry()->schema_map(); + + PolicyNamespace policy_namespace = + PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()); + + // Make a copy that can be modified, since some policy values are modified + // before being displayed. + map.CopyFrom(policy_service->GetPolicies(policy_namespace)); + + // Get a list of all the errors in the policy values. + const ConfigurationPolicyHandlerList* handler_list = + g_browser_process->browser_policy_connector()->GetHandlerList(); + PolicyErrorMap errors; + handler_list->ApplyPolicySettings(map, NULL, &errors); + + // Convert dictionary values to strings for display. + handler_list->PrepareForDisplaying(&map); + + return GetPolicyValues(map, &errors, + GetKnownPolicies(schema_map, policy_namespace)); +} + +Value PolicyConversions::GetExtensionsPolicies() { + Value policies(Value::Type::LIST); +#if BUILDFLAG(ENABLE_EXTENSIONS) + // Add extension policy values. + extensions::ExtensionRegistry* registry = + extensions::ExtensionRegistry::Get(profile_); + if (!registry) { + LOG(ERROR) << "Can not dump extension policies, no extension registry"; + return policies; + } + auto* schema_registry_service = profile_->GetPolicySchemaRegistryService(); + if (!schema_registry_service || !schema_registry_service->registry()) { + LOG(ERROR) << "Can not dump extension policies, no schema registry service"; + return policies; + } + const scoped_refptr<SchemaMap> schema_map = + schema_registry_service->registry()->schema_map(); + for (const scoped_refptr<const extensions::Extension>& extension : + registry->enabled_extensions()) { + // Skip this extension if it's not an enterprise extension. + if (!extension->manifest()->HasPath( + extensions::manifest_keys::kStorageManagedSchema)) { + continue; + } + + PolicyNamespace policy_namespace = + PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, extension->id()); + PolicyErrorMap empty_error_map; + Value extension_policies = GetPolicyValues( + GetPolicyService(profile_)->GetPolicies(policy_namespace), + &empty_error_map, GetKnownPolicies(schema_map, policy_namespace)); + Value extension_policies_data(Value::Type::DICTIONARY); + extension_policies_data.SetKey("name", Value(extension->name())); + extension_policies_data.SetKey("id", Value(extension->id())); + extension_policies_data.SetKey("policies", std::move(extension_policies)); + policies.GetList().push_back(std::move(extension_policies_data)); + } +#endif + return policies; +} + +#if defined(OS_CHROMEOS) +Value PolicyConversions::GetDeviceLocalAccountPolicies() { + Value policies(Value::Type::LIST); + // DeviceLocalAccount policies are only available for affiliated users and for + // system logs. + if (!device_policies_enabled_ && + (!user_manager::UserManager::IsInitialized() || + !user_manager::UserManager::Get()->GetPrimaryUser() || + !user_manager::UserManager::Get()->GetPrimaryUser()->IsAffiliated())) { + return policies; + } + + BrowserPolicyConnectorChromeOS* connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + DCHECK(connector); // always not-null + + auto* device_local_account_policy_service = + connector->GetDeviceLocalAccountPolicyService(); + DCHECK(device_local_account_policy_service); // always non null for + // affiliated users + std::vector<DeviceLocalAccount> device_local_accounts = + GetDeviceLocalAccounts(chromeos::CrosSettings::Get()); + for (const auto& account : device_local_accounts) { + std::string user_id = account.user_id; + + auto* device_local_account_policy_broker = + device_local_account_policy_service->GetBrokerForUser(user_id); + if (!device_local_account_policy_broker) { + LOG(ERROR) + << "Can not get policy broker for device local account with user id: " + << user_id; + continue; + } + + auto* cloud_policy_core = device_local_account_policy_broker->core(); + DCHECK(cloud_policy_core); + auto* cloud_policy_store = cloud_policy_core->store(); + DCHECK(cloud_policy_store); + + const scoped_refptr<SchemaMap> schema_map = + device_local_account_policy_broker->schema_registry()->schema_map(); + + PolicyNamespace policy_namespace = + PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()); + + // Make a copy that can be modified, since some policy values are modified + // before being displayed. + PolicyMap map; + map.CopyFrom(cloud_policy_store->policy_map()); + + // Get a list of all the errors in the policy values. + const ConfigurationPolicyHandlerList* handler_list = + connector->GetHandlerList(); + PolicyErrorMap errors; + handler_list->ApplyPolicySettings(map, NULL, &errors); + + // Convert dictionary values to strings for display. + handler_list->PrepareForDisplaying(&map); + + Value current_account_policies = GetPolicyValues( + map, &errors, GetKnownPolicies(schema_map, policy_namespace)); + Value current_account_policies_data(Value::Type::DICTIONARY); + current_account_policies_data.SetKey("id", Value(user_id)); + current_account_policies_data.SetKey("user_id", Value(user_id)); + current_account_policies_data.SetKey("name", Value(user_id)); + current_account_policies_data.SetKey("policies", + std::move(current_account_policies)); + policies.GetList().push_back(std::move(current_account_policies_data)); + } + return policies; +} + +Value PolicyConversions::GetIdentityFields() { + Value identity_fields(Value::Type::DICTIONARY); + if (!device_info_enabled_) + return Value(); + BrowserPolicyConnectorChromeOS* connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + if (!connector) { + LOG(ERROR) << "Can not dump identity fields, no policy connector"; + return Value(); + } + if (connector->IsEnterpriseManaged()) { + identity_fields.SetKey("enrollment_domain", + Value(connector->GetEnterpriseEnrollmentDomain())); + + if (connector->IsActiveDirectoryManaged()) { + Value active_directory_info = GetIdentityFieldsFromPolicy( + connector->GetDeviceActiveDirectoryPolicyManager() + ->store() + ->policy()); + identity_fields.MergeDictionary(&active_directory_info); + } + + if (connector->IsCloudManaged()) { + Value cloud_info = GetIdentityFieldsFromPolicy( + connector->GetDeviceCloudPolicyManager()->device_store()->policy()); + identity_fields.MergeDictionary(&cloud_info); + } + } + return identity_fields; +} +#endif + +std::string PolicyConversions::ConvertValueToJSON(const Value& value) { + std::string json_string; + base::JSONWriter::WriteWithOptions( + value, + (pretty_print_enabled_ ? base::JSONWriter::OPTIONS_PRETTY_PRINT : 0), + &json_string); + return json_string; +} + +Value PolicyConversions::CopyAndMaybeConvert( + const Value& value, + const base::Optional<Schema>& schema) { + Value value_copy = value.Clone(); + if (schema.has_value()) + schema->MaskSensitiveValues(&value_copy); + if (!convert_values_enabled_) + return value_copy; + if (value_copy.is_dict()) + return Value(ConvertValueToJSON(value_copy)); + + if (!value_copy.is_list()) { + return value_copy; + } + + Value result(Value::Type::LIST); + for (const auto& element : value_copy.GetList()) { + if (element.is_dict()) { + result.GetList().emplace_back(Value(ConvertValueToJSON(element))); + } else { + result.GetList().push_back(element.Clone()); + } + } + return result; +} + +Value PolicyConversions::GetPolicyValue( const std::string& policy_name, const PolicyMap::Entry& policy, PolicyErrorMap* errors, - bool convert_values, - const base::Optional<PolicyToSchemaMap>& known_policy_schemas, - bool is_pretty_print, - bool convert_types) { + const base::Optional<PolicyToSchemaMap>& known_policy_schemas) { base::Optional<Schema> known_policy_schema = GetKnownPolicySchema(known_policy_schemas, policy_name); Value value(Value::Type::DICTIONARY); value.SetKey("value", - CopyAndMaybeConvert(*policy.value, convert_values, - known_policy_schema, is_pretty_print)); - if (convert_types) { + CopyAndMaybeConvert(*policy.value, known_policy_schema)); + if (convert_types_enabled_) { value.SetKey( "scope", Value((policy.scope == POLICY_SCOPE_USER) ? "user" : "machine")); @@ -194,8 +421,7 @@ Value conflict_values(Value::Type::LIST); for (const auto& conflict : policy.conflicts) { base::Value conflicted_policy_value = - GetPolicyValue(policy_name, conflict, errors, convert_values, - known_policy_schemas, is_pretty_print, convert_types); + GetPolicyValue(policy_name, conflict, errors, known_policy_schemas); conflict_values.GetList().push_back(std::move(conflicted_policy_value)); } @@ -205,396 +431,195 @@ return value; } -// Inserts a description of each policy in |map| into |values|, using the -// optional errors in |errors| to determine the status of each policy. If -// |convert_values| is true, converts the values to show them in javascript. -// |known_policy_schemas| contains |Schema|s for known policies in the same -// policy namespace of |map|. A policy in |map| but without an entry -// |known_policy_schemas| is an unknown policy. -void GetPolicyValues( +Value PolicyConversions::GetPolicyValues( const PolicyMap& map, PolicyErrorMap* errors, - bool with_user_policies, - bool convert_values, - const base::Optional<PolicyToSchemaMap>& known_policy_schemas, - Value* values, - bool is_pretty_print, - bool convert_types) { - DCHECK(values); + const base::Optional<PolicyToSchemaMap>& known_policy_schemas) { + base::Value values(base::Value::Type::DICTIONARY); for (const auto& entry : map) { const std::string& policy_name = entry.first; const PolicyMap::Entry& policy = entry.second; - if (policy.scope == POLICY_SCOPE_USER && !with_user_policies) + if (policy.scope == POLICY_SCOPE_USER && !user_policies_enabled_) continue; base::Value value = - GetPolicyValue(policy_name, policy, errors, convert_values, - known_policy_schemas, is_pretty_print, convert_types); - values->SetKey(policy_name, std::move(value)); + GetPolicyValue(policy_name, policy, errors, known_policy_schemas); + values.SetKey(policy_name, std::move(value)); } -} - -base::Optional<PolicyToSchemaMap> GetKnownPolicies( - const scoped_refptr<SchemaMap> schema_map, - const PolicyNamespace& policy_namespace, - bool is_pretty_print) { - const Schema* schema = schema_map->GetSchema(policy_namespace); - // There is no policy name verification without valid schema. - if (!schema || !schema->valid()) - return base::nullopt; - - // Build a vector first and construct the PolicyToSchemaMap (which is a - // |flat_map|) from that. The reason is that insertion into a |flat_map| is - // O(n), which would make the loop O(n^2), but constructing from a - // pre-populated vector is less expensive. - std::vector<std::pair<std::string, Schema>> policy_to_schema_entries; - for (auto it = schema->GetPropertiesIterator(); !it.IsAtEnd(); it.Advance()) { - policy_to_schema_entries.push_back(std::make_pair(it.key(), it.schema())); - } - return PolicyToSchemaMap(std::move(policy_to_schema_entries)); -} - -void GetChromePolicyValues(content::BrowserContext* context, - bool keep_user_policies, - bool convert_values, - Value* values, - bool is_pretty_print, - bool convert_types) { - PolicyService* policy_service = GetPolicyService(context); - PolicyMap map; - - Profile* profile = Profile::FromBrowserContext(context); - auto* schema_registry_service = profile->GetPolicySchemaRegistryService(); - if (!schema_registry_service || !schema_registry_service->registry()) { - LOG(ERROR) << "Can not dump extension policies, no schema registry service"; - return; - } - - const scoped_refptr<SchemaMap> schema_map = - schema_registry_service->registry()->schema_map(); - - PolicyNamespace policy_namespace = - PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()); - - // Make a copy that can be modified, since some policy values are modified - // before being displayed. - map.CopyFrom(policy_service->GetPolicies(policy_namespace)); - - // Get a list of all the errors in the policy values. - const ConfigurationPolicyHandlerList* handler_list = - g_browser_process->browser_policy_connector()->GetHandlerList(); - PolicyErrorMap errors; - handler_list->ApplyPolicySettings(map, NULL, &errors); - - // Convert dictionary values to strings for display. - handler_list->PrepareForDisplaying(&map); - - GetPolicyValues( - map, &errors, keep_user_policies, convert_values, - GetKnownPolicies(schema_map, policy_namespace, is_pretty_print), values, - is_pretty_print, convert_types); + return values; } #if defined(OS_CHROMEOS) -void GetDeviceLocalAccountPolicies(bool convert_values, - Value* values, - bool with_device_data, - bool is_pretty_print, - bool convert_types) { - // DeviceLocalAccount policies are only available for affiliated users and for - // system logs. - if (!with_device_data && - (!user_manager::UserManager::IsInitialized() || - !user_manager::UserManager::Get()->GetPrimaryUser() || - !user_manager::UserManager::Get()->GetPrimaryUser()->IsAffiliated())) { - return; - } - - BrowserPolicyConnectorChromeOS* connector = - g_browser_process->platform_part()->browser_policy_connector_chromeos(); - DCHECK(connector); // always not-null - - auto* device_local_account_policy_service = - connector->GetDeviceLocalAccountPolicyService(); - DCHECK(device_local_account_policy_service); // always non null for - // affiliated users - std::vector<DeviceLocalAccount> device_local_accounts = - GetDeviceLocalAccounts(chromeos::CrosSettings::Get()); - for (const auto& account : device_local_accounts) { - std::string user_id = account.user_id; - Value current_account_policies(Value::Type::DICTIONARY); - - auto* device_local_account_policy_broker = - device_local_account_policy_service->GetBrokerForUser(user_id); - if (!device_local_account_policy_broker) { - LOG(ERROR) - << "Can not get policy broker for device local account with user id: " - << user_id; - continue; - } - - auto* cloud_policy_core = device_local_account_policy_broker->core(); - DCHECK(cloud_policy_core); - auto* cloud_policy_store = cloud_policy_core->store(); - DCHECK(cloud_policy_store); - - const scoped_refptr<SchemaMap> schema_map = - device_local_account_policy_broker->schema_registry()->schema_map(); - - PolicyNamespace policy_namespace = - PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()); - - // Make a copy that can be modified, since some policy values are modified - // before being displayed. - PolicyMap map; - map.CopyFrom(cloud_policy_store->policy_map()); - - // Get a list of all the errors in the policy values. - const ConfigurationPolicyHandlerList* handler_list = - connector->GetHandlerList(); - PolicyErrorMap errors; - handler_list->ApplyPolicySettings(map, NULL, &errors); - - // Convert dictionary values to strings for display. - handler_list->PrepareForDisplaying(&map); - - GetPolicyValues( - map, &errors, true, convert_values, - GetKnownPolicies(schema_map, policy_namespace, is_pretty_print), - ¤t_account_policies, is_pretty_print, convert_types); - - if (values->is_list()) { - Value current_account_policies_data(Value::Type::DICTIONARY); - current_account_policies_data.SetKey("id", Value(user_id)); - current_account_policies_data.SetKey("user_id", Value(user_id)); - current_account_policies_data.SetKey("name", Value(user_id)); - current_account_policies_data.SetKey("policies", - std::move(current_account_policies)); - values->GetList().push_back(std::move(current_account_policies_data)); - } else { - values->SetKey(user_id, std::move(current_account_policies)); - } - } -} -#endif // defined(OS_CHROMEOS) - -} // namespace - -const LocalizedString kPolicySources[POLICY_SOURCE_COUNT] = { - {"sourceEnterpriseDefault", IDS_POLICY_SOURCE_ENTERPRISE_DEFAULT}, - {"cloud", IDS_POLICY_SOURCE_CLOUD}, - {"sourceActiveDirectory", IDS_POLICY_SOURCE_ACTIVE_DIRECTORY}, - {"sourceDeviceLocalAccountOverride", - IDS_POLICY_SOURCE_DEVICE_LOCAL_ACCOUNT_OVERRIDE}, - {"platform", IDS_POLICY_SOURCE_PLATFORM}, - {"priorityCloud", IDS_POLICY_SOURCE_CLOUD}, - {"merged", IDS_POLICY_SOURCE_MERGED}, -}; - -Value GetAllPolicyValuesAsArray(content::BrowserContext* context, - bool with_user_policies, - bool convert_values, - bool with_device_data, - bool is_pretty_print, - bool convert_types) { - Value all_policies(Value::Type::LIST); - DCHECK(context); - - context = chrome::GetBrowserContextRedirectedInIncognito(context); - - // Add Chrome policy values. - Value chrome_policies(Value::Type::DICTIONARY); - GetChromePolicyValues(context, with_user_policies, convert_values, - &chrome_policies, is_pretty_print, convert_types); - Value chrome_policies_data(Value::Type::DICTIONARY); - chrome_policies_data.SetKey("name", Value("Chrome Policies")); - chrome_policies_data.SetKey("policies", std::move(chrome_policies)); - - all_policies.GetList().push_back(std::move(chrome_policies_data)); - -#if BUILDFLAG(ENABLE_EXTENSIONS) - // Add extension policy values. - extensions::ExtensionRegistry* registry = - extensions::ExtensionRegistry::Get(Profile::FromBrowserContext(context)); - if (!registry) { - LOG(ERROR) << "Can not dump extension policies, no extension registry"; - return all_policies; - } - Profile* profile = Profile::FromBrowserContext(context); - auto* schema_registry_service = profile->GetPolicySchemaRegistryService(); - if (!schema_registry_service || !schema_registry_service->registry()) { - LOG(ERROR) << "Can not dump extension policies, no schema registry service"; - return all_policies; - } - const scoped_refptr<SchemaMap> schema_map = - schema_registry_service->registry()->schema_map(); - for (const scoped_refptr<const extensions::Extension>& extension : - registry->enabled_extensions()) { - // Skip this extension if it's not an enterprise extension. - if (!extension->manifest()->HasPath( - extensions::manifest_keys::kStorageManagedSchema)) { - continue; - } - - Value extension_policies(Value::Type::DICTIONARY); - PolicyNamespace policy_namespace = - PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, extension->id()); - PolicyErrorMap empty_error_map; - GetPolicyValues( - GetPolicyService(context)->GetPolicies(policy_namespace), - &empty_error_map, with_user_policies, convert_values, - GetKnownPolicies(schema_map, policy_namespace, is_pretty_print), - &extension_policies, is_pretty_print, convert_types); - Value extension_policies_data(Value::Type::DICTIONARY); - extension_policies_data.SetKey("name", Value(extension->name())); - extension_policies_data.SetKey("id", Value(extension->id())); - extension_policies_data.SetKey("policies", std::move(extension_policies)); - all_policies.GetList().push_back(std::move(extension_policies_data)); - } -#endif - -#if defined(OS_CHROMEOS) - Value device_local_account_policies(Value::Type::DICTIONARY); - GetDeviceLocalAccountPolicies(convert_values, &all_policies, with_device_data, - is_pretty_print, convert_types); -#endif // defined(OS_CHROMEOS) - - return all_policies; -} - -Value GetAllPolicyValuesAsDictionary(content::BrowserContext* context, - bool with_user_policies, - bool convert_values, - bool with_device_data, - bool is_pretty_print, - bool convert_types) { - Value all_policies(Value::Type::DICTIONARY); - if (!context) { - LOG(ERROR) << "Can not dump policies, null context"; - return all_policies; - } - - context = chrome::GetBrowserContextRedirectedInIncognito(context); - - // Add Chrome policy values. - Value chrome_policies(Value::Type::DICTIONARY); - GetChromePolicyValues(context, with_user_policies, convert_values, - &chrome_policies, is_pretty_print, convert_types); - all_policies.SetKey("chromePolicies", std::move(chrome_policies)); - -#if BUILDFLAG(ENABLE_EXTENSIONS) - // Add extension policy values. - extensions::ExtensionRegistry* registry = - extensions::ExtensionRegistry::Get(Profile::FromBrowserContext(context)); - if (!registry) { - LOG(ERROR) << "Can not dump extension policies, no extension registry"; - return all_policies; - } - Value extension_values(Value::Type::DICTIONARY); - Profile* profile = Profile::FromBrowserContext(context); - auto* schema_registry_service = profile->GetPolicySchemaRegistryService(); - if (!schema_registry_service || !schema_registry_service->registry()) { - LOG(ERROR) << "Can not dump extension policies, no schema registry service"; - return all_policies; - } - const scoped_refptr<SchemaMap> schema_map = - schema_registry_service->registry()->schema_map(); - for (const scoped_refptr<const extensions::Extension>& extension : - registry->enabled_extensions()) { - // Skip this extension if it's not an enterprise extension. - if (!extension->manifest()->HasPath( - extensions::manifest_keys::kStorageManagedSchema)) - continue; - Value extension_policies(Value::Type::DICTIONARY); - PolicyNamespace policy_namespace = - PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, extension->id()); - PolicyErrorMap empty_error_map; - GetPolicyValues( - GetPolicyService(context)->GetPolicies(policy_namespace), - &empty_error_map, with_user_policies, convert_values, - GetKnownPolicies(schema_map, policy_namespace, is_pretty_print), - &extension_policies, is_pretty_print, convert_types); - extension_values.SetKey(extension->id(), std::move(extension_policies)); - } - all_policies.SetKey("extensionPolicies", std::move(extension_values)); -#endif - -#if defined(OS_CHROMEOS) - Value device_local_account_policies(Value::Type::DICTIONARY); - GetDeviceLocalAccountPolicies(convert_values, &device_local_account_policies, - with_device_data, is_pretty_print, - convert_types); - all_policies.SetKey("deviceLocalAccountPolicies", - std::move(device_local_account_policies)); -#endif // defined(OS_CHROMEOS) - - if (with_device_data) - FillIdentityFields(&all_policies); - - return all_policies; -} - -#if defined(OS_CHROMEOS) -void FillIdentityFieldsFromPolicy(const em::PolicyData* policy, - Value* policy_dump) { +Value PolicyConversions::GetIdentityFieldsFromPolicy( + const em::PolicyData* policy) { + Value identity_fields(Value::Type::DICTIONARY); if (!policy) { - return; + return identity_fields; } - DCHECK(policy_dump); if (policy->has_device_id()) - policy_dump->SetKey("client_id", Value(policy->device_id())); + identity_fields.SetKey("client_id", Value(policy->device_id())); - if (policy->has_annotated_location()) - policy_dump->SetKey("device_location", Value(policy->annotated_location())); + if (policy->has_annotated_location()) { + identity_fields.SetKey("device_location", + Value(policy->annotated_location())); + } if (policy->has_annotated_asset_id()) - policy_dump->SetKey("asset_id", Value(policy->annotated_asset_id())); + identity_fields.SetKey("asset_id", Value(policy->annotated_asset_id())); if (policy->has_display_domain()) - policy_dump->SetKey("display_domain", Value(policy->display_domain())); + identity_fields.SetKey("display_domain", Value(policy->display_domain())); if (policy->has_machine_name()) - policy_dump->SetKey("machine_name", Value(policy->machine_name())); + identity_fields.SetKey("machine_name", Value(policy->machine_name())); + + return identity_fields; } + #endif // defined(OS_CHROMEOS) -void FillIdentityFields(Value* policy_dump) { +/** + * DictionaryPolicyConversions + */ + +DictionaryPolicyConversions::DictionaryPolicyConversions() = default; +DictionaryPolicyConversions::~DictionaryPolicyConversions() = default; + +Value DictionaryPolicyConversions::ToValue() { + Value all_policies(Value::Type::DICTIONARY); + + if (profile()) { + all_policies.SetKey("chromePolicies", GetChromePolicies()); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + all_policies.SetKey("extensionPolicies", GetExtensionsPolicies()); +#endif + } + #if defined(OS_CHROMEOS) - DCHECK(policy_dump); - BrowserPolicyConnectorChromeOS* connector = - g_browser_process->platform_part()->browser_policy_connector_chromeos(); - if (!connector) { - LOG(ERROR) << "Can not dump identity fields, no policy connector"; - return; - } - if (connector->IsEnterpriseManaged()) { - policy_dump->SetKey("enrollment_domain", - Value(connector->GetEnterpriseEnrollmentDomain())); - - if (connector->IsActiveDirectoryManaged()) { - FillIdentityFieldsFromPolicy( - connector->GetDeviceActiveDirectoryPolicyManager()->store()->policy(), - policy_dump); - } - - if (connector->IsCloudManaged()) { - FillIdentityFieldsFromPolicy( - connector->GetDeviceCloudPolicyManager()->device_store()->policy(), - policy_dump); - } - } + all_policies.SetKey("deviceLocalAccountPolicies", + GetDeviceLocalAccountPolicies()); + Value identity_fields = GetIdentityFields(); + if (!identity_fields.is_none()) + all_policies.MergeDictionary(&identity_fields); #endif // defined(OS_CHROMEOS) + return all_policies; +} + +#if defined(OS_CHROMEOS) +Value DictionaryPolicyConversions::GetDeviceLocalAccountPolicies() { + Value policies = PolicyConversions::GetDeviceLocalAccountPolicies(); + Value device_values(Value::Type::DICTIONARY); + for (auto&& policy : policies.GetList()) { + device_values.SetKey(policy.FindKey("id")->GetString(), + std::move(*policy.FindKey("policies"))); + } + return device_values; +} +#endif + +Value DictionaryPolicyConversions::GetExtensionsPolicies() { + Value policies = PolicyConversions::GetExtensionsPolicies(); + Value extension_values(Value::Type::DICTIONARY); + for (auto&& policy : policies.GetList()) { + extension_values.SetKey(policy.FindKey("id")->GetString(), + std::move(*policy.FindKey("policies"))); + } + return extension_values; +} + +/** + * ArrayPolicyConversions + */ + +ArrayPolicyConversions::ArrayPolicyConversions() = default; +ArrayPolicyConversions::~ArrayPolicyConversions() = default; + +Value ArrayPolicyConversions::ToValue() { + Value all_policies(Value::Type::LIST); + + if (profile()) { + all_policies.GetList().push_back(GetChromePolicies()); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + Value extension_policies = GetExtensionsPolicies(); + all_policies.GetList().insert( + all_policies.GetList().end(), + std::make_move_iterator(extension_policies.GetList().begin()), + std::make_move_iterator(extension_policies.GetList().end())); +#endif + } + +#if defined(OS_CHROMEOS) + Value device_policeis = GetDeviceLocalAccountPolicies(); + all_policies.GetList().insert( + all_policies.GetList().end(), + std::make_move_iterator(device_policeis.GetList().begin()), + std::make_move_iterator(device_policeis.GetList().end())); + + Value identity_fields = GetIdentityFields(); + if (!identity_fields.is_none()) + all_policies.GetList().push_back(std::move(identity_fields)); +#endif // defined(OS_CHROMEOS) + + return all_policies; +} + +Value ArrayPolicyConversions::GetChromePolicies() { + Value chrome_policies_data(Value::Type::DICTIONARY); + chrome_policies_data.SetKey("name", Value("Chrome Policies")); + chrome_policies_data.SetKey("policies", + PolicyConversions::GetChromePolicies()); + return chrome_policies_data; +} + +base::Value GetAllPolicyValuesAsArray(content::BrowserContext* context, + bool with_user_policies, + bool convert_values, + bool with_device_data, + bool is_pretty_print, + bool convert_types) { + return ArrayPolicyConversions() + .WithBrowserContext(context) + .EnableConvertTypes(convert_types) + .EnableConvertValues(convert_values) + .EnableDevicePolicies(with_device_data) + .EnableDeviceInfo(false) + .EnablePrettyPrint(is_pretty_print) + .EnableUserPolicies(with_user_policies) + .ToValue(); +} + +base::Value GetAllPolicyValuesAsDictionary(content::BrowserContext* context, + bool with_user_policies, + bool convert_values, + bool with_device_data, + bool is_pretty_print, + bool convert_types) { + return DictionaryPolicyConversions() + .WithBrowserContext(context) + .EnableConvertTypes(convert_types) + .EnableConvertValues(convert_values) + .EnableDevicePolicies(with_device_data) + .EnableDeviceInfo(with_device_data) + .EnablePrettyPrint(is_pretty_print) + .EnableUserPolicies(with_user_policies) + .ToValue(); } std::string GetAllPolicyValuesAsJSON(content::BrowserContext* context, bool with_user_policies, bool with_device_data, bool is_pretty_print) { - Value all_policies = GetAllPolicyValuesAsDictionary( - context, with_user_policies, false /* convert_values */, with_device_data, - is_pretty_print, true /* convert_types */); - - return DictionaryToJSONString(all_policies, is_pretty_print); + return DictionaryPolicyConversions() + .WithBrowserContext(context) + .EnableConvertTypes(true) + .EnableConvertValues(false) + .EnableDevicePolicies(with_device_data) + .EnableDeviceInfo(with_device_data) + .EnablePrettyPrint(is_pretty_print) + .EnableUserPolicies(with_user_policies) + .ToJSON(); } } // namespace policy
diff --git a/chrome/browser/policy/policy_conversions.h b/chrome/browser/policy/policy_conversions.h index f1e3b1ff..1204d2f 100644 --- a/chrome/browser/policy/policy_conversions.h +++ b/chrome/browser/policy/policy_conversions.h
@@ -10,23 +10,161 @@ #include "base/values.h" #include "chrome/browser/ui/webui/localized_string.h" +#include "components/policy/core/common/policy_map.h" #include "components/policy/core/common/policy_types.h" +class Profile; + namespace content { class BrowserContext; } // namespace content +namespace enterprise_management { +class PolicyData; +} + namespace policy { -// TODO(crbug.com/983174): Refactor the file as these functions have too many -// parameters. +class PolicyErrorMap; +class Schema; extern const LocalizedString kPolicySources[POLICY_SOURCE_COUNT]; +// A convenience class to retrieve all policies values. +class PolicyConversions { + public: + // Maps known policy names to their schema. If a policy is not present, it is + // not known (either through policy_templates.json or through an extenion's + // managed storage schema). + using PolicyToSchemaMap = base::flat_map<std::string, Schema>; + + PolicyConversions(); + virtual ~PolicyConversions(); + + // Set to get Chrome and extension policies. + PolicyConversions& WithBrowserContext(content::BrowserContext* context); + // Set to get policy types as human friendly string instead of enum integer. + // Policy types includes policy source, policy scope and policy level. + // Enabled by default. + PolicyConversions& EnableConvertTypes(bool enabled); + // Set to get dictionary policy value as JSON string. + // Disabled by default. + PolicyConversions& EnableConvertValues(bool enabled); + // Set to get device policies on ChromeOS. + // Disabled by default. + PolicyConversions& EnableDevicePolicies(bool enabled); + // Set to get device basic information on ChromeOS. + // Disabled by default. + PolicyConversions& EnableDeviceInfo(bool enabled); + // Set to enable pretty print for all JSON string. + // Enabled by default. + PolicyConversions& EnablePrettyPrint(bool enabled); + // Set to get all user scope policies. + // Enabled by default. + PolicyConversions& EnableUserPolicies(bool enabled); + + // Returns the policy data as a base::Value object. + virtual base::Value ToValue() = 0; + + // Returns the policy data as a JSON string; + virtual std::string ToJSON(); + + protected: + const Profile* profile() const { return profile_; } + + // Returns policies for Chrome browser. + virtual base::Value GetChromePolicies(); + // Returns policies for Chrome extensions. + virtual base::Value GetExtensionsPolicies(); +#if defined(OS_CHROMEOS) + // Returns policies for ChromeOS device. + virtual base::Value GetDeviceLocalAccountPolicies(); + // Returns device specific information if this device is enterprise managed. + virtual base::Value GetIdentityFields(); +#endif + + std::string ConvertValueToJSON(const base::Value& value); + + private: + // Returns a copy of |value|. If necessary (which is specified by + // |convert_values_enabled_|), converts some values to a representation that + // i18n_template.js will display. + base::Value CopyAndMaybeConvert(const base::Value& value, + const base::Optional<Schema>& schema); + + // Creates a description of the policy |policy_name| using |policy| and the + // optional errors in |errors| to determine the status of each policy. + // |known_policy_schemas| contains |Schema|s for known policies in the same + // policy namespace of |map|. A policy without an entry in + // |known_policy_schemas| is an unknown policy. + base::Value GetPolicyValue( + const std::string& policy_name, + const PolicyMap::Entry& policy, + PolicyErrorMap* errors, + const base::Optional<PolicyToSchemaMap>& known_policy_schemas); + + // Returns a description of each policy in |map| as Value, using the + // optional errors in |errors| to determine the status of each policy. + // |known_policy_schemas| contains |Schema|s for known policies in the same + // policy namespace of |map|. A policy in |map| but without an entry + // |known_policy_schemas| is an unknown policy. + base::Value GetPolicyValues( + const PolicyMap& map, + PolicyErrorMap* errors, + const base::Optional<PolicyToSchemaMap>& known_policy_schemas); + +#if defined(OS_CHROMEOS) + base::Value GetIdentityFieldsFromPolicy( + const enterprise_management::PolicyData* policy); +#endif + + Profile* profile_; + + bool convert_types_enabled_ = true; + bool convert_values_enabled_ = false; + bool device_policies_enabled_ = false; + bool device_info_enabled_ = false; + bool pretty_print_enabled_ = true; + bool user_policies_enabled_ = true; + + DISALLOW_COPY_AND_ASSIGN(PolicyConversions); +}; + +class DictionaryPolicyConversions : public PolicyConversions { + public: + DictionaryPolicyConversions(); + ~DictionaryPolicyConversions() override; + + base::Value ToValue() override; + + private: + base::Value GetExtensionsPolicies() override; + +#if defined(OS_CHROMEOS) + base::Value GetDeviceLocalAccountPolicies() override; +#endif + + DISALLOW_COPY_AND_ASSIGN(DictionaryPolicyConversions); +}; + +class ArrayPolicyConversions : public PolicyConversions { + public: + ArrayPolicyConversions(); + ~ArrayPolicyConversions() override; + + base::Value ToValue() override; + + private: + base::Value GetChromePolicies() override; + + DISALLOW_COPY_AND_ASSIGN(ArrayPolicyConversions); +}; + // Returns an array with the values of all set policies, with some values // converted to be shown in javascript, if it is specified. // |with_user_policies| governs if values with POLICY_SCOPE_USER are included. // |convert_types| governs if policy types are returned as string. +// DEPRECATED, use ArrayPolicyConversions::ToValue() instead. base::Value GetAllPolicyValuesAsArray(content::BrowserContext* context, bool with_user_policies, bool convert_values, @@ -42,6 +180,7 @@ // it is used in logs uploads to the server. // |is_pretty_print| governs if JSON policy value is pretty printed. // |convert_types| governs if policy types are returned as string. +// DEPRECATED, use DictionaryPolicyConversions::ToValue() instead. base::Value GetAllPolicyValuesAsDictionary(content::BrowserContext* context, bool with_user_policies, bool convert_values, @@ -55,6 +194,7 @@ // enrollment client ID) and device local accounts policies are included, // it is used in logs uploads to the server. // |is_pretty_print| governs if the output is formatted. +// DEPRECATED, use DictionaryPolicyConversions::ToJSON() instead. std::string GetAllPolicyValuesAsJSON(content::BrowserContext* context, bool with_user_policies, bool with_device_data,
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 17f773f..a76821e 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/accessibility/accessibility_labels_service.h" #include "chrome/browser/accessibility/accessibility_ui.h" #include "chrome/browser/accessibility/invert_bubble_prefs.h" +#include "chrome/browser/availability/availability_prober.h" #include "chrome/browser/browser_process_impl.h" #include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/chromeos/policy/tpm_auto_update_mode_policy_handler.h" @@ -51,7 +52,6 @@ #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/previews/previews_lite_page_decider.h" #include "chrome/browser/previews/previews_offline_helper.h" -#include "chrome/browser/previews/previews_prober.h" #include "chrome/browser/profiles/chrome_version_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_attributes_entry.h" @@ -691,6 +691,7 @@ // User prefs. Please keep this list alphabetized. AccessibilityLabelsService::RegisterProfilePrefs(registry); AccessibilityUIMessageHandler::RegisterProfilePrefs(registry); + AvailabilityProber::RegisterProfilePrefs(registry); autofill::prefs::RegisterProfilePrefs(registry); browsing_data::prefs::RegisterBrowserUserPrefs(registry); certificate_transparency::prefs::RegisterPrefs(registry); @@ -733,7 +734,6 @@ PrefsTabHelper::RegisterProfilePrefs(registry, locale); PreviewsLitePageDecider::RegisterProfilePrefs(registry); PreviewsOfflineHelper::RegisterProfilePrefs(registry); - PreviewsProber::RegisterProfilePrefs(registry); Profile::RegisterProfilePrefs(registry); ProfileImpl::RegisterProfilePrefs(registry); ProfileNetworkContextService::RegisterProfilePrefs(registry); @@ -1099,4 +1099,5 @@ // Added 7/2019. syncer::MigrateSyncSuppressedPref(profile_prefs); profile_prefs->ClearPref(kSignedInTime); + syncer::ClearObsoleteMemoryPressurePrefs(profile_prefs); }
diff --git a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc index 3c2845c..b03ff9c02 100644 --- a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc +++ b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
@@ -130,10 +130,16 @@ ->GetAppCacheService(); do { base::RunLoop wait_loop; - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::IO}, - base::BindOnce(WaitForAppcacheOnIO, manifest_url, appcache_service, - wait_loop.QuitClosure(), &found_manifest)); + if (base::FeatureList::IsEnabled(features::kNavigationLoaderOnUI)) { + WaitForAppcacheOnLoaderThread(manifest_url, appcache_service, + base::DoNothing(), &found_manifest); + } else { + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::IO}, + base::BindOnce(WaitForAppcacheOnLoaderThread, manifest_url, + appcache_service, wait_loop.QuitClosure(), + &found_manifest)); + } // There seems to be some flakiness in the appcache getting back to us, so // use a timeout task to try the appcache query again. base::PostDelayedTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, @@ -179,10 +185,11 @@ // |found_manifest| if an appcache exists for |manifest_url|. |callback| will // be called on the UI thread after the info is retrieved, whether or not the // manifest exists. - static void WaitForAppcacheOnIO(const GURL& manifest_url, - content::AppCacheService* appcache_service, - base::Closure callback, - bool* found_manifest) { + static void WaitForAppcacheOnLoaderThread( + const GURL& manifest_url, + content::AppCacheService* appcache_service, + base::Closure callback, + bool* found_manifest) { scoped_refptr<content::AppCacheInfoCollection> info_collection = new content::AppCacheInfoCollection(); appcache_service->GetAllAppCacheInfo(
diff --git a/chrome/browser/previews/previews_prober_browsertest.cc b/chrome/browser/previews/previews_prober_browsertest.cc deleted file mode 100644 index dd16b80..0000000 --- a/chrome/browser/previews/previews_prober_browsertest.cc +++ /dev/null
@@ -1,177 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <string> - -#include "base/bind.h" -#include "base/command_line.h" -#include "base/run_loop.h" -#include "build/build_config.h" -#include "chrome/browser/previews/previews_prober.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/browser.h" -#include "chrome/test/base/in_process_browser_test.h" -#include "content/public/browser/network_service_instance.h" -#include "content/public/browser/system_connector.h" -#include "content/public/common/network_service_util.h" -#include "content/public/common/service_names.mojom.h" -#include "content/public/test/network_connection_change_simulator.h" -#include "net/test/embedded_test_server/embedded_test_server.h" -#include "net/test/embedded_test_server/http_request.h" -#include "net/test/embedded_test_server/http_response.h" -#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" -#include "services/network/public/mojom/network_service_test.mojom.h" -#include "services/service_manager/public/cpp/connector.h" - -namespace { - -void WaitForCompletedProbe(PreviewsProber* prober) { - while (true) { - if (prober->LastProbeWasSuccessful().has_value()) - return; - base::RunLoop().RunUntilIdle(); - } -} - -} // namespace - -class TestDelegate : public PreviewsProber::Delegate { - public: - TestDelegate() = default; - ~TestDelegate() = default; - - bool ShouldSendNextProbe() override { return should_send_next_probe_; } - - bool IsResponseSuccess(net::Error net_error, - const network::ResourceResponseHead& head, - std::unique_ptr<std::string> body) override { - return net_error == net::OK && - head.headers->response_code() == net::HTTP_OK; - } - - void set_should_send_next_probe(bool should_send_next_probe) { - should_send_next_probe_ = should_send_next_probe; - } - - private: - bool should_send_next_probe_ = true; -}; - -class PreviewsProberBrowserTest : public InProcessBrowserTest { - public: - PreviewsProberBrowserTest() = default; - ~PreviewsProberBrowserTest() override = default; - - void SetUpOnMainThread() override { - https_server_.reset( - new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS)); - https_server_->RegisterRequestHandler(base::BindRepeating( - &PreviewsProberBrowserTest::HandleRequest, base::Unretained(this))); - ASSERT_TRUE(https_server_->Start()); - } - - void SetUpCommandLine(base::CommandLine* cmd) override { - cmd->AppendSwitchASCII("host-rules", "MAP * 127.0.0.1"); - } - - void TearDownOnMainThread() override { - EXPECT_TRUE(https_server_->ShutdownAndWaitUntilComplete()); - InProcessBrowserTest::TearDownOnMainThread(); - } - - GURL TestURLWithPath(const std::string& path) const { - return https_server_->GetURL("test.com", path); - } - - private: - std::unique_ptr<net::test_server::HttpResponse> HandleRequest( - const net::test_server::HttpRequest& request) { - std::string path = request.GetURL().path(); - if (path == "/ok") { - std::unique_ptr<net::test_server::BasicHttpResponse> response = - std::make_unique<net::test_server::BasicHttpResponse>(); - response->set_code(net::HTTP_OK); - return response; - } - - if (path == "/timeout") { - std::unique_ptr<net::test_server::HungResponse> response = - std::make_unique<net::test_server::HungResponse>(); - return response; - } - - NOTREACHED() << path << " is not handled"; - return nullptr; - } - - std::unique_ptr<net::EmbeddedTestServer> https_server_; - - DISALLOW_COPY_AND_ASSIGN(PreviewsProberBrowserTest); -}; - -IN_PROC_BROWSER_TEST_F(PreviewsProberBrowserTest, OK) { - GURL url = TestURLWithPath("/ok"); - TestDelegate delegate; - net::HttpRequestHeaders headers; - PreviewsProber::RetryPolicy retry_policy; - PreviewsProber::TimeoutPolicy timeout_policy; - - PreviewsProber prober(&delegate, browser()->profile()->GetURLLoaderFactory(), - browser()->profile()->GetPrefs(), - PreviewsProber::ClientName::kLitepages, url, - PreviewsProber::HttpMethod::kGet, headers, retry_policy, - timeout_policy, TRAFFIC_ANNOTATION_FOR_TESTS, 1, - base::TimeDelta::FromDays(1)); - prober.SendNowIfInactive(false); - WaitForCompletedProbe(&prober); - - EXPECT_TRUE(prober.LastProbeWasSuccessful().value()); -} - -IN_PROC_BROWSER_TEST_F(PreviewsProberBrowserTest, Timeout) { - GURL url = TestURLWithPath("/timeout"); - TestDelegate delegate; - net::HttpRequestHeaders headers; - - PreviewsProber::RetryPolicy retry_policy; - retry_policy.max_retries = 0; - - PreviewsProber::TimeoutPolicy timeout_policy; - timeout_policy.base_timeout = base::TimeDelta::FromMilliseconds(1); - - PreviewsProber prober(&delegate, browser()->profile()->GetURLLoaderFactory(), - browser()->profile()->GetPrefs(), - PreviewsProber::ClientName::kLitepages, url, - PreviewsProber::HttpMethod::kGet, headers, retry_policy, - timeout_policy, TRAFFIC_ANNOTATION_FOR_TESTS, 1, - base::TimeDelta::FromDays(1)); - prober.SendNowIfInactive(false); - WaitForCompletedProbe(&prober); - - EXPECT_FALSE(prober.LastProbeWasSuccessful().value()); -} - -IN_PROC_BROWSER_TEST_F(PreviewsProberBrowserTest, NetworkChange) { - content::NetworkConnectionChangeSimulator().SetConnectionType( - network::mojom::ConnectionType::CONNECTION_2G); - - GURL url = TestURLWithPath("/ok"); - TestDelegate delegate; - net::HttpRequestHeaders headers; - PreviewsProber::RetryPolicy retry_policy; - PreviewsProber::TimeoutPolicy timeout_policy; - - PreviewsProber prober(&delegate, browser()->profile()->GetURLLoaderFactory(), - browser()->profile()->GetPrefs(), - PreviewsProber::ClientName::kLitepages, url, - PreviewsProber::HttpMethod::kGet, headers, retry_policy, - timeout_policy, TRAFFIC_ANNOTATION_FOR_TESTS, 1, - base::TimeDelta::FromDays(1)); - - content::NetworkConnectionChangeSimulator().SetConnectionType( - network::mojom::ConnectionType::CONNECTION_4G); - WaitForCompletedProbe(&prober); - - EXPECT_TRUE(prober.LastProbeWasSuccessful().value()); -}
diff --git a/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc b/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc index d76f910..2e86b5f 100644 --- a/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc +++ b/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
@@ -15,7 +15,7 @@ #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_pump.h" #include "base/process/kill.h" #include "base/process/process.h" #include "base/rand_util.h" @@ -24,6 +24,7 @@ #include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/task/post_task.h" +#include "base/task/single_thread_task_executor.h" #include "base/test/multiprocess_test.h" #include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" @@ -184,7 +185,7 @@ // determine the failure. int CloudPrintMockService_Main(SetExpectationsCallback set_expectations) { base::PlatformThread::SetName("Main Thread"); - base::MessageLoopForUI main_message_loop; + base::SingleThreadTaskExecutor executor(base::MessagePump::Type::UI); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); content::RegisterPathProvider(); @@ -200,7 +201,7 @@ base::FilePath executable_path = command_line->GetSwitchValuePath(kTestExecutablePath); EXPECT_FALSE(executable_path.empty()); - MockLaunchd mock_launchd(executable_path, main_message_loop.task_runner(), + MockLaunchd mock_launchd(executable_path, executor.task_runner(), run_loop.QuitClosure(), true); Launchd::ScopedInstance use_mock(&mock_launchd); #endif
diff --git a/chrome/browser/profile_resetter/triggered_profile_resetter_win.cc b/chrome/browser/profile_resetter/triggered_profile_resetter_win.cc index c52eb7c4..e3f4155 100644 --- a/chrome/browser/profile_resetter/triggered_profile_resetter_win.cc +++ b/chrome/browser/profile_resetter/triggered_profile_resetter_win.cc
@@ -9,13 +9,14 @@ #include "base/metrics/field_trial.h" #include "base/metrics/histogram_macros.h" #include "base/win/registry.h" +#include "build/branding_buildflags.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" #include "components/prefs/pref_service.h" #if defined(GOOGLE_CHROME_BUILD) #define PRODUCT_NAME L"Google\\Chrome" -#elif defined(CHROMIUM_BUILD) +#elif BUILDFLAG(CHROMIUM_BRANDING) #define PRODUCT_NAME L"Chromium" #else #error Unknown branding
diff --git a/chrome/browser/profiles/profile_attributes_storage_unittest.cc b/chrome/browser/profiles/profile_attributes_storage_unittest.cc index d167180..befdeca 100644 --- a/chrome/browser/profiles/profile_attributes_storage_unittest.cc +++ b/chrome/browser/profiles/profile_attributes_storage_unittest.cc
@@ -493,12 +493,14 @@ ASSERT_FALSE(entry->IsChild()); ASSERT_TRUE(entry->IsLegacySupervised()); +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) EXPECT_CALL(observer(), OnProfileSupervisedUserIdChanged(path)).Times(1); entry->SetSupervisedUserId(supervised_users::kChildAccountSUID); VerifyAndResetCallExpectations(); ASSERT_TRUE(entry->IsSupervised()); ASSERT_TRUE(entry->IsChild()); ASSERT_FALSE(entry->IsLegacySupervised()); +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) } TEST_F(ProfileAttributesStorageTest, ReSortTriggered) {
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 17a23f76..084648e 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc
@@ -232,6 +232,7 @@ #include "extensions/browser/extension_pref_store.h" #include "extensions/browser/extension_pref_value_map.h" #include "extensions/browser/extension_pref_value_map_factory.h" +#include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_system.h" #endif @@ -951,6 +952,12 @@ if (g_browser_process->local_state()) MigrateObsoleteBrowserPrefs(this, g_browser_process->local_state()); MigrateObsoleteProfilePrefs(this); +#if BUILDFLAG(ENABLE_EXTENSIONS) + // Note: Extension preferences can be keyed off the extension ID, so need to + // be handled specially (rather than directly as part of + // MigrateObsoleteProfilePrefs()). + extensions::ExtensionPrefs::Get(this)->MigrateObsoleteExtensionPrefs(); +#endif // |kSessionExitType| was added after |kSessionExitedCleanly|. If the pref // value is empty fallback to checking for |kSessionExitedCleanly|.
diff --git a/chrome/browser/profiles/profile_info_cache_unittest.cc b/chrome/browser/profiles/profile_info_cache_unittest.cc index a3d4c62..3266a24 100644 --- a/chrome/browser/profiles/profile_info_cache_unittest.cc +++ b/chrome/browser/profiles/profile_info_cache_unittest.cc
@@ -167,8 +167,13 @@ EXPECT_EQ(icon->width(), actual_icon->width()); EXPECT_EQ(icon->height(), actual_icon->height()); #endif +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) EXPECT_EQ(i == 3, GetCache()->ProfileIsSupervisedAtIndex(i)); EXPECT_EQ(i == 3, GetCache()->IsOmittedProfileAtIndex(i)); +#else + EXPECT_FALSE(GetCache()->ProfileIsSupervisedAtIndex(i)); + EXPECT_FALSE(GetCache()->IsOmittedProfileAtIndex(i)); +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) EXPECT_EQ(supervised_user_id, GetCache()->GetSupervisedUserIdOfProfileAtIndex(i)); }
diff --git a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc index 61aec11..e91b613 100644 --- a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc +++ b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
@@ -199,13 +199,13 @@ // Posts a task to call ShellUtil::CreateOrUpdateShortcut on the COM thread. void PostCreateOrUpdateShortcut( const base::Location& location, + ShellUtil::ShortcutLocation shortcut_location, const ShellUtil::ShortcutProperties& properties) { base::PostTaskAndReplyWithResult( base::CreateCOMSTATaskRunnerWithTraits({base::MayBlock()}).get(), location, - base::Bind(&ShellUtil::CreateOrUpdateShortcut, - ShellUtil::SHORTCUT_LOCATION_DESKTOP, properties, - ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS), + base::Bind(&ShellUtil::CreateOrUpdateShortcut, shortcut_location, + properties, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS), base::Bind([](bool succeeded) { EXPECT_TRUE(succeeded); })); thread_bundle_.RunUntilIdle(); } @@ -222,7 +222,8 @@ ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER); ShellUtil::AddDefaultShortcutProperties(GetExePath(), &properties); properties.set_shortcut_name(shortcut_name); - PostCreateOrUpdateShortcut(location, properties); + PostCreateOrUpdateShortcut(location, ShellUtil::SHORTCUT_LOCATION_DESKTOP, + properties); EXPECT_TRUE(base::PathExists(shortcut_path)) << location.ToString(); return shortcut_path; @@ -232,7 +233,8 @@ const base::Location& location) { ShellUtil::ShortcutProperties properties(ShellUtil::SYSTEM_LEVEL); ShellUtil::AddDefaultShortcutProperties(GetExePath(), &properties); - PostCreateOrUpdateShortcut(location, properties); + PostCreateOrUpdateShortcut(location, ShellUtil::SHORTCUT_LOCATION_DESKTOP, + properties); const base::FilePath system_level_shortcut_path = GetSystemShortcutsDirectory().Append(InstallUtil::GetShortcutName() + installer::kLnkExt);
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn index b2cf441..5f26c76 100644 --- a/chrome/browser/resources/BUILD.gn +++ b/chrome/browser/resources/BUILD.gn
@@ -11,6 +11,7 @@ group("closure_compile") { deps = [ "engagement:closure_compile", + "interventions_internals:closure_compile", ] if (is_linux || is_win || is_mac) { deps += [
diff --git a/chrome/browser/resources/chromeos/camera/src/css/main.css b/chrome/browser/resources/chromeos/camera/src/css/main.css index e0335ab..ee74beb6 100644 --- a/chrome/browser/resources/chromeos/camera/src/css/main.css +++ b/chrome/browser/resources/chromeos/camera/src/css/main.css
@@ -460,8 +460,7 @@ background-image: url(../images/camera_button_mic_off.svg); } -body:not(.multi-fps) #toggle-fps, -body:not(.video-mode) #toggle-fps { +#toggle-fps { display: none; }
diff --git a/chrome/browser/resources/chromeos/camera/src/js/browser_proxy/browser_proxy_interface.js b/chrome/browser/resources/chromeos/camera/src/js/browser_proxy/browser_proxy_interface.js index 22367be..115a7669 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/browser_proxy/browser_proxy_interface.js +++ b/chrome/browser/resources/chromeos/camera/src/js/browser_proxy/browser_proxy_interface.js
@@ -30,7 +30,7 @@ /** * @param {(string|!Array<string>|!Object)} keys - * @param {function(!Object)=} callback + * @param {function(!Object)} callback */ localStorageGet(keys, callback) {}
diff --git a/chrome/browser/resources/chromeos/camera/src/js/browser_proxy/webui_browser_proxy.js b/chrome/browser/resources/chromeos/camera/src/js/browser_proxy/webui_browser_proxy.js index cb5720b..9e895695 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/browser_proxy/webui_browser_proxy.js +++ b/chrome/browser/resources/chromeos/camera/src/js/browser_proxy/webui_browser_proxy.js
@@ -39,17 +39,50 @@ /** @override */ localStorageGet(keys, callback) { - NOTIMPLEMENTED(); + let sanitizedKeys = []; + if (typeof keys === 'string') { + sanitizedKeys = [keys]; + } else if (Array.isArray(keys)) { + sanitizedKeys = keys; + } else if (keys !== null && typeof keys === 'object') { + sanitizedKeys = Object.keys(keys); + } else { + throw new Error('WebUI localStorageGet() cannot be run with ' + keys); + } + + let result = {}; + for (let key of sanitizedKeys) { + let value = window.localStorage.getItem(key); + if (value !== null) { + value = JSON.parse(value); + } + result[key] = value === null ? {} : value; + } + + callback(result); } /** @override */ localStorageSet(items, callback) { - NOTIMPLEMENTED(); + for (let [key, val] of Object.entries(items)) { + window.localStorage.setItem(key, JSON.stringify(val)); + } + if (callback) { + callback(); + } } /** @override */ localStorageRemove(items, callback) { - NOTIMPLEMENTED(); + if (typeof items === 'string') { + items = [items]; + } + for (let key of items) { + window.localStorage.removeItem(key); + } + if (callback) { + callback(); + } } }
diff --git a/chrome/browser/resources/chromeos/camera/src/js/main.js b/chrome/browser/resources/chromeos/camera/src/js/main.js index f5f0408..1a9281d8 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/main.js +++ b/chrome/browser/resources/chromeos/camera/src/js/main.js
@@ -27,24 +27,24 @@ this.resolBroker_ = new cca.ResolutionEventBroker(); /** - * @type {cca.camera.PhotoResolPreferrer} + * @type {cca.device.PhotoResolPreferrer} * @private */ - this.photoPreferrer_ = new cca.camera.PhotoResolPreferrer( + this.photoPreferrer_ = new cca.device.PhotoResolPreferrer( this.resolBroker_, () => this.cameraView_.restart()); /** - * @type {cca.camera.VideoConstraintsPreferrer} + * @type {cca.device.VideoConstraintsPreferrer} * @private */ - this.videoPreferrer_ = new cca.camera.VideoConstraintsPreferrer( + this.videoPreferrer_ = new cca.device.VideoConstraintsPreferrer( this.resolBroker_, () => this.cameraView_.restart()); /** - * @type {cca.camera.DeviceInfoUpdater} + * @type {cca.device.DeviceInfoUpdater} * @private */ - this.infoUpdater_ = new cca.camera.DeviceInfoUpdater( + this.infoUpdater_ = new cca.device.DeviceInfoUpdater( this.photoPreferrer_, this.videoPreferrer_); /**
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js index 80959fc..5b9efd7 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera.js
@@ -17,9 +17,9 @@ /** * Creates the camera-view controller. * @param {cca.models.Gallery} model Model object. - * @param {cca.camera.DeviceInfoUpdater} infoUpdater - * @param {cca.camera.PhotoResolPreferrer} photoPreferrer - * @param {cca.camera.VideoConstraintsPreferrer} videoPreferrer + * @param {cca.device.DeviceInfoUpdater} infoUpdater + * @param {cca.device.PhotoResolPreferrer} photoPreferrer + * @param {cca.device.VideoConstraintsPreferrer} videoPreferrer * @constructor */ cca.views.Camera = function( @@ -34,7 +34,7 @@ this.model_ = model; /** - * @type {cca.camera.DeviceInfoUpdater} + * @type {cca.device.DeviceInfoUpdater} * @private */ this.infoUpdater_ = infoUpdater;
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js index fc2e674..60ee0142 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/modes.js
@@ -85,8 +85,8 @@ /** * Mode controller managing capture sequence of different camera mode. - * @param {cca.camera.PhotoResolPreferrer} photoResolPreferrer - * @param {cca.camera.VideoConstraintsPreferrer} videoPreferrer + * @param {cca.device.PhotoResolPreferrer} photoResolPreferrer + * @param {cca.device.VideoConstraintsPreferrer} videoPreferrer * @param {function()} doSwitchMode Callback to trigger mode switching. * @param {DoSavePhoto} doSavePhoto * @param {DoSaveVideo} doSaveVideo
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/camera/options.js b/chrome/browser/resources/chromeos/camera/src/js/views/camera/options.js index 33d79a74..f60d433 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/camera/options.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/camera/options.js
@@ -78,13 +78,13 @@ /** * Creates a controller for the options of Camera view. - * @param {cca.camera.DeviceInfoUpdater} infoUpdater + * @param {cca.device.DeviceInfoUpdater} infoUpdater * @param {function()} doSwitchDevice Callback to trigger device switching. * @constructor */ cca.views.camera.Options = function(infoUpdater, doSwitchDevice) { /** - * @type {cca.camera.DeviceInfoUpdater} + * @type {cca.device.DeviceInfoUpdater} * @private */ this.infoUpdater_ = infoUpdater;
diff --git a/chrome/browser/resources/chromeos/camera/src/js/views/settings.js b/chrome/browser/resources/chromeos/camera/src/js/views/settings.js index 6c396dcb..575adfc 100644 --- a/chrome/browser/resources/chromeos/camera/src/js/views/settings.js +++ b/chrome/browser/resources/chromeos/camera/src/js/views/settings.js
@@ -109,9 +109,9 @@ /** * Creates the controller of resolution settings view. - * @param {!cca.camera.DeviceInfoUpdater} infoUpdater - * @param {!cca.camera.PhotoResolPreferrer} photoPreferrer - * @param {!cca.camera.VideoConstraintsPreferrer} videoPreferrer + * @param {!cca.device.DeviceInfoUpdater} infoUpdater + * @param {!cca.device.PhotoResolPreferrer} photoPreferrer + * @param {!cca.device.VideoConstraintsPreferrer} videoPreferrer * @param {!cca.ResolutionEventBroker} resolBroker * @extends {cca.views.BaseSettings} * @constructor
diff --git a/chrome/browser/resources/chromeos/camera/src/views/main.html b/chrome/browser/resources/chromeos/camera/src/views/main.html index 761482c7..d056d3d 100644 --- a/chrome/browser/resources/chromeos/camera/src/views/main.html +++ b/chrome/browser/resources/chromeos/camera/src/views/main.html
@@ -20,9 +20,9 @@ <script src="../js/sound.js"></script> <script src="../js/scrollbar.js"></script> <script src="../js/gallerybutton.js"></script> - <script src="../js/camera/camera3_device_info.js"></script> - <script src="../js/camera/constraints_preferrer.js"></script> - <script src="../js/camera/device_info_updater.js"></script> + <script src="../js/device/camera3_device_info.js"></script> + <script src="../js/device/constraints_preferrer.js"></script> + <script src="../js/device/device_info_updater.js"></script> <script src="../js/models/filenamer.js"></script> <script src="../js/models/gallery.js"></script> <script src="../js/models/filesystem.js"></script>
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/color.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/color.js index 312c361c..62d0426 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/color.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/color.js
@@ -84,9 +84,12 @@ /** * The distance between black and dark grey is the threshold. + * 0x000000 = Black. + * 0x282828 = Dark Grey. This value was chosen somewhat arbitrarily. It encodes + * a shade of grey that could be visibly identified as black. * @const {number} */ -Color.DISTANCE_THRESHOLD = Color.findDistance(0X000000, 0X181818); +Color.DISTANCE_THRESHOLD = Color.findDistance(0X000000, 0X282828); /** * Holds objects that contain hexadecimal RGB values of colors and their
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/color_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/color_test.extjs index 8eee010..c9f492c 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/color_test.extjs +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/color_test.extjs
@@ -38,10 +38,11 @@ var blue = 0x0000ff; var black = 0x000000; + var gmailDefaultTextColor = 0x222222; var looksLikePink = 0xF4CCCC; var looksLikeGreen = 0x38761D; - - var unknownColor = 0x0C343D; + var looksLikeDarkGrey = 0x0C343D; + var unknownColor = 0x003DAC; // Exact matches. assertEquals('White', Color.findClosestMatchingColor(white)); @@ -51,8 +52,10 @@ assertEquals('Black', Color.findClosestMatchingColor(black)); // Inexact matches. + assertEquals('Black', Color.findClosestMatchingColor(gmailDefaultTextColor)); assertEquals('Pink', Color.findClosestMatchingColor(looksLikePink)); assertEquals('Forest Green', Color.findClosestMatchingColor(looksLikeGreen)); + assertEquals('Dark Slate Grey', Color.findClosestMatchingColor(looksLikeDarkGrey)); // No match. assertEquals('', Color.findClosestMatchingColor(unknownColor));
diff --git a/chrome/browser/resources/chromeos/login/oobe_eula.css b/chrome/browser/resources/chromeos/login/oobe_eula.css index 758a7fa..b78674a 100644 --- a/chrome/browser/resources/chromeos/login/oobe_eula.css +++ b/chrome/browser/resources/chromeos/login/oobe_eula.css
@@ -43,6 +43,7 @@ } #usageStatsLabelContainer { + color: var(--google-grey-refresh-700); /* #5F6368 */ line-height: 20px; margin-inline-start: 16px; }
diff --git a/chrome/browser/resources/chromeos/password_change/confirm_password_change.html b/chrome/browser/resources/chromeos/password_change/confirm_password_change.html index 96a768e..67c7380 100644 --- a/chrome/browser/resources/chromeos/password_change/confirm_password_change.html +++ b/chrome/browser/resources/chromeos/password_change/confirm_password_change.html
@@ -35,16 +35,17 @@ } [slot='body'] { - color: rgb(20, 21, 24); + color: var(--google-grey-900); font-family: Roboto, sans-serif; font-size: 13px; padding: 0 48px 0 24px; } [slot='button-container'] { - bottom: 16px; + bottom: 0; box-sizing: border-box; - padding: 0 16px; + margin: 0; + padding: 16px; position: fixed; width: 100%; }
diff --git a/chrome/browser/resources/chromeos/password_change/urgent_password_expiry_notification.html b/chrome/browser/resources/chromeos/password_change/urgent_password_expiry_notification.html index dd539af..9702996 100644 --- a/chrome/browser/resources/chromeos/password_change/urgent_password_expiry_notification.html +++ b/chrome/browser/resources/chromeos/password_change/urgent_password_expiry_notification.html
@@ -27,30 +27,31 @@ } [slot='title'] { - color: rgb(20, 21, 25); + color: var(--google-grey-900); font-family: Google Sans, sans-serif; font-size: 28px; padding: 64px 64px 8px; } #title-icon { - --iron-icon-fill-color: rgb(20, 21, 25); + --iron-icon-fill-color: var(--google-grey-900); height: 32px; padding-bottom: 24px; width: 32px; } [slot='body'] { - color: rgb(21, 21, 21); + color: var(--google-grey-900); font-family: Roboto, sans-serif; font-size: 13px; padding: 0 64px; } [slot='button-container'] { - bottom: 32px; + bottom: 0; box-sizing: border-box; - padding: 0 32px; + margin: 0; + padding: 32px; position: fixed; width: 100%; }
diff --git a/chrome/browser/resources/interventions_internals/BUILD.gn b/chrome/browser/resources/interventions_internals/BUILD.gn new file mode 100644 index 0000000..e6c48042 --- /dev/null +++ b/chrome/browser/resources/interventions_internals/BUILD.gn
@@ -0,0 +1,20 @@ +# 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. + +import("//third_party/closure_compiler/compile_js.gni") + +js_type_check("closure_compile") { + deps = [ + ":index", + ] +} + +js_library("index") { + deps = [ + "//chrome/browser/ui/webui/interventions_internals:mojo_bindings_js_library_for_compile", + "//ui/webui/resources/js:assert", + "//ui/webui/resources/js:cr", + "//ui/webui/resources/js:util", + ] +}
diff --git a/chrome/browser/resources/interventions_internals/index.js b/chrome/browser/resources/interventions_internals/index.js index c02243f..c417033d 100644 --- a/chrome/browser/resources/interventions_internals/index.js +++ b/chrome/browser/resources/interventions_internals/index.js
@@ -284,7 +284,7 @@ * Helper function to check if all keywords, case insensitive, are in the given * text. * - * @param {string[]} keywords The collection of keywords. + * @param {Array<string>} keywords The collection of keywords. * @param {string} text The given text to search. * @return True iff all keywords present in the given text. */ @@ -370,7 +370,7 @@ * Create and add a copy to clipboard button to a given node. * * @param {string} text The text that will be copied to the clipboard. - * @param {element!} node The node that will have the button appended to. + * @param {Element} node The node that will have the button appended to. */ function appendCopyToClipBoardButton(text, node) { if (!document.queryCommandSupported || @@ -449,15 +449,20 @@ $('clear-log-button').addEventListener('click', removeAllLogMessagesRows); } -/** @constructor */ -const InterventionsInternalPageImpl = function() {}; +/** + * @constructor + * @implements {mojom.InterventionsInternalsPageInterface} + */ +const InterventionsInternalPageImpl = function() { + this.receiver_ = new mojom.InterventionsInternalsPageReceiver(this); +}; InterventionsInternalPageImpl.prototype = { /** * Post a new log message to the web page. * * @override - * @param {!MessageLog} log The new log message recorded by + * @param {!mojom.MessageLog} log The new log message recorded by * PreviewsLogger. */ logNewMessage: function(log) { @@ -580,6 +585,14 @@ nqeCol.textContent = type; nqeRow.appendChild(nqeCol); }, + + /** + * Returns a remote interface to the receiver. + */ + bindNewPipeAndPassRemote: function() { + const helper = this.receiver_.$; + return helper.bindNewPipeAndPassRemote(); + }, }; cr.define('interventions_internals', () => { @@ -600,22 +613,6 @@ } /** - * Sort keys by the value of each value by its description attribute of a - * |mapObject|. - * - * @param mapObject {!Map<string, Object} A map where all values have a - * description attribute. - * @return A list of keys sorted by their descriptions. - */ - function getSortedKeysByDescription(mapObject) { - const sortedKeys = Array.from(mapObject.keys()); - sortedKeys.sort((a, b) => { - return mapObject.get(a).description > mapObject.get(b).description; - }); - return sortedKeys; - } - - /** * Retrieves the statuses of previews (i.e. Offline, Lite Pages, etc), * and posts them on chrome://intervention-internals. */ @@ -699,12 +696,11 @@ if (window.testPageHandler) { pageHandler = window.testPageHandler; } else { - pageHandler = mojom.InterventionsInternalsPageHandler.getProxy(); + pageHandler = mojom.InterventionsInternalsPageHandler.getRemote(); // Set up client side mojo interface. pageImpl = new InterventionsInternalPageImpl(); - const client = new mojom.InterventionsInternalsPage(pageImpl); - pageHandler.setClientPage(client.$.createProxy()); + pageHandler.setClientPage(pageImpl.bindNewPipeAndPassRemote()); } interventions_internals.init(pageHandler);
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js index 213afc16..a288671 100644 --- a/chrome/browser/resources/local_ntp/customize.js +++ b/chrome/browser/resources/local_ntp/customize.js
@@ -1450,6 +1450,7 @@ // Selecting a local image for the background should close the picker. if (configData.richerPicker) { ntpApiHandle.onlocalbackgroundselected = () => { + customize.selectedOptions.backgroundData = null; customize.richerPicker_deselectBackgroundTile( customize.selectedOptions.background); customize.richerPicker_applyCustomization();
diff --git a/chrome/browser/resources/omnibox/BUILD.gn b/chrome/browser/resources/omnibox/BUILD.gn index 10b8777..0465f91 100644 --- a/chrome/browser/resources/omnibox/BUILD.gn +++ b/chrome/browser/resources/omnibox/BUILD.gn
@@ -16,6 +16,7 @@ ":omnibox_input", ":omnibox_output", "//chrome/browser/ui/webui/omnibox:mojo_bindings_js_library_for_compile", + "//ui/webui/resources/js:load_time_data", ] }
diff --git a/chrome/browser/resources/omnibox/omnibox.html b/chrome/browser/resources/omnibox/omnibox.html index 4947569..1f9f1f8 100644 --- a/chrome/browser/resources/omnibox/omnibox.html +++ b/chrome/browser/resources/omnibox/omnibox.html
@@ -8,12 +8,14 @@ <link rel="stylesheet" href="omnibox.css"> <script src="chrome://resources/js/cr.js"></script> <script src="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js"></script> + <script src="chrome://resources/js/load_time_data.js"></script> <script src="chrome://resources/js/util.js"></script> <script src="chrome/browser/ui/webui/omnibox/omnibox.mojom-lite.js"></script> <script src="omnibox_element.js"></script> <script src="omnibox_input.js"></script> <script src="omnibox_output.js"></script> <script src="omnibox.js"></script> + <script src="strings.js"></script> </head> <body>
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js index 74e3738..7bcb89eb 100644 --- a/chrome/browser/resources/omnibox/omnibox.js +++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -81,8 +81,13 @@ * @param {boolean} isPageController */ handleNewAutocompleteResponse(response, isPageController) { + // Note: Using inputText is a sufficient fix for the way this is used today, + // but in principle it would be better to associate requests with responses + // using a unique session identifier, for example by rolling an integer each + // time a request is made. Doing so would require extra bookkeeping on the + // host side, so for now we keep it simple. const isForLastPageRequest = isPageController && this.lastRequest && - this.lastRequest.inputText === response.host; + this.lastRequest.inputText === response.inputText; // When unfocusing the browser omnibox, the autocomplete controller // sends a response with no combined results. This response is ignored @@ -95,6 +100,9 @@ omniboxOutput.addAutocompleteResponse(response); } + // TODO(orinj|manukh): If |response.done| but not |isForLastPageRequest| + // then callback is being dropped. We should guarantee that callback is + // always called because some callers await promises. if (isForLastPageRequest && response.done) { this.lastRequest.callback(response); this.lastRequest = null; @@ -213,8 +221,9 @@ * This is the worker function that transforms query inputs to accumulate * batch exports, then finally initiates a download for the complete set. * @param {!Array<!QueryInputs>} batchQueryInputs + * @param {string} batchName */ - async processBatch(batchQueryInputs) { + async processBatch(batchQueryInputs, batchName) { const batchExports = []; for (const queryInputs of batchQueryInputs) { const omniboxResponse = await browserProxy @@ -233,8 +242,21 @@ }; batchExports.push(exportData); } - const fileName = `omnibox_batch_${ExportDelegate.getTimeStamp()}.json`; - const batchData = { appVersion: navigator.appVersion, batchExports }; + const now = new Date(); + const fileName = `omnibox_batch_${ExportDelegate.getTimeStamp(now)}.json`; + // If this data format changes, please roll schemaVersion. + const batchData = { + schemaKind: 'Omnibox Batch Export', + schemaVersion: 2, + dateCreated: now.toISOString(), + author: '', + description: '', + authorTool: 'chrome://omnibox', + batchName, + versionDetails: window.loadTimeData.data_, + appVersion: navigator.appVersion, + batchExports + }; ExportDelegate.download_(batchData, fileName); } @@ -244,11 +266,14 @@ * @param {!BatchSpecifier} processBatchData */ processBatchData(processBatchData) { - if (processBatchData.batchMode && processBatchData.batchQueryInputs) { - this.processBatch(processBatchData.batchQueryInputs); + if (processBatchData.batchMode && processBatchData.batchQueryInputs && + processBatchData.batchName) { + this.processBatch( + processBatchData.batchQueryInputs, processBatchData.batchName); } else { const expected = { batchMode: "combined", + batchName: "name for this batch of queries", batchQueryInputs: [ { inputText: "example input text", @@ -305,9 +330,15 @@ a.click(); } - /** @return {string} A sortable timestamp string for use in filenames. */ - static getTimeStamp() { - const iso = new Date().toISOString(); + /** + * @param {Date=} date + * @return {string} A sortable timestamp string for use in filenames. + */ + static getTimeStamp(date) { + if (!date) { + date = new Date(); + } + const iso = date.toISOString(); return iso.replace(/:/g, '').split('.')[0]; } }
diff --git a/chrome/browser/resources/policy/policy_base.js b/chrome/browser/resources/policy/policy_base.js index 47e5f49d..cba1b9a5 100644 --- a/chrome/browser/resources/policy/policy_base.js +++ b/chrome/browser/resources/policy/policy_base.js
@@ -505,7 +505,7 @@ link: knownPolicyNames === policyNames.chrome.policyNames && knownPolicyNamesSet.has(name) ? - `https://chromium.org/administrators/policy-list-3#${ + `https://cloud.google.com/docs/chrome-enterprise/policies/?policy=${ name}` : undefined, },
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_reset_page/BUILD.gn index 85fc4d8..81ef1c0 100644 --- a/chrome/browser/resources/settings/chromeos/os_reset_page/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_reset_page/BUILD.gn
@@ -7,14 +7,14 @@ js_type_check("closure_compile") { deps = [ ":os_powerwash_dialog", + ":os_reset_browser_proxy", ":os_reset_page", - ":reset_os_proxy", ] } js_library("os_powerwash_dialog") { deps = [ - ":reset_os_proxy", + ":os_reset_browser_proxy", "../..:lifetime_browser_proxy", ] } @@ -28,7 +28,7 @@ ] } -js_library("reset_os_proxy") { +js_library("os_reset_browser_proxy") { deps = [ "//ui/webui/resources/js:cr", ]
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.html b/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.html index c021575..51a81006 100644 --- a/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.html +++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.html
@@ -2,7 +2,7 @@ <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html"> <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> -<link rel="import" href="reset_os_proxy.html"> +<link rel="import" href="os_reset_browser_proxy.html"> <link rel="import" href="../../lifetime_browser_proxy.html"> <link rel="import" href="../../settings_shared_css.html">
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.js b/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.js index 32b6c036..99d0905 100644 --- a/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_powerwash_dialog.js
@@ -19,7 +19,7 @@ /** @override */ attached: function() { - settings.ResetOsProxyImpl.getInstance().onPowerwashDialogShow(); + settings.OsResetBrowserProxyImpl.getInstance().onPowerwashDialogShow(); this.$.dialog.showModal(); },
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_browser_proxy.html b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_browser_proxy.html new file mode 100644 index 0000000..09bda1a --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_browser_proxy.html
@@ -0,0 +1,2 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="os_reset_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/reset_os_proxy.js b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_browser_proxy.js similarity index 67% rename from chrome/browser/resources/settings/chromeos/os_reset_page/reset_os_proxy.js rename to chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_browser_proxy.js index 83929c9..ebdf4fa 100644 --- a/chrome/browser/resources/settings/chromeos/os_reset_page/reset_os_proxy.js +++ b/chrome/browser/resources/settings/chromeos/os_reset_page/os_reset_browser_proxy.js
@@ -4,22 +4,22 @@ cr.define('settings', function() { /** @interface */ - class ResetOsProxy { + class OsResetBrowserProxy { /** * A method to be called when the reset powerwash dialog is shown. */ onPowerwashDialogShow() {} /** - * Initiates a factory reset and restarts ChromeOS. + * Initiates a factory reset and restarts. */ requestFactoryResetRestart() {} } /** - * @implements {settings.ResetOsProxy} + * @implements {settings.OsResetBrowserProxy} */ - class ResetOsProxyImpl { + class OsResetBrowserProxyImpl { /** @override */ onPowerwashDialogShow() { chrome.send('onPowerwashDialogShow'); @@ -31,10 +31,10 @@ } } - cr.addSingletonGetter(ResetOsProxyImpl); + cr.addSingletonGetter(OsResetBrowserProxyImpl); return { - ResetOsProxy: ResetOsProxy, - ResetOsProxyImpl: ResetOsProxyImpl, + OsResetBrowserProxy: OsResetBrowserProxy, + OsResetBrowserProxyImpl: OsResetBrowserProxyImpl, }; });
diff --git a/chrome/browser/resources/settings/chromeos/os_reset_page/reset_os_proxy.html b/chrome/browser/resources/settings/chromeos/os_reset_page/reset_os_proxy.html deleted file mode 100644 index 77b9e53..0000000 --- a/chrome/browser/resources/settings/chromeos/os_reset_page/reset_os_proxy.html +++ /dev/null
@@ -1,2 +0,0 @@ -<link rel="import" href="chrome://resources/html/cr.html"> -<script src="reset_os_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.html b/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.html index 0f74897..79b9e54 100644 --- a/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.html +++ b/chrome/browser/resources/settings/chromeos/os_search_page/os_search_page.html
@@ -6,6 +6,8 @@ <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-tooltip/paper-tooltip.html"> <link rel="import" href="../../controls/extension_controlled_indicator.html"> <link rel="import" href="../../google_assistant_page/google_assistant_page.html"> <link rel="import" href="../../google_assistant_page/google_assistant_browser_proxy.html"> @@ -27,8 +29,20 @@ min-height: var(--settings-row-min-height); } + /* TODO(jamescook): Style all OS settings tooltips to new spec. */ + paper-tooltip { + --paper-tooltip: { + @apply --cr-tooltip; + padding: 12px 10px; + }; + } + iron-icon { - padding-inline-end: 16px; + --iron-icon-fill-color: var(--google-grey-refresh-500); + } + + cr-policy-pref-indicator { + padding-inline-end: 8px; } </style> <settings-animated-pages id="pages" section="search" @@ -40,7 +54,14 @@ <div class="settings-box first block"> <div id="search-wrapper"> <div id="searchExplanation" class="start settings-box-text"> - $i18nRaw{searchExplanation} + $i18n{osSearchEngineLabel} + <iron-icon id="help-icon" icon="cr:help-outline" + aria-label="$i18n{osSearchEngineTooltip}" + aria-describedby="tooltip"></iron-icon> + <paper-tooltip id="tooltip" for="help-icon" position="bottom" + fit-to-visible-bounds> + $i18n{osSearchEngineTooltip} + </paper-tooltip> </div> <template is="dom-if" if="[[isDefaultSearchControlledByPolicy_( prefs.default_search_provider_data.template_url_data)]]">
diff --git a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js index 808af92..cb8f1dc 100644 --- a/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js +++ b/chrome/browser/resources/settings/multidevice_page/multidevice_subpage.js
@@ -108,10 +108,8 @@ * @private */ doesAndroidMessagesRequireSetUp_: function() { - // The pairing state is preferred over the FeatureState here since - // FeatureState.UNAVAILABLE_SUITE_DISABLED is returned when the suite is - // disabled, regardless if Messages requires further setup. - return !this.pageContentData.isAndroidSmsPairingComplete; + return this.getFeatureState(settings.MultiDeviceFeature.MESSAGES) === + settings.MultiDeviceFeatureState.FURTHER_SETUP_REQUIRED; }, /**
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd index 8ad9dd0..4b86241 100644 --- a/chrome/browser/resources/settings/os_settings_resources.grd +++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -468,11 +468,11 @@ <structure name="IDR_OS_SETTINGS_RESET_PAGE_JS" file="chromeos/os_reset_page/os_reset_page.js" type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_RESET_OS_PROXY_JS" - file="chromeos/os_reset_page/reset_os_proxy.js" + <structure name="IDR_OS_SETTINGS_RESET_BROWSER_PROXY_JS" + file="chromeos/os_reset_page/os_reset_browser_proxy.js" type="chrome_html" /> - <structure name="IDR_OS_SETTINGS_RESET_OS_PROXY_HTML" - file="chromeos/os_reset_page/reset_os_proxy.html" + <structure name="IDR_OS_SETTINGS_RESET_BROWSER_PROXY_HTML" + file="chromeos/os_reset_page/os_reset_browser_proxy.html" type="chrome_html" /> <structure name="IDR_OS_SETTINGS_LANGUAGES_HTML" file="languages_page/languages.html"
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers.html b/chrome/browser/resources/settings/printing_page/cups_printers.html index 5500878..7f23152 100644 --- a/chrome/browser/resources/settings/printing_page/cups_printers.html +++ b/chrome/browser/resources/settings/printing_page/cups_printers.html
@@ -51,7 +51,7 @@ } </style> - <template is="dom-if" if="[[!enableUpdatedUI_]]"> + <template is="dom-if" if="[[!enableUpdatedUi_]]"> <div class="settings-box first"> <div class="start"> <span>$i18n{cupsPrintersLearnMoreLabel}</span> @@ -82,7 +82,7 @@ </settings-cups-printers-list> </template> - <template is="dom-if" if="[[enableUpdatedUI_]]"> + <template is="dom-if" if="[[enableUpdatedUi_]]"> <div class="settings-box first"> <div class="start"> <span>$i18n{savedPrintersTitle}</span> @@ -132,7 +132,8 @@ </template> <settings-cups-add-printer-dialog id="addPrinterDialog" - on-close="onAddPrinterDialogClose_"> + on-close="onAddPrinterDialogClose_" + enable-updated-ui="[[enableUpdatedUi_]]"> </settings-cups-add-printer-dialog> <template is="dom-if" if="[[showCupsEditPrinterDialog_]]" restamp>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers.js b/chrome/browser/resources/settings/printing_page/cups_printers.js index bcab11f..7e41ed4 100644 --- a/chrome/browser/resources/settings/printing_page/cups_printers.js +++ b/chrome/browser/resources/settings/printing_page/cups_printers.js
@@ -50,7 +50,7 @@ * is launched. * @private */ - enableUpdatedUI_: { + enableUpdatedUi_: { type: Boolean, value: function() { return loadTimeData.getBoolean('updatedCupsPrintersUiEnabled'); @@ -87,7 +87,7 @@ this.onActiveNetworksChanged(responseParams.result); }); - if (this.enableUpdatedUI_) { + if (this.enableUpdatedUi_) { return; } @@ -123,7 +123,7 @@ const printerName = event.detail.printerName; switch (event.detail.resultCode) { case PrinterSetupResult.SUCCESS: - if (this.enableUpdatedUI_) { + if (this.enableUpdatedUi_) { this.$$('#savedPrinters').updateSavedPrintersList(); } else { this.updateCupsPrintersList_(); @@ -133,7 +133,7 @@ printerName); break; case PrinterSetupResult.EDIT_SUCCESS: - if (this.enableUpdatedUI_) { + if (this.enableUpdatedUi_) { this.$$('#savedPrinters').updateSavedPrintersList(); } else { this.updateCupsPrintersList_();
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index b94ace4..2be129c 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -142,6 +142,8 @@ "download_protection/download_url_sb_client.h", "download_protection/file_analyzer.cc", "download_protection/file_analyzer.h", + "download_protection/multipart_uploader.cc", + "download_protection/multipart_uploader.h", "download_protection/path_sanitizer.cc", "download_protection/path_sanitizer.h", "download_protection/ppapi_download_request.cc",
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win.cc index 56648e7e..40ce757 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win.cc +++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win.cc
@@ -159,7 +159,14 @@ } // Reads |buffer_size| bytes from a pipe of PIPE_TYPE_MESSAGE. -bool ReadMessageFromPipe(HANDLE handle, LPVOID buffer, DWORD buffer_size) { +// Uses |error_category| to report WinAPI errors if needed. +// Uses |custom_error| to report short reads if needed. +bool ReadMessageFromPipe( + HANDLE handle, + LPVOID buffer, + DWORD buffer_size, + ChromePromptChannelProtobuf::ErrorCategory error_category, + ChromePromptChannelProtobuf::CustomErrors short_read_error) { // If the process at the other end of the pipe is behaving correctly it will // write exactly |buffer_size| bytes to the pipe and PIPE_TYPE_MESSAGE // ensures that we read all of them at once. If the process writes more bytes @@ -167,13 +174,20 @@ // we treat that as an error. DWORD bytes_read = 0; if (!::ReadFile(handle, buffer, buffer_size, &bytes_read, nullptr)) { + WriteStatusErrorCodeToHistogram(error_category, + logging::GetLastSystemErrorCode()); PLOG(ERROR) << "ReadFile failed"; return false; } + CHECK_LE(bytes_read, buffer_size); if (bytes_read != buffer_size) { - PLOG(ERROR) << "Short read (read " << bytes_read << " of " << buffer_size - << ")"; + LOG(ERROR) << "Short read (read " << bytes_read << " of " << buffer_size + << ")"; + + WriteStatusErrorCodeToHistogram( + ChromePromptChannelProtobuf::ErrorCategory::kCustomError, + short_read_error); return false; } return true; @@ -209,7 +223,6 @@ HANDLE request_read_handle, std::unique_ptr<CleanerProcessDelegate> cleaner_process, base::OnceClosure on_connection_closed) { - static constexpr uint32_t kMaxMessageLength = 1 * 1024 * 1024; // 1M bytes // Always call OnConnectionClosed when finished whether it's with an error or // because a CloseConnectionRequest was received. @@ -253,18 +266,29 @@ // Read the request length followed by a request. uint32_t request_length = 0; if (!ReadMessageFromPipe(request_read_handle, &request_length, - sizeof(request_length))) { + sizeof(request_length), + ChromePromptChannelProtobuf::ErrorCategory:: + kReadRequestLengthWinError, + ChromePromptChannelProtobuf::CustomErrors:: + kRequestLengthShortRead)) { return; } - if (request_length < 1 || request_length > kMaxMessageLength) { - PLOG(ERROR) << "Bad request length: " << request_length; + + if (request_length < 1 || + request_length > ChromePromptChannelProtobuf::kMaxMessageLength) { + WriteStatusErrorCodeToHistogram( + ChromePromptChannelProtobuf::ErrorCategory::kCustomError, + ChromePromptChannelProtobuf::CustomErrors::kRequestInvalidSize); + + LOG(ERROR) << "Bad request length: " << request_length; return; } std::string request; - // Include space for the null terminator in the WriteInto call. - if (!ReadMessageFromPipe(request_read_handle, - base::WriteInto(&request, request_length + 1), - request_length)) { + if (!ReadMessageFromPipe( + request_read_handle, base::WriteInto(&request, request_length + 1), + request_length, + ChromePromptChannelProtobuf::ErrorCategory::kReadRequestWinError, + ChromePromptChannelProtobuf::CustomErrors::kRequestShortRead)) { return; }
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win.h b/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win.h index 2d7252c..b5e075c2 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win.h +++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win.h
@@ -137,6 +137,7 @@ class ChromePromptChannelProtobuf : public ChromePromptChannel { public: static const char kErrorHistogramName[]; + static constexpr uint32_t kMaxMessageLength = 1 * 1024 * 1024; // 1M bytes // Values from this enum will serve as the high bits of the histogram values. // We will be able to use them to separate the errors by category if we ever @@ -153,6 +154,7 @@ kWrongHandshakeVersion = 1, kRequestLengthShortRead = 2, kRequestShortRead = 3, + kRequestInvalidSize = 4, }; static int32_t GetErrorCodeInt(ErrorCategory category,
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win_unittest.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win_unittest.cc index ee17414..17f4031 100644 --- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win_unittest.cc +++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_channel_win_unittest.cc
@@ -9,6 +9,7 @@ #include <memory> #include <string> #include <utility> +#include <vector> #include "base/bind.h" #include "base/bind_helpers.h" @@ -36,6 +37,8 @@ namespace { static constexpr uint8_t kVersion = 1U; +static constexpr uint32_t kErrorMoreData = + 0xEA; // Equivalent to Windows ERROR_MORE_DATA // Get the error category from a histogram sample. ChromePromptChannelProtobuf::ErrorCategory SampleToCategory( @@ -142,6 +145,11 @@ // Closes the cleaner process pipe handles to simulate the cleaner process // exiting. void CloseCleanerHandles() { + // Cancel anything that might be left to be read/written for fail-scenario + // tests. + ::CancelIoEx(response_read_handle_.Get(), nullptr); + ::CancelIoEx(request_write_handle_.Get(), nullptr); + response_read_handle_.Close(); request_write_handle_.Close(); } @@ -153,19 +161,45 @@ base::Unretained(this))); } - void WriteVersion(uint8_t version) { + template <typename T> + void WriteByValue(T value) { DWORD bytes_written = 0; - ASSERT_TRUE(::WriteFile(request_write_handle_.Get(), &version, - sizeof(version), &bytes_written, nullptr)); - ASSERT_EQ(bytes_written, sizeof(version)); + ASSERT_TRUE(::WriteFile(request_write_handle_.Get(), &value, sizeof(value), + &bytes_written, nullptr)); + ASSERT_EQ(bytes_written, sizeof(value)); } - // Writes the version to the pipe without blocking the main test thread. - void PostWriteVersion(uint8_t version) { + template <typename T> + void WriteByPointer(const T* ptr, uint32_t size, bool should_succeed) { + DWORD bytes_written = 0; + ASSERT_EQ(::WriteFile(request_write_handle_.Get(), ptr, size, + &bytes_written, nullptr), + should_succeed); + + // On a failed write we don't care about the number of bytes read. + if (should_succeed) { + ASSERT_EQ(bytes_written, size); + } + } + + // Writes bytes taken by pointer to the pipe without blocking the main test + // thread. + template <typename T> + void PostWriteByPointer(const T* ptr, uint32_t size, bool should_succeed) { channel_->task_runner()->PostTask( FROM_HERE, - base::BindOnce(&ChromePromptChannelProtobufTest::WriteVersion, - base::Unretained(this), version)); + base::BindOnce(&ChromePromptChannelProtobufTest::WriteByPointer<T>, + base::Unretained(this), ptr, size, should_succeed)); + } + + // Writes bytes taken by value to the pipe without blocking the main test + // thread. + template <typename T> + void PostWriteByValue(T value) { + channel_->task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&ChromePromptChannelProtobufTest::WriteByValue<T>, + base::Unretained(this), value)); } void ExpectReadFails() { @@ -200,6 +234,7 @@ base::RunLoop run_loop_; ChromePromptChannelPtr channel_ = ChromePromptChannelPtr(nullptr, base::OnTaskRunnerDeleter(nullptr)); + base::win::ScopedHandle response_read_handle_; base::win::ScopedHandle request_write_handle_; @@ -239,7 +274,8 @@ channel_->ConnectToCleaner(std::move(mock_cleaner_process_)); // Invalid version - PostWriteVersion(128); + constexpr uint8_t kVersion = 128; + PostWriteByValue(kVersion); WaitForDisconnect(); // We expect the the handshake to have failed because of the version. @@ -255,7 +291,8 @@ channel_->ConnectToCleaner(std::move(mock_cleaner_process_)); // Invalid version - PostWriteVersion(0U); + constexpr uint8_t kVersion = 0; + PostWriteByValue(kVersion); WaitForDisconnect(); // We expect the the handshake to have failed because of the version. @@ -270,17 +307,148 @@ channel_->ConnectToCleaner(std::move(mock_cleaner_process_)); // Write version 1. - PostWriteVersion(kVersion); + PostWriteByValue(kVersion); // Simulate the cleaner exiting after writing the version. PostCloseCleanerHandles(); WaitForDisconnect(); - // There were no errors so the histogram should be empty - // TODO(crbug.com/969139): We should be getting a kReadRequestLengthWinError - // here. - ExpectHistogramEmpty(); + ExpectCategoryErrorCount( + ChromePromptChannelProtobuf::ErrorCategory::kReadRequestLengthWinError, + 1); + + ExpectReadFails(); +} + +TEST_F(ChromePromptChannelProtobufTest, PostSizeOfZero) { + SetupCommunicationFailure(); + channel_->ConnectToCleaner(std::move(mock_cleaner_process_)); + + // Valid version + PostWriteByValue(kVersion); + + // Send invalid size + PostWriteByValue(0U); + WaitForDisconnect(); + + ExpectUniqueSample( + ChromePromptChannelProtobuf::ErrorCategory::kCustomError, + ChromePromptChannelProtobuf::CustomErrors::kRequestInvalidSize); + ExpectReadFails(); +} + +TEST_F(ChromePromptChannelProtobufTest, PostSizeMoreThanMax) { + SetupCommunicationFailure(); + channel_->ConnectToCleaner(std::move(mock_cleaner_process_)); + + // Valid version + PostWriteByValue(kVersion); + + // Send invalid size + PostWriteByValue(ChromePromptChannelProtobuf::kMaxMessageLength + 1); + WaitForDisconnect(); + + ExpectUniqueSample( + ChromePromptChannelProtobuf::ErrorCategory::kCustomError, + ChromePromptChannelProtobuf::CustomErrors::kRequestInvalidSize); + ExpectReadFails(); +} + +TEST_F(ChromePromptChannelProtobufTest, PostExtraData) { + SetupCommunicationFailure(); + channel_->ConnectToCleaner(std::move(mock_cleaner_process_)); + + // Valid version + PostWriteByValue(kVersion); + + constexpr uint32_t kSize = 10; + const std::vector<uint8_t> bytes(kSize); + + // Post the size of the read. + PostWriteByValue(kSize - 1); + + // Post slightly more data. + PostWriteByPointer(bytes.data(), bytes.size(), false); + + WaitForDisconnect(); + + ExpectUniqueSample( + ChromePromptChannelProtobuf::ErrorCategory::kReadRequestWinError, + kErrorMoreData); + + ExpectReadFails(); +} + +// The pipes are valid before ConnectToCleaner just as much as after. +TEST_F(ChromePromptChannelProtobufTest, VersionSentBeforeConnection) { + SetupCommunicationFailure(); + + // Valid version but BEFORE connection + PostWriteByValue(kVersion); + + // Connect + channel_->ConnectToCleaner(std::move(mock_cleaner_process_)); + + // Disconnect + PostCloseCleanerHandles(); + WaitForDisconnect(); + + // The first read that fails is the reading of the length of the first + // request. That is because the sending of the version was successful (unless + // we see an error in the histogram which will cause a test failure) and we + // disconnect before sending a length. + ExpectCategoryErrorCount( + ChromePromptChannelProtobuf::ErrorCategory::kReadRequestLengthWinError, + 1); + + ExpectReadFails(); +} + +TEST_F(ChromePromptChannelProtobufTest, LengthShortWrite) { + SetupCommunicationFailure(); + channel_->ConnectToCleaner(std::move(mock_cleaner_process_)); + + // Valid version + PostWriteByValue(kVersion); + + // The receiving side expects to receive the size of the request using 4 + // bytes. Setup data that is one byte less than that. + const std::vector<uint8_t> bytes(sizeof(uint32_t) - 1); + + // Post the incomplete size data. + PostWriteByPointer(bytes.data(), bytes.size(), true); + + WaitForDisconnect(); + + ExpectUniqueSample( + ChromePromptChannelProtobuf::ErrorCategory::kCustomError, + ChromePromptChannelProtobuf::CustomErrors::kRequestLengthShortRead); + + ExpectReadFails(); +} + +TEST_F(ChromePromptChannelProtobufTest, RequestShortWrite) { + SetupCommunicationFailure(); + channel_->ConnectToCleaner(std::move(mock_cleaner_process_)); + + // Valid version + PostWriteByValue(kVersion); + + constexpr uint32_t kSize = 10; + const std::vector<uint8_t> bytes(kSize); + + // Post the size of the read. It's too big. + PostWriteByValue(kSize + 1); + + // Post slightly less data. + PostWriteByPointer(bytes.data(), bytes.size(), true); + + WaitForDisconnect(); + + ExpectUniqueSample( + ChromePromptChannelProtobuf::ErrorCategory::kCustomError, + ChromePromptChannelProtobuf::CustomErrors::kRequestShortRead); ExpectReadFails(); }
diff --git a/chrome/browser/safe_browsing/download_protection/multipart_uploader.cc b/chrome/browser/safe_browsing/download_protection/multipart_uploader.cc new file mode 100644 index 0000000..446d3b8 --- /dev/null +++ b/chrome/browser/safe_browsing/download_protection/multipart_uploader.cc
@@ -0,0 +1,129 @@ +// 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. + +#include "chrome/browser/safe_browsing/download_protection/multipart_uploader.h" + +#include <memory> + +#include "base/bind.h" +#include "base/memory/scoped_refptr.h" +#include "base/task/post_task.h" +#include "base/time/time.h" +#include "content/public/browser/browser_task_traits.h" +#include "content/public/browser/browser_thread.h" +#include "net/base/mime_util.h" +#include "net/http/http_status_code.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" + +namespace safe_browsing { + +namespace { + +// Constants associated with exponential backoff. On each failure, we will +// increase the backoff by |kBackoffFactor|, starting from +// |kInitialBackoffSeconds|. If we fail after |kMaxRetryAttempts| retries, the +// upload fails. +const int kInitialBackoffSeconds = 1; +const int kBackoffFactor = 2; +const int kMaxRetryAttempts = 2; + +// Content type of a full multipart request +const char kUploadContentType[] = "multipart/related; boundary="; + +// Content type of the metadata and file contents. +const char kDataContentType[] = "Content-Type: application/octet-stream"; + +} // namespace + +MultipartUploadRequest::MultipartUploadRequest( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const GURL& base_url, + const std::string& metadata, + const std::string& data, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + Callback callback) + : base_url_(base_url), + metadata_(metadata), + data_(data), + boundary_(net::GenerateMimeMultipartBoundary()), + callback_(std::move(callback)), + current_backoff_(base::TimeDelta::FromSeconds(kInitialBackoffSeconds)), + retry_count_(0), + url_loader_factory_(url_loader_factory), + traffic_annotation_(traffic_annotation), + weak_factory_(this) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +} + +MultipartUploadRequest::~MultipartUploadRequest() {} + +void MultipartUploadRequest::Start() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + SendRequest(); +} + +std::string MultipartUploadRequest::GenerateRequestBody( + const std::string& metadata, + const std::string& data) { + return "--" + boundary_ + "\r\n" + kDataContentType + "\r\n\r\n" + metadata + + "\r\n--" + boundary_ + "\r\n" + kDataContentType + "\r\n\r\n" + data + + "\r\n--" + boundary_ + "--\r\n"; +} + +void MultipartUploadRequest::SendRequest() { + auto resource_request = std::make_unique<network::ResourceRequest>(); + resource_request->url = base_url_; + resource_request->method = "POST"; + resource_request->headers.SetHeader("X-Goog-Upload-Protocol", "multipart"); + + url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), + traffic_annotation_); + url_loader_->SetAllowHttpErrorResults(true); + url_loader_->AttachStringForUpload(GenerateRequestBody(metadata_, data_), + kUploadContentType + boundary_); + + url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + url_loader_factory_.get(), + base::BindOnce(&MultipartUploadRequest::OnURLLoaderComplete, + weak_factory_.GetWeakPtr())); +} + +void MultipartUploadRequest::OnURLLoaderComplete( + std::unique_ptr<std::string> response_body) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + int response_code = 0; + if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) + response_code = url_loader_->ResponseInfo()->headers->response_code(); + + RetryOrFinish(url_loader_->NetError(), response_code, + std::move(response_body)); +} + +void MultipartUploadRequest::RetryOrFinish( + int net_error, + int response_code, + std::unique_ptr<std::string> response_body) { + // TODO(drubery): Add metrics for success rates here. + if (net_error == net::OK && response_code == net::HTTP_OK) { + std::move(callback_).Run(net::OK, net::HTTP_OK, *response_body.get()); + } else { + if (retry_count_ < kMaxRetryAttempts) { + base::PostDelayedTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&MultipartUploadRequest::SendRequest, + weak_factory_.GetWeakPtr()), + current_backoff_); + current_backoff_ *= kBackoffFactor; + retry_count_++; + } else { + std::move(callback_).Run(net_error, response_code, *response_body.get()); + } + } +} + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/multipart_uploader.h b/chrome/browser/safe_browsing/download_protection/multipart_uploader.h new file mode 100644 index 0000000..63c95302 --- /dev/null +++ b/chrome/browser/safe_browsing/download_protection/multipart_uploader.h
@@ -0,0 +1,93 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_MULTIPART_UPLOADER_H_ +#define CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_MULTIPART_UPLOADER_H_ + +#include <string> + +#include "base/callback.h" +#include "base/gtest_prod_util.h" +#include "base/memory/scoped_refptr.h" +#include "base/memory/weak_ptr.h" +#include "net/traffic_annotation/network_traffic_annotation.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/network/public/cpp/simple_url_loader.h" +#include "url/gurl.h" + +namespace network { +class SharedURLLoaderFactory; +class SimpleURLLoader; +} // namespace network + +namespace safe_browsing { + +// This class encapsulates the upload of a file with metadata using the +// multipart protocol. This class is neither movable nor copyable. +class MultipartUploadRequest { + public: + using Callback = base::OnceCallback< + void(int net_error, int response_code, const std::string& response_data)>; + + // Creates a MultipartUploadRequest, which will upload |data| to the given + // |base_url| with |metadata| attached. + MultipartUploadRequest( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const GURL& base_url, + const std::string& metadata, + const std::string& data, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + Callback callback); + MultipartUploadRequest(const MultipartUploadRequest&) = delete; + MultipartUploadRequest& operator=(const MultipartUploadRequest&) = delete; + MultipartUploadRequest(MultipartUploadRequest&&) = delete; + MultipartUploadRequest& operator=(MultipartUploadRequest&&) = delete; + + ~MultipartUploadRequest(); + + // Start the upload. This must be called on the UI thread. When complete, this + // will call |callback_| on the UI thread. + void Start(); + + private: + FRIEND_TEST_ALL_PREFIXES(MultipartUploadRequestTest, GeneratesCorrectBody); + FRIEND_TEST_ALL_PREFIXES(MultipartUploadRequestTest, RetriesCorrectly); + + // Set the boundary between parts. + void set_boundary(const std::string& boundary) { boundary_ = boundary; } + + // Helper method to create the multipart request body. + std::string GenerateRequestBody(const std::string& metadata, + const std::string& data); + + // Called whenever a net request finishes (on success or failure). + void OnURLLoaderComplete(std::unique_ptr<std::string> response_body); + + // Called whenever a net request finishes (on success or failure). + void RetryOrFinish(int net_error, + int response_code, + std::unique_ptr<std::string> response_body); + + // Called to send a single request. Is overridden in tests. + virtual void SendRequest(); + + GURL base_url_; + std::string metadata_; + std::string data_; + std::string boundary_; + Callback callback_; + + base::TimeDelta current_backoff_; + int retry_count_; + + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; + std::unique_ptr<network::SimpleURLLoader> url_loader_; + net::NetworkTrafficAnnotationTag traffic_annotation_; + + base::WeakPtrFactory<MultipartUploadRequest> weak_factory_; +}; + +} // namespace safe_browsing + +#endif // CHROME_BROWSER_SAFE_BROWSING_DOWNLOAD_PROTECTION_MULTIPART_UPLOADER_H_
diff --git a/chrome/browser/safe_browsing/download_protection/multipart_uploader_unittest.cc b/chrome/browser/safe_browsing/download_protection/multipart_uploader_unittest.cc new file mode 100644 index 0000000..bfec3928 --- /dev/null +++ b/chrome/browser/safe_browsing/download_protection/multipart_uploader_unittest.cc
@@ -0,0 +1,80 @@ +// 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. + +#include "chrome/browser/safe_browsing/download_protection/multipart_uploader.h" + +#include <memory> + +#include "base/bind_helpers.h" +#include "base/run_loop.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "net/http/http_status_code.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace safe_browsing { + +using ::testing::Invoke; + +class MultipartUploadRequestTest : public testing::Test { + public: + MultipartUploadRequestTest() + : thread_bundle_( + base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME) {} + + protected: + content::TestBrowserThreadBundle thread_bundle_; +}; + +class MockMultipartUploadRequest : public MultipartUploadRequest { + public: + MockMultipartUploadRequest(const std::string& metadata, + const std::string& data, + Callback callback) + : MultipartUploadRequest(nullptr, + GURL(), + metadata, + data, + TRAFFIC_ANNOTATION_FOR_TESTS, + std::move(callback)) {} + + MOCK_METHOD(void, SendRequest, (), (override)); +}; + +TEST_F(MultipartUploadRequestTest, GeneratesCorrectBody) { + MultipartUploadRequest request(nullptr, GURL(), "metadata", "data", + TRAFFIC_ANNOTATION_FOR_TESTS, + base::DoNothing()); + + std::string expected_body = + "--boundary\r\n" + "Content-Type: application/octet-stream\r\n" + "\r\n" + "metadata\r\n" + "--boundary\r\n" + "Content-Type: application/octet-stream\r\n" + "\r\n" + "file data\r\n" + "--boundary--\r\n"; + + request.set_boundary("boundary"); + EXPECT_EQ(request.GenerateRequestBody("metadata", "file data"), + expected_body); +} + +TEST_F(MultipartUploadRequestTest, RetriesCorrectly) { + MockMultipartUploadRequest mock_request("metadata", "data", + base::DoNothing()); + EXPECT_CALL(mock_request, SendRequest()) + .Times(3) + .WillRepeatedly(Invoke([&mock_request]() { + mock_request.RetryOrFinish(net::OK, net::HTTP_BAD_REQUEST, + std::make_unique<std::string>("response")); + })); + mock_request.Start(); + thread_bundle_.FastForwardUntilNoTasksRemain(); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/search/chrome_colors/chrome_colors_service.cc b/chrome/browser/search/chrome_colors/chrome_colors_service.cc index f1b2975..9a13ba7 100644 --- a/chrome/browser/search/chrome_colors/chrome_colors_service.cc +++ b/chrome/browser/search/chrome_colors/chrome_colors_service.cc
@@ -5,15 +5,35 @@ #include "chrome/browser/search/chrome_colors/chrome_colors_service.h" #include "base/metrics/histogram_macros.h" -#include "base/metrics/user_metrics.h" +#include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/common/search/generated_colors_info.h" #include "chrome/common/search/selected_colors_info.h" +namespace { + +// Records whether current theme changes are confirmed or reverted. +void RecordChangesConfirmedHistogram(bool confirmed) { + UMA_HISTOGRAM_BOOLEAN("ChromeColors.ChangesConfirmed", confirmed); +} + +} // namespace + namespace chrome_colors { ChromeColorsService::ChromeColorsService(Profile* profile) - : theme_service_(ThemeServiceFactory::GetForProfile(profile)) {} + : theme_service_(ThemeServiceFactory::GetForProfile(profile)) { + // Determine if we are using a third-party NTP. When user switches to + // third-party NTP we should revert all the changes. + TemplateURLService* template_url_service = + TemplateURLServiceFactory::GetForProfile(profile); + if (template_url_service) { + search_provider_observer_ = std::make_unique<SearchProviderObserver>( + template_url_service, + base::BindRepeating(&ChromeColorsService::OnSearchProviderChanged, + weak_ptr_factory_.GetWeakPtr())); + } +} ChromeColorsService::~ChromeColorsService() = default; @@ -35,33 +55,54 @@ } void ChromeColorsService::ApplyDefaultTheme(content::WebContents* tab) { + if (!search_provider_observer_ || !search_provider_observer_->is_google()) + return; SaveThemeRevertState(tab); theme_service_->UseDefaultTheme(); } void ChromeColorsService::ApplyAutogeneratedTheme(SkColor color, content::WebContents* tab) { + if (!search_provider_observer_ || !search_provider_observer_->is_google()) + return; SaveThemeRevertState(tab); theme_service_->BuildFromColor(color); } void ChromeColorsService::RevertThemeChangesForTab(content::WebContents* tab) { - if (dialog_tab_ == tab) { - RecordAction(base::UserMetricsAction("ChromeColors_TabClosed")); - RevertThemeChanges(); - } + if (!search_provider_observer_ || !search_provider_observer_->is_google() || + dialog_tab_ != tab) + return; + RevertThemeChangesWithReason(RevertReason::TAB_CLOSED); } void ChromeColorsService::RevertThemeChanges() { - if (!revert_theme_changes_.is_null()) { - std::move(revert_theme_changes_).Run(); - ConfirmThemeChanges(); - } + if (!search_provider_observer_ || !search_provider_observer_->is_google()) + return; + RevertThemeChangesWithReason(RevertReason::MENU_CANCEL); } void ChromeColorsService::ConfirmThemeChanges() { + if (!search_provider_observer_ || !search_provider_observer_->is_google()) + return; revert_theme_changes_.Reset(); dialog_tab_ = nullptr; + RecordChangesConfirmedHistogram(true); +} + +void ChromeColorsService::RevertThemeChangesWithReason(RevertReason reason) { + if (!revert_theme_changes_.is_null()) { + std::move(revert_theme_changes_).Run(); + revert_theme_changes_.Reset(); + dialog_tab_ = nullptr; + UMA_HISTOGRAM_ENUMERATION("ChromeColors.RevertReason", reason); + RecordChangesConfirmedHistogram(false); + } +} + +void ChromeColorsService::OnSearchProviderChanged() { + if (search_provider_observer_ && !search_provider_observer_->is_google()) + RevertThemeChangesWithReason(RevertReason::SEARCH_PROVIDER_CHANGE); } void ChromeColorsService::SaveThemeRevertState(content::WebContents* tab) {
diff --git a/chrome/browser/search/chrome_colors/chrome_colors_service.h b/chrome/browser/search/chrome_colors/chrome_colors_service.h index d89a142..020cded 100644 --- a/chrome/browser/search/chrome_colors/chrome_colors_service.h +++ b/chrome/browser/search/chrome_colors/chrome_colors_service.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_SEARCH_CHROME_COLORS_CHROME_COLORS_SERVICE_H_ #include "base/callback.h" +#include "chrome/browser/search/search_provider_observer.h" #include "chrome/browser/themes/theme_service.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/browser/web_contents.h" @@ -15,10 +16,22 @@ namespace chrome_colors { +// Different cases that will trigger a revert for theme changes. +// This enum must match the numbering for ChromeColorsRevertReason in enums.xml. +// Do not reorder or remove items, and update kMaxValue when new items are +// added. +enum class RevertReason { + MENU_CANCEL = 0, + SEARCH_PROVIDER_CHANGE = 1, + TAB_CLOSED = 2, + kMaxValue = TAB_CLOSED, +}; + // Supports theme changes originating from the NTP customization menu. Users can // apply a Chrome color or the default theme, which will then either be reverted // or confirmed and made permanent. If third party themes are present, users // will also have a choice to permanently uninstall it. +// This service only works for Google NTP. class ChromeColorsService : public KeyedService { public: explicit ChromeColorsService(Profile* profile); @@ -37,7 +50,8 @@ void ApplyDefaultTheme(content::WebContents* tab); void ApplyAutogeneratedTheme(SkColor color, content::WebContents* tab); - // Reverts to the previous theme state before first Apply* was used. + // Reverts to the previous theme state before first Apply* was used. Called + // because user action on colors menu. void RevertThemeChanges(); // Same as |RevertThemeChanges| but only reverts theme changes if they were @@ -51,6 +65,12 @@ private: friend class ::TestChromeColorsService; + // Reverts to the previous theme state and records |reason|. + void RevertThemeChangesWithReason(RevertReason reason); + + // Callback for search provider change. + void OnSearchProviderChanged(); + // Saves the necessary state(revert callback and the current tab) for // performing theme change revert. Saves the state only if it is not set. void SaveThemeRevertState(content::WebContents* tab); @@ -67,6 +87,11 @@ // callback's creation. base::OnceClosure revert_theme_changes_; + // Keeps track of any changes in search engine provider. May be null. + std::unique_ptr<SearchProviderObserver> search_provider_observer_; + + base::WeakPtrFactory<ChromeColorsService> weak_ptr_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(ChromeColorsService); };
diff --git a/chrome/browser/search/chrome_colors/chrome_colors_service_unittest.cc b/chrome/browser/search/chrome_colors/chrome_colors_service_unittest.cc index 78a89008..c9865b0 100644 --- a/chrome/browser/search/chrome_colors/chrome_colors_service_unittest.cc +++ b/chrome/browser/search/chrome_colors/chrome_colors_service_unittest.cc
@@ -3,10 +3,17 @@ // found in the LICENSE file. #include "chrome/browser/search/chrome_colors/chrome_colors_service.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/search/chrome_colors/chrome_colors_factory.h" +#include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" +#include "chrome/browser/ui/search/local_ntp_test_utils.h" #include "chrome/test/base/browser_with_test_window_test.h" +#include "chrome/test/base/search_test_utils.h" +#include "components/search_engines/template_url.h" +#include "components/search_engines/template_url_data.h" +#include "components/search_engines/template_url_service.h" #include "content/public/test/web_contents_tester.h" #include "testing/gtest/include/gtest/gtest.h" @@ -16,6 +23,10 @@ void SetUp() override { BrowserWithTestWindowTest::SetUp(); + + template_url_service_ = TemplateURLServiceFactory::GetForProfile(profile()); + search_test_utils::WaitForTemplateURLServiceToLoad(template_url_service_); + chrome_colors_service_ = chrome_colors::ChromeColorsFactory::GetForProfile(profile()); @@ -27,8 +38,33 @@ return !chrome_colors_service_->revert_theme_changes_.is_null(); } + void SetUserSelectedDefaultSearchProvider(const std::string& base_url) { + TemplateURLData data; + data.SetShortName(base::UTF8ToUTF16(base_url)); + data.SetKeyword(base::UTF8ToUTF16(base_url)); + data.SetURL(base_url + "url?bar={searchTerms}"); + data.new_tab_url = base_url + "newtab"; + data.alternate_urls.push_back(base_url + "alt#quux={searchTerms}"); + + TemplateURL* template_url = + template_url_service_->Add(std::make_unique<TemplateURL>(data)); + template_url_service_->SetUserSelectedDefaultSearchProvider(template_url); + } + chrome_colors::ChromeColorsService* chrome_colors_service_; content::WebContents* tab_; + + private: + // BrowserWithTestWindowTest override: + TestingProfile* CreateProfile() override { + TestingProfile* profile = BrowserWithTestWindowTest::CreateProfile(); + TemplateURLServiceFactory::GetInstance()->SetTestingFactoryAndUse( + profile, + base::BindRepeating(&TemplateURLServiceFactory::BuildInstanceFor)); + return profile; + } + + TemplateURLService* template_url_service_; }; TEST_F(TestChromeColorsService, ApplyAndConfirmAutogeneratedTheme) { @@ -167,3 +203,23 @@ EXPECT_FALSE(theme_service->UsingAutogenerated()); EXPECT_FALSE(HasThemeRevertCallback()); } + +TEST_F(TestChromeColorsService, RevertThemeChangesWhenSwitchToThirdPartyNTP) { + ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile()); + ASSERT_TRUE(theme_service->UsingDefaultTheme()); + + SkColor theme_color = SkColorSetRGB(100, 0, 200); + chrome_colors_service_->ApplyAutogeneratedTheme(theme_color, tab_); + EXPECT_TRUE(theme_service->UsingAutogenerated()); + EXPECT_TRUE(HasThemeRevertCallback()); + + // Switching to third-party NTP should revert current changes. + SetUserSelectedDefaultSearchProvider("www.third-party-ntp.com"); + EXPECT_FALSE(theme_service->UsingAutogenerated()); + EXPECT_FALSE(HasThemeRevertCallback()); + + // When third-party NTP is present autogenerated theme shouldn't apply. + chrome_colors_service_->ApplyAutogeneratedTheme(theme_color, tab_); + EXPECT_FALSE(theme_service->UsingAutogenerated()); + EXPECT_FALSE(HasThemeRevertCallback()); +}
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc index d34cd2b..327c90e 100644 --- a/chrome/browser/search/instant_service.cc +++ b/chrome/browser/search/instant_service.cc
@@ -44,9 +44,6 @@ #include "components/ntp_tiles/constants.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" -#include "components/search/search.h" -#include "components/search_engines/template_url_service.h" -#include "components/search_engines/template_url_service_observer.h" #include "components/sync_preferences/pref_service_syncable.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" @@ -146,44 +143,6 @@ const char kNtpCustomBackgroundMainColor[] = "background_main_color"; -// Keeps track of any changes in search engine provider and notifies -// InstantService if a third-party search provider (i.e. a third-party NTP) is -// being used. -class InstantService::SearchProviderObserver - : public TemplateURLServiceObserver { - public: - explicit SearchProviderObserver(TemplateURLService* service, - base::RepeatingClosure callback) - : service_(service), - is_google_(search::DefaultSearchProviderIsGoogle(service_)), - callback_(std::move(callback)) { - DCHECK(service_); - service_->AddObserver(this); - } - - ~SearchProviderObserver() override { - if (service_) - service_->RemoveObserver(this); - } - - bool is_google() { return is_google_; } - - private: - void OnTemplateURLServiceChanged() override { - is_google_ = search::DefaultSearchProviderIsGoogle(service_); - callback_.Run(); - } - - void OnTemplateURLServiceShuttingDown() override { - service_->RemoveObserver(this); - service_ = nullptr; - } - - TemplateURLService* service_; - bool is_google_; - base::RepeatingClosure callback_; -}; - InstantService::InstantService(Profile* profile) : profile_(profile), most_visited_info_(std::make_unique<InstantMostVisitedInfo>()),
diff --git a/chrome/browser/search/instant_service.h b/chrome/browser/search/instant_service.h index 9cf98e2..723cb98e 100644 --- a/chrome/browser/search/instant_service.h +++ b/chrome/browser/search/instant_service.h
@@ -17,6 +17,7 @@ #include "base/observer_list.h" #include "base/optional.h" #include "build/build_config.h" +#include "chrome/browser/search/search_provider_observer.h" #include "components/history/core/browser/history_types.h" #include "components/image_fetcher/core/image_fetcher_impl.h" #include "components/keyed_service/core/keyed_service.h" @@ -180,8 +181,6 @@ void FetchCustomBackground(base::TimeTicks timestamp, const GURL& fetch_url); private: - class SearchProviderObserver; - friend class InstantExtendedTest; friend class InstantUnitTestBase; friend class LocalNTPBackgroundsAndDarkModeTest;
diff --git a/chrome/browser/search/search_provider_observer.cc b/chrome/browser/search/search_provider_observer.cc new file mode 100644 index 0000000..4a3bdaa --- /dev/null +++ b/chrome/browser/search/search_provider_observer.cc
@@ -0,0 +1,29 @@ +// 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. + +#include "chrome/browser/search/search_provider_observer.h" + +SearchProviderObserver::SearchProviderObserver(TemplateURLService* service, + base::RepeatingClosure callback) + : service_(service), + is_google_(search::DefaultSearchProviderIsGoogle(service_)), + callback_(std::move(callback)) { + DCHECK(service_); + service_->AddObserver(this); +} + +SearchProviderObserver::~SearchProviderObserver() { + if (service_) + service_->RemoveObserver(this); +} + +void SearchProviderObserver::OnTemplateURLServiceChanged() { + is_google_ = search::DefaultSearchProviderIsGoogle(service_); + callback_.Run(); +} + +void SearchProviderObserver::OnTemplateURLServiceShuttingDown() { + service_->RemoveObserver(this); + service_ = nullptr; +}
diff --git a/chrome/browser/search/search_provider_observer.h b/chrome/browser/search/search_provider_observer.h new file mode 100644 index 0000000..009506d7a --- /dev/null +++ b/chrome/browser/search/search_provider_observer.h
@@ -0,0 +1,34 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SEARCH_SEARCH_PROVIDER_OBSERVER_H_ +#define CHROME_BROWSER_SEARCH_SEARCH_PROVIDER_OBSERVER_H_ + +#include "chrome/browser/search/search.h" +#include "components/search_engines/template_url_service.h" +#include "components/search_engines/template_url_service_observer.h" + +// Keeps track of any changes in search engine provider and call +// the provided callback if a third-party search provider (i.e. a third-party +// NTP) is being used. +class SearchProviderObserver : public TemplateURLServiceObserver { + public: + explicit SearchProviderObserver(TemplateURLService* service, + base::RepeatingClosure callback); + + ~SearchProviderObserver() override; + + bool is_google() { return is_google_; } + + private: + // TemplateURLServiceObserver: + void OnTemplateURLServiceChanged() override; + void OnTemplateURLServiceShuttingDown() override; + + TemplateURLService* service_; + bool is_google_; + base::RepeatingClosure callback_; +}; + +#endif // CHROME_BROWSER_SEARCH_SEARCH_PROVIDER_OBSERVER_H_
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc index 4424c63..7552030 100644 --- a/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc +++ b/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
@@ -77,6 +77,9 @@ Profile::FromBrowserContext(web_contents->GetBrowserContext()); return IsSendingEnabled() && IsUserSyncTypeActive(profile) && HasValidTargetDevice(profile) && + // Send tab to self should not be offered for tel links, click to call + // feature will be handling tel links. + !link_url.SchemeIs(url::kTelScheme) && (IsContentRequirementsMet(web_contents->GetURL(), profile) || IsContentRequirementsMet(link_url, profile)); }
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_util_unittest.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_util_unittest.cc index 891d033..1a467b0 100644 --- a/chrome/browser/send_tab_to_self/send_tab_to_self_util_unittest.cc +++ b/chrome/browser/send_tab_to_self/send_tab_to_self_util_unittest.cc
@@ -132,6 +132,39 @@ EXPECT_FALSE(IsContentRequirementsMet(url_, incognito_profile_)); } +TEST_F(SendTabToSelfUtilTest, ShouldOfferFeatureForTelephoneLink) { + url_ = GURL("tel:07387252578"); + + // Set the IsSendingEnable, IsUserSyncTypeActive and + // HasValidTargetDevice to true + scoped_feature_list_.InitWithFeatures( + {switches::kSyncSendTabToSelf, kSendTabToSelfShowSendingUI}, {}); + AddTab(browser(), url_); + SendTabToSelfSyncServiceFactory::GetInstance()->SetTestingFactory( + profile(), base::BindRepeating(&BuildTestSendTabToSelfSyncService)); + + // get web contents + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + EXPECT_FALSE(ShouldOfferFeatureForLink(web_contents, url_)); +} + +TEST_F(SendTabToSelfUtilTest, ShouldOfferFeatureForGoogleLink) { + // Set the IsSendingEnable, IsUserSyncTypeActive and + // HasValidTargetDevice to true + scoped_feature_list_.InitWithFeatures( + {switches::kSyncSendTabToSelf, kSendTabToSelfShowSendingUI}, {}); + AddTab(browser(), url_); + SendTabToSelfSyncServiceFactory::GetInstance()->SetTestingFactory( + profile(), base::BindRepeating(&BuildTestSendTabToSelfSyncService)); + + // get web contents + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + + EXPECT_TRUE(ShouldOfferFeatureForLink(web_contents, url_)); +} } // namespace } // namespace send_tab_to_self
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc index 1bfe2943..437173c 100644 --- a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc +++ b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer.cc
@@ -61,7 +61,8 @@ url_ = params.link_url; devices_ = sharing_service_->GetDeviceCandidates( static_cast<int>(SharingDeviceCapability::kTelephony)); - LogClickToCallDevicesToShow(devices_.size()); + LogClickToCallDevicesToShow(kSharingClickToCallUiContextMenu, + devices_.size()); if (devices_.empty()) return;
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer_unittest.cc b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer_unittest.cc index 3e1c96c..87d5fa2 100644 --- a/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer_unittest.cc +++ b/chrome/browser/sharing/click_to_call/click_to_call_context_menu_observer_unittest.cc
@@ -47,14 +47,15 @@ class MockSharingService : public SharingService { public: explicit MockSharingService(std::unique_ptr<SharingFCMHandler> fcm_handler) - : SharingService(nullptr, - nullptr, - nullptr, - nullptr, + : SharingService(/* sync_prefs= */ nullptr, + /* vapid_key_manager= */ nullptr, + /* sharing_device_registration= */ nullptr, + /* fcm_sender= */ nullptr, std::move(fcm_handler), - nullptr, - nullptr, - nullptr) {} + /* gcm_driver= */ nullptr, + /* device_info_tracker= */ nullptr, + /* local_device_info_provider= */ nullptr, + /* sync_service */ nullptr) {} ~MockSharingService() override = default;
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller.cc b/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller.cc index cc5d714..b7381087 100644 --- a/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller.cc +++ b/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller.cc
@@ -81,7 +81,10 @@ void ClickToCallSharingDialogController::ShowNewDialog() { if (dialog_) dialog_->Hide(); - DCHECK(!dialog_); + + // Treat the dialog as closed as the process of closing the native widget + // might be async. + dialog_ = nullptr; Browser* browser = chrome::FindBrowserWithWebContents(web_contents_); auto* window = browser ? browser->window() : nullptr; @@ -174,7 +177,12 @@ web_contents_); } -void ClickToCallSharingDialogController::OnDialogClosed() { +void ClickToCallSharingDialogController::OnDialogClosed( + ClickToCallDialog* dialog) { + // Ignore already replaced dialogs. + if (dialog != dialog_) + return; + dialog_ = nullptr; UpdateIcon(); }
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller.h b/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller.h index 19964663..6c26b47 100644 --- a/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller.h +++ b/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller.h
@@ -45,7 +45,7 @@ void OnAppChosen(const App& app) override; // Called by the ClickToCallDialogView when it is being closed. - void OnDialogClosed(); + void OnDialogClosed(ClickToCallDialog* dialog); // Called by the ClickToCallDialogView when the help text got clicked. void OnHelpTextClicked();
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller_unittest.cc b/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller_unittest.cc index 71994b7..54b85d0a 100644 --- a/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller_unittest.cc +++ b/chrome/browser/sharing/click_to_call/click_to_call_sharing_dialog_controller_unittest.cc
@@ -49,6 +49,7 @@ /* sharing_device_registration= */ nullptr, /* fcm_sender= */ nullptr, std::move(fcm_handler), + /* gcm_driver= */ nullptr, /* device_info_tracker= */ nullptr, /* local_device_info_provider= */ nullptr, /* sync_service */ nullptr) {}
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_utils_unittest.cc b/chrome/browser/sharing/click_to_call/click_to_call_utils_unittest.cc index 6bfce60..9843dc9 100644 --- a/chrome/browser/sharing/click_to_call/click_to_call_utils_unittest.cc +++ b/chrome/browser/sharing/click_to_call/click_to_call_utils_unittest.cc
@@ -39,14 +39,15 @@ class MockSharingService : public SharingService { public: explicit MockSharingService(std::unique_ptr<SharingFCMHandler> fcm_handler) - : SharingService(nullptr, - nullptr, - nullptr, - nullptr, + : SharingService(/* sync_prefs= */ nullptr, + /* vapid_key_manager= */ nullptr, + /* sharing_device_registration= */ nullptr, + /* fcm_sender= */ nullptr, std::move(fcm_handler), - nullptr, - nullptr, - nullptr) {} + /* gcm_driver= */ nullptr, + /* device_info_tracker= */ nullptr, + /* local_device_info_provider= */ nullptr, + /* sync_service */ nullptr) {} ~MockSharingService() override = default;
diff --git a/chrome/browser/sharing/sharing_device_registration.cc b/chrome/browser/sharing/sharing_device_registration.cc index b62c08d..4e7d35080 100644 --- a/chrome/browser/sharing/sharing_device_registration.cc +++ b/chrome/browser/sharing/sharing_device_registration.cc
@@ -15,11 +15,9 @@ #include "chrome/browser/sharing/sharing_constants.h" #include "chrome/browser/sharing/sharing_device_info.h" #include "chrome/browser/sharing/sharing_device_registration_result.h" -#include "chrome/browser/sharing/sharing_metrics.h" #include "chrome/browser/sharing/sharing_sync_preference.h" #include "chrome/browser/sharing/vapid_key_manager.h" #include "components/gcm_driver/crypto/p256_key_util.h" -#include "components/gcm_driver/gcm_driver.h" #include "components/gcm_driver/instance_id/instance_id_driver.h" #include "components/sync_device_info/device_info.h" #include "components/sync_device_info/local_device_info_provider.h" @@ -33,12 +31,10 @@ SharingSyncPreference* sharing_sync_preference, instance_id::InstanceIDDriver* instance_id_driver, VapidKeyManager* vapid_key_manager, - gcm::GCMDriver* gcm_driver, syncer::LocalDeviceInfoProvider* local_device_info_provider) : sharing_sync_preference_(sharing_sync_preference), instance_id_driver_(instance_id_driver), vapid_key_manager_(vapid_key_manager), - gcm_driver_(gcm_driver), local_device_info_provider_(local_device_info_provider) {} SharingDeviceRegistration::~SharingDeviceRegistration() = default; @@ -46,8 +42,6 @@ void SharingDeviceRegistration::RegisterDevice(RegistrationCallback callback) { base::Optional<std::string> authorized_entity = GetAuthorizationEntity(); if (!authorized_entity) { - LogSharingRegistrationResult( - SharingDeviceRegistrationResult::kEncryptionError); std::move(callback).Run(SharingDeviceRegistrationResult::kEncryptionError); return; } @@ -56,7 +50,8 @@ if (registration && registration->authorized_entity == authorized_entity && (base::Time::Now() - registration->timestamp < kRegistrationExpiration)) { // Authorized entity hasn't changed nor has expired, skip to next step. - RetrieveEncrpytionInfo(std::move(callback), registration->fcm_token); + RetrieveEncryptionInfo(std::move(callback), registration->authorized_entity, + registration->fcm_token); return; } @@ -78,34 +73,33 @@ case instance_id::InstanceID::SUCCESS: sharing_sync_preference_->SetFCMRegistration( {authorized_entity, fcm_registration_token, base::Time::Now()}); - RetrieveEncrpytionInfo(std::move(callback), fcm_registration_token); + RetrieveEncryptionInfo(std::move(callback), authorized_entity, + fcm_registration_token); break; case instance_id::InstanceID::NETWORK_ERROR: case instance_id::InstanceID::SERVER_ERROR: case instance_id::InstanceID::ASYNC_OPERATION_PENDING: - LogSharingRegistrationResult( - SharingDeviceRegistrationResult::kFcmTransientError); std::move(callback).Run( SharingDeviceRegistrationResult::kFcmTransientError); break; case instance_id::InstanceID::INVALID_PARAMETER: case instance_id::InstanceID::UNKNOWN_ERROR: case instance_id::InstanceID::DISABLED: - LogSharingRegistrationResult( - SharingDeviceRegistrationResult::kFcmFatalError); std::move(callback).Run(SharingDeviceRegistrationResult::kFcmFatalError); break; } } -void SharingDeviceRegistration::RetrieveEncrpytionInfo( +void SharingDeviceRegistration::RetrieveEncryptionInfo( RegistrationCallback callback, + const std::string& authorized_entity, const std::string& fcm_registration_token) { - gcm_driver_->GetEncryptionInfo( - kSharingFCMAppID, - base::BindOnce(&SharingDeviceRegistration::OnEncryptionInfoReceived, - weak_ptr_factory_.GetWeakPtr(), std::move(callback), - fcm_registration_token)); + instance_id_driver_->GetInstanceID(kSharingFCMAppID) + ->GetEncryptionInfo( + authorized_entity, + base::BindOnce(&SharingDeviceRegistration::OnEncryptionInfoReceived, + weak_ptr_factory_.GetWeakPtr(), std::move(callback), + fcm_registration_token)); } void SharingDeviceRegistration::OnEncryptionInfoReceived( @@ -116,8 +110,6 @@ const syncer::DeviceInfo* local_device_info = local_device_info_provider_->GetLocalDeviceInfo(); if (!local_device_info) { - LogSharingRegistrationResult( - SharingDeviceRegistrationResult::kSyncServiceError); std::move(callback).Run(SharingDeviceRegistrationResult::kSyncServiceError); return; } @@ -127,30 +119,26 @@ fcm_registration_token, std::move(p256dh), std::move(auth_secret), device_capabilities); sharing_sync_preference_->SetSyncDevice(local_device_info->guid(), device); - LogSharingRegistrationResult(SharingDeviceRegistrationResult::kSuccess); std::move(callback).Run(SharingDeviceRegistrationResult::kSuccess); } void SharingDeviceRegistration::UnregisterDevice( RegistrationCallback callback) { - sharing_sync_preference_->ClearFCMRegistration(); + auto registration = sharing_sync_preference_->GetFCMRegistration(); + if (!registration) { + std::move(callback).Run( + SharingDeviceRegistrationResult::kDeviceNotRegistered); + return; + } const syncer::DeviceInfo* local_device_info = local_device_info_provider_->GetLocalDeviceInfo(); if (local_device_info) sharing_sync_preference_->RemoveDevice(local_device_info->guid()); - base::Optional<std::string> authorized_entity = GetAuthorizationEntity(); - if (!authorized_entity) { - LogSharingUnegistrationResult( - SharingDeviceRegistrationResult::kEncryptionError); - std::move(callback).Run(SharingDeviceRegistrationResult::kEncryptionError); - return; - } - instance_id_driver_->GetInstanceID(kSharingFCMAppID) ->DeleteToken( - *authorized_entity, kFCMScope, + registration->authorized_entity, kFCMScope, base::BindOnce(&SharingDeviceRegistration::OnFCMTokenDeleted, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } @@ -163,21 +151,17 @@ // INVALID_PARAMETER is expected if InstanceID.GetToken hasn't been // invoked since restart. case instance_id::InstanceID::INVALID_PARAMETER: - LogSharingUnegistrationResult(SharingDeviceRegistrationResult::kSuccess); + sharing_sync_preference_->ClearFCMRegistration(); std::move(callback).Run(SharingDeviceRegistrationResult::kSuccess); return; case instance_id::InstanceID::NETWORK_ERROR: case instance_id::InstanceID::SERVER_ERROR: case instance_id::InstanceID::ASYNC_OPERATION_PENDING: - LogSharingUnegistrationResult( - SharingDeviceRegistrationResult::kFcmTransientError); std::move(callback).Run( SharingDeviceRegistrationResult::kFcmTransientError); return; case instance_id::InstanceID::UNKNOWN_ERROR: case instance_id::InstanceID::DISABLED: - LogSharingUnegistrationResult( - SharingDeviceRegistrationResult::kFcmFatalError); std::move(callback).Run(SharingDeviceRegistrationResult::kFcmFatalError); return; }
diff --git a/chrome/browser/sharing/sharing_device_registration.h b/chrome/browser/sharing/sharing_device_registration.h index 5980cba..9e514bc 100644 --- a/chrome/browser/sharing/sharing_device_registration.h +++ b/chrome/browser/sharing/sharing_device_registration.h
@@ -18,10 +18,6 @@ class InstanceIDDriver; } -namespace gcm { -class GCMDriver; -} - namespace syncer { class LocalDeviceInfoProvider; } @@ -41,7 +37,6 @@ SharingSyncPreference* prefs, instance_id::InstanceIDDriver* instance_id_driver, VapidKeyManager* vapid_key_manager, - gcm::GCMDriver* gcm_driver, syncer::LocalDeviceInfoProvider* device_info_tracker); virtual ~SharingDeviceRegistration(); @@ -71,8 +66,9 @@ void OnFCMTokenDeleted(RegistrationCallback callback, instance_id::InstanceID::Result result); - // Retrieve encryption info from GCMDriver. - void RetrieveEncrpytionInfo(RegistrationCallback callback, + // Retrieve encryption info from InstanceID. + void RetrieveEncryptionInfo(RegistrationCallback callback, + const std::string& authorized_entity, const std::string& fcm_registration_token); // Callback function responsible for saving device registration information in @@ -94,7 +90,6 @@ SharingSyncPreference* sharing_sync_preference_; instance_id::InstanceIDDriver* instance_id_driver_; VapidKeyManager* vapid_key_manager_; - gcm::GCMDriver* gcm_driver_; syncer::LocalDeviceInfoProvider* local_device_info_provider_; base::WeakPtrFactory<SharingDeviceRegistration> weak_ptr_factory_{this};
diff --git a/chrome/browser/sharing/sharing_device_registration_result.h b/chrome/browser/sharing/sharing_device_registration_result.h index f2fef8b..d72f527 100644 --- a/chrome/browser/sharing/sharing_device_registration_result.h +++ b/chrome/browser/sharing/sharing_device_registration_result.h
@@ -20,8 +20,10 @@ kFcmTransientError = 3, // Failed with FCM fatal error. kFcmFatalError = 4, + // Device has not been registered. + kDeviceNotRegistered = 5, // Max value for historgram. - kMaxValue = kFcmFatalError, + kMaxValue = kDeviceNotRegistered, }; #endif // CHROME_BROWSER_SHARING_SHARING_DEVICE_REGISTRATION_RESULT_H_
diff --git a/chrome/browser/sharing/sharing_device_registration_unittest.cc b/chrome/browser/sharing/sharing_device_registration_unittest.cc index ba555d6..a0f8dfd 100644 --- a/chrome/browser/sharing/sharing_device_registration_unittest.cc +++ b/chrome/browser/sharing/sharing_device_registration_unittest.cc
@@ -17,8 +17,6 @@ #include "chrome/browser/sharing/sharing_device_registration_result.h" #include "chrome/browser/sharing/sharing_sync_preference.h" #include "chrome/browser/sharing/vapid_key_manager.h" -#include "components/gcm_driver/fake_gcm_driver.h" -#include "components/gcm_driver/gcm_driver.h" #include "components/gcm_driver/instance_id/instance_id_driver.h" #include "components/sync_device_info/device_info.h" #include "components/sync_preferences/testing_pref_service_syncable.h" @@ -95,17 +93,7 @@ void SetFCMToken(std::string fcm_token) { fcm_token_ = std::move(fcm_token); } - private: - InstanceID::Result result_; - std::string fcm_token_; -}; - -class FakeEncryptionGCMDriver : public FakeGCMDriver { - public: - FakeEncryptionGCMDriver() = default; - ~FakeEncryptionGCMDriver() override = default; - - void GetEncryptionInfo(const std::string& app_id, + void GetEncryptionInfo(const std::string& authorized_entity, GetEncryptionInfoCallback callback) override { std::move(callback).Run(p256dh_, auth_secret_); } @@ -117,7 +105,8 @@ } private: - DISALLOW_COPY_AND_ASSIGN(FakeEncryptionGCMDriver); + InstanceID::Result result_; + std::string fcm_token_; std::string p256dh_ = kDevicep256dh; std::string auth_secret_ = kDeviceAuthSecret; }; @@ -130,7 +119,6 @@ sharing_device_registration_(&sync_prefs_, &mock_instance_id_driver_, &vapid_key_manager_, - &fake_encryption_gcm_driver_, &fake_local_device_info_provider_) { SharingSyncPreference::RegisterProfilePrefs(prefs_.registry()); } @@ -177,7 +165,6 @@ base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME_AND_NOW}; sync_preferences::TestingPrefServiceSyncable prefs_; - FakeEncryptionGCMDriver fake_encryption_gcm_driver_; NiceMock<MockInstanceIDDriver> mock_instance_id_driver_; FakeLocalDeviceInfoProvider fake_local_device_info_provider_; FakeInstanceID fake_instance_id_; @@ -245,8 +232,7 @@ // Instance ID now returns a new token, however it shouldn't be invoked. SetInstanceIDFCMToken(kFCMToken2); // GCMDriver now returns new encryption info. - fake_encryption_gcm_driver_.SetEncryptionInfo(kDevicep256dh2, - kDeviceAuthSecret2); + fake_instance_id_.SetEncryptionInfo(kDevicep256dh2, kDeviceAuthSecret2); // Register device again without changing VAPID keys. RegisterDeviceSync(); @@ -329,6 +315,10 @@ ASSERT_EQ(devices_.end(), devices_.find(guid)); EXPECT_FALSE(fcm_registration_); + // Further unregister does nothing and returns kDeviceNotRegistered. + UnregisterDeviceSync(); + EXPECT_EQ(SharingDeviceRegistrationResult::kDeviceNotRegistered, result_); + // Register the device again, Instance.GetToken will be attempted once more, // which will return a different FCM token. SetInstanceIDFCMToken(kFCMToken2);
diff --git a/chrome/browser/sharing/sharing_fcm_sender.cc b/chrome/browser/sharing/sharing_fcm_sender.cc index 42a41bc..a2f66d91 100644 --- a/chrome/browser/sharing/sharing_fcm_sender.cc +++ b/chrome/browser/sharing/sharing_fcm_sender.cc
@@ -77,9 +77,16 @@ web_push_message.urgency = gcm::WebPushMessage::Urgency::kHigh; message.SerializeToString(&web_push_message.payload); + auto fcm_registration = sync_preference_->GetFCMRegistration(); + if (!fcm_registration) { + LOG(ERROR) << "Unable to retrieve FCM registration"; + std::move(callback).Run(base::nullopt); + return; + } + gcm_driver_->SendWebPushMessage( - kSharingFCMAppID, - /* authorized_entity= */ std::string(), target.p256dh, target.auth_secret, - target.fcm_token, vapid_key_manager_->GetOrCreateKey(), - std::move(web_push_message), std::move(callback)); + kSharingFCMAppID, fcm_registration->authorized_entity, target.p256dh, + target.auth_secret, target.fcm_token, + vapid_key_manager_->GetOrCreateKey(), std::move(web_push_message), + std::move(callback)); }
diff --git a/chrome/browser/sharing/sharing_fcm_sender_unittest.cc b/chrome/browser/sharing/sharing_fcm_sender_unittest.cc index 9ab543e7..12fbcd51 100644 --- a/chrome/browser/sharing/sharing_fcm_sender_unittest.cc +++ b/chrome/browser/sharing/sharing_fcm_sender_unittest.cc
@@ -32,6 +32,7 @@ constexpr int kNoCapabilities = static_cast<int>(SharingDeviceCapability::kNone); const char kSenderGuid[] = "test_sender_guid"; +const char kAuthorizedEntity[] = "authorized_entity"; const int kTtlSeconds = 10; class MockGCMDriver : public gcm::FakeGCMDriver { @@ -140,6 +141,7 @@ TEST_F(SharingFCMSenderTest, SendMessageToDevice) { std::string guid = base::GenerateGUID(); sync_prefs_->SetSyncDevice(guid, CreateFakeSyncDevice()); + sync_prefs_->SetFCMRegistration({kAuthorizedEntity, "", base::Time::Now()}); std::unique_ptr<crypto::ECPrivateKey> vapid_key = crypto::ECPrivateKey::Create(); @@ -153,9 +155,9 @@ EXPECT_CALL( mock_gcm_driver_, - SendWebPushMessage(Eq(kSharingFCMAppID), Eq(""), Eq(kP256dh), - Eq(kAuthSecret), Eq(kFcmToken), Eq(vapid_key.get()), - WebPushMessageMatcher(), _)); + SendWebPushMessage(Eq(kSharingFCMAppID), Eq(kAuthorizedEntity), + Eq(kP256dh), Eq(kAuthSecret), Eq(kFcmToken), + Eq(vapid_key.get()), WebPushMessageMatcher(), _)); sharing_fcm_sender_->SendMessageToDevice( guid, base::TimeDelta::FromSeconds(kTtlSeconds), SharingMessage(), @@ -166,6 +168,7 @@ TEST_F(SharingFCMSenderTest, SendMessageBeforeLocalDeviceInfoReady) { std::string guid = base::GenerateGUID(); sync_prefs_->SetSyncDevice(guid, CreateFakeSyncDevice()); + sync_prefs_->SetFCMRegistration({kAuthorizedEntity, "", base::Time::Now()}); std::unique_ptr<crypto::ECPrivateKey> vapid_key = crypto::ECPrivateKey::Create(); @@ -189,9 +192,9 @@ EXPECT_CALL( mock_gcm_driver_, - SendWebPushMessage(Eq(kSharingFCMAppID), Eq(""), Eq(kP256dh), - Eq(kAuthSecret), Eq(kFcmToken), Eq(vapid_key.get()), - WebPushMessageMatcher(), _)); + SendWebPushMessage(Eq(kSharingFCMAppID), Eq(kAuthorizedEntity), + Eq(kP256dh), Eq(kAuthSecret), Eq(kFcmToken), + Eq(vapid_key.get()), WebPushMessageMatcher(), _)); local_device_info_provider_.SetReady(true); }
diff --git a/chrome/browser/sharing/sharing_metrics.cc b/chrome/browser/sharing/sharing_metrics.cc index c1657e2..c95490b 100644 --- a/chrome/browser/sharing/sharing_metrics.cc +++ b/chrome/browser/sharing/sharing_metrics.cc
@@ -54,18 +54,33 @@ base::UmaHistogramEnumeration("Sharing.VapidKeyCreationResult", result); } -void LogClickToCallDevicesToShow(int count) { +void LogClickToCallDevicesToShow(const char* histogram_suffix, int count) { + // Explicitly log both the base and the suffixed histogram because the base + // aggregation is not automatically generated. base::UmaHistogramExactLinear("Sharing.ClickToCallDevicesToShow", count, /*value_max=*/20); + base::UmaHistogramExactLinear( + base::StrCat({"Sharing.ClickToCallDevicesToShow.", histogram_suffix}), + count, + /*value_max=*/20); } -void LogClickToCallAppsToShow(int count) { +void LogClickToCallAppsToShow(const char* histogram_suffix, int count) { + // Explicitly log both the base and the suffixed histogram because the base + // aggregation is not automatically generated. base::UmaHistogramExactLinear("Sharing.ClickToCallAppsToShow", count, /*value_max=*/20); + base::UmaHistogramExactLinear( + base::StrCat({"Sharing.ClickToCallAppsToShow.", histogram_suffix}), count, + /*value_max=*/20); } void LogClickToCallSelectedDeviceIndex(const char* histogram_suffix, int index) { + // Explicitly log both the base and the suffixed histogram because the base + // aggregation is not automatically generated. + base::UmaHistogramExactLinear("Sharing.ClickToCallSelectedDeviceIndex", index, + /*value_max=*/20); base::UmaHistogramExactLinear( base::StrCat( {"Sharing.ClickToCallSelectedDeviceIndex.", histogram_suffix}), @@ -74,6 +89,10 @@ } void LogClickToCallSelectedAppIndex(const char* histogram_suffix, int index) { + // Explicitly log both the base and the suffixed histogram because the base + // aggregation is not automatically generated. + base::UmaHistogramExactLinear("Sharing.ClickToCallSelectedAppIndex", index, + /*value_max=*/20); base::UmaHistogramExactLinear( base::StrCat({"Sharing.ClickToCallSelectedAppIndex.", histogram_suffix}), index, @@ -83,3 +102,7 @@ void LogSharingMessageAckTime(base::TimeDelta time) { base::UmaHistogramMediumTimes("Sharing.MessageAckTime", time); } + +void LogClickToCallDialogShown(SharingClickToCallDialogType type) { + base::UmaHistogramEnumeration("Sharing.ClickToCallDialogShown", type); +}
diff --git a/chrome/browser/sharing/sharing_metrics.h b/chrome/browser/sharing/sharing_metrics.h index 208ced2..669fe72 100644 --- a/chrome/browser/sharing/sharing_metrics.h +++ b/chrome/browser/sharing/sharing_metrics.h
@@ -22,6 +22,18 @@ kMaxValue = kExportPrivateKeyFailed, }; +// The types of dialogs that can be shown for Click to Call. +// These values are logged to UMA. Entries should not be renumbered and numeric +// values should never be reused. Please keep in sync with +// "SharingClickToCallDialogType" in src/tools/metrics/histograms/enums.xml. +enum class SharingClickToCallDialogType { + kDialogWithDevicesMaybeApps = 0, + kDialogWithoutDevicesWithApp = 1, + kEducationalDialog = 2, + kErrorDialog = 3, + kMaxValue = kErrorDialog, +}; + // These histogram suffixes must match the ones in SharingClickToCallUi defined // in histograms.xml. const char kSharingClickToCallUiContextMenu[] = "ContextMenu"; @@ -45,25 +57,34 @@ void LogSharingVapidKeyCreationResult(SharingVapidKeyCreationResult result); // Logs the number of available devices that are about to be shown in a UI for -// picking a device to start a phone call on. -void LogClickToCallDevicesToShow(int count); +// picking a device to start a phone call on. The |histogram_suffix| indicates +// in which UI this event happened and must match one from SharingClickToCallUi +// defined in histograms.xml - use the constants defined in this file for that. +void LogClickToCallDevicesToShow(const char* histogram_suffix, int count); // Logs the number of available apps that are about to be shown in a UI for -// picking an app to start a phone call with. -void LogClickToCallAppsToShow(int count); +// picking an app to start a phone call with. The |histogram_suffix| indicates +// in which UI this event happened and must match one from SharingClickToCallUi +// defined in histograms.xml - use the constants defined in this file for that. +void LogClickToCallAppsToShow(const char* histogram_suffix, int count); // Logs the |index| of the device selected by the user for Click to Call. The // |histogram_suffix| indicates in which UI this event happened and must match -// one from SharingClickToCallUi defined in histograms.xml. +// one from SharingClickToCallUi defined in histograms.xml - use the constants +// defined in this file for that. void LogClickToCallSelectedDeviceIndex(const char* histogram_suffix, int index); // Logs the |index| of the app selected by the user for Click to Call. The // |histogram_suffix| indicates in which UI this event happened and must match -// one from SharingClickToCallUi defined in histograms.xml. +// one from SharingClickToCallUi defined in histograms.xml - use the constants +// defined in this file for that. void LogClickToCallSelectedAppIndex(const char* histogram_suffix, int index); // Logs to UMA the time from sending a FCM message from the Sharing service // until an ack message is received for it. void LogSharingMessageAckTime(base::TimeDelta time); +// Logs to UMA the |type| of dialog shown for Click to Call. +void LogClickToCallDialogShown(SharingClickToCallDialogType type); + #endif // CHROME_BROWSER_SHARING_SHARING_METRICS_H_
diff --git a/chrome/browser/sharing/sharing_service.cc b/chrome/browser/sharing/sharing_service.cc index 4a02587..7c3b3ca 100644 --- a/chrome/browser/sharing/sharing_service.cc +++ b/chrome/browser/sharing/sharing_service.cc
@@ -27,6 +27,8 @@ #include "chrome/browser/sharing/sharing_metrics.h" #include "chrome/browser/sharing/sharing_sync_preference.h" #include "chrome/browser/sharing/vapid_key_manager.h" +#include "components/gcm_driver/crypto/gcm_encryption_provider.h" +#include "components/gcm_driver/gcm_driver.h" #include "components/sync/driver/sync_service.h" #include "components/sync_device_info/device_info.h" #include "components/sync_device_info/device_info_tracker.h" @@ -39,6 +41,7 @@ std::unique_ptr<SharingDeviceRegistration> sharing_device_registration, std::unique_ptr<SharingFCMSender> fcm_sender, std::unique_ptr<SharingFCMHandler> fcm_handler, + gcm::GCMDriver* gcm_driver, syncer::DeviceInfoTracker* device_info_tracker, syncer::LocalDeviceInfoProvider* local_device_info_provider, syncer::SyncService* sync_service) @@ -52,6 +55,19 @@ sync_service_(sync_service), backoff_entry_(&kRetryBackoffPolicy), state_(State::DISABLED) { + // Remove old encryption info with empty authrozed_entity to avoid DCHECK. + // See http://crbug/987591 + if (gcm_driver) { + gcm::GCMEncryptionProvider* encryption_provider = + gcm_driver->GetEncryptionProviderInternal(); + if (encryption_provider) { + encryption_provider->RemoveEncryptionInfo( + kSharingFCMAppID, /*authorized_entity=*/std::string(), + base::DoNothing()); + } + } + + // Initialize sharing handlers. fcm_handler_->AddSharingHandler( chrome_browser_sharing::SharingMessage::kAckMessage, &ack_message_handler_); @@ -76,8 +92,7 @@ sync_service_->AddObserver(this); // Only unregister if sync is disabled (not initializing). - if (sync_service_ && sync_service->GetTransportState() == - syncer::SyncService::TransportState::DISABLED) { + if (IsSyncDisabled()) { // state_ is kept as State::DISABLED as SharingService has never registered, // and only doing clean up via UnregisterDevice(). UnregisterDevice(); @@ -239,7 +254,7 @@ sync_service_->RemoveObserver(this); UnregisterDevice(); } - } else if (state_ == State::ACTIVE) { + } else if (IsSyncDisabled() && state_ == State::ACTIVE) { state_ = State::UNREGISTERING; fcm_handler_->StopListening(); sync_prefs_->ClearVapidKeyChangeObserver(); @@ -259,6 +274,7 @@ void SharingService::OnDeviceRegistered( SharingDeviceRegistrationResult result) { + LogSharingRegistrationResult(result); switch (result) { case SharingDeviceRegistrationResult::kSuccess: backoff_entry_.InformOfRequest(true); @@ -271,7 +287,7 @@ // state_ is kept as State::ACTIVE during re-registration. sync_prefs_->SetVapidKeyChangeObserver(base::BindRepeating( &SharingService::RegisterDevice, weak_ptr_factory_.GetWeakPtr())); - } else { + } else if (IsSyncDisabled()) { // In case sync is disabled during registration, unregister it. state_ = State::UNREGISTERING; UnregisterDevice(); @@ -298,11 +314,15 @@ // No need to bother retrying in the case of one of fatal errors. LOG(ERROR) << "Device registration failed with fatal error"; break; + case SharingDeviceRegistrationResult::kDeviceNotRegistered: + // Register device cannot return kDeviceNotRegistered. + NOTREACHED(); } } void SharingService::OnDeviceUnregistered( SharingDeviceRegistrationResult result) { + LogSharingUnegistrationResult(result); if (IsSyncEnabled() && base::FeatureList::IsEnabled(kSharingDeviceRegistration)) { // In case sync is enabled during un-registration, register it. @@ -312,9 +332,22 @@ state_ = State::DISABLED; } - // Unregistration failure is ignored, and will be attempted in next restart. - if (result != SharingDeviceRegistrationResult::kSuccess) - LOG(ERROR) << "Device unregistration failed"; + switch (result) { + case SharingDeviceRegistrationResult::kSuccess: + // Successfully unregistered, no-op + break; + case SharingDeviceRegistrationResult::kFcmTransientError: + case SharingDeviceRegistrationResult::kSyncServiceError: + LOG(ERROR) << "Device un-registration failed with transient error"; + break; + case SharingDeviceRegistrationResult::kEncryptionError: + case SharingDeviceRegistrationResult::kFcmFatalError: + LOG(ERROR) << "Device un-registration failed with fatal error"; + break; + case SharingDeviceRegistrationResult::kDeviceNotRegistered: + // Device has not been registered, no-op. + break; + } } bool SharingService::IsSyncEnabled() const { @@ -323,3 +356,12 @@ syncer::SyncService::TransportState::ACTIVE && sync_service_->GetActiveDataTypes().Has(syncer::PREFERENCES); } + +bool SharingService::IsSyncDisabled() const { + return sync_service_ && + (sync_service_->GetTransportState() == + syncer::SyncService::TransportState::DISABLED || + (sync_service_->GetTransportState() == + syncer::SyncService::TransportState::ACTIVE && + !sync_service_->GetActiveDataTypes().Has(syncer::PREFERENCES))); +}
diff --git a/chrome/browser/sharing/sharing_service.h b/chrome/browser/sharing/sharing_service.h index 5cc47ab7..fa0811be 100644 --- a/chrome/browser/sharing/sharing_service.h +++ b/chrome/browser/sharing/sharing_service.h
@@ -26,6 +26,10 @@ #include "chrome/browser/sharing/click_to_call/click_to_call_message_handler_android.h" #endif // defined(OS_ANDROID) +namespace gcm { +class GCMDriver; +} // namespace gcm + namespace syncer { class DeviceInfoTracker; class LocalDeviceInfoProvider; @@ -65,6 +69,7 @@ std::unique_ptr<SharingDeviceRegistration> sharing_device_registration, std::unique_ptr<SharingFCMSender> fcm_sender, std::unique_ptr<SharingFCMHandler> fcm_handler, + gcm::GCMDriver* gcm_driver, syncer::DeviceInfoTracker* device_info_tracker, syncer::LocalDeviceInfoProvider* local_device_info_provider, syncer::SyncService* sync_service); @@ -110,9 +115,13 @@ base::Optional<std::string> message_id); void InvokeSendMessageCallback(const std::string& message_guid, bool result); - // Returns true if sync is active and sync preference is enabled. + // Returns true if required sync feature is enabled. bool IsSyncEnabled() const; + // Returns true if required sync feature is disabled. Returns false if sync is + // in transitioning state. + bool IsSyncDisabled() const; + std::unique_ptr<SharingSyncPreference> sync_prefs_; std::unique_ptr<VapidKeyManager> vapid_key_manager_; std::unique_ptr<SharingDeviceRegistration> sharing_device_registration_;
diff --git a/chrome/browser/sharing/sharing_service_factory.cc b/chrome/browser/sharing/sharing_service_factory.cc index d3b9e0e..b8b551e 100644 --- a/chrome/browser/sharing/sharing_service_factory.cc +++ b/chrome/browser/sharing/sharing_service_factory.cc
@@ -83,7 +83,7 @@ std::unique_ptr<SharingDeviceRegistration> sharing_device_registration = std::make_unique<SharingDeviceRegistration>( sync_prefs.get(), instance_id_service->driver(), - vapid_key_manager.get(), gcm_driver, local_device_info_provider); + vapid_key_manager.get(), local_device_info_provider); std::unique_ptr<SharingFCMSender> fcm_sender = std::make_unique<SharingFCMSender>(gcm_driver, local_device_info_provider, sync_prefs.get(), @@ -94,8 +94,8 @@ return new SharingService(std::move(sync_prefs), std::move(vapid_key_manager), std::move(sharing_device_registration), std::move(fcm_sender), std::move(fcm_handler), - device_info_tracker, local_device_info_provider, - sync_service); + gcm_driver, device_info_tracker, + local_device_info_provider, sync_service); } content::BrowserContext* SharingServiceFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/sharing/sharing_service_unittest.cc b/chrome/browser/sharing/sharing_service_unittest.cc index 20b83ec6..a66fe70 100644 --- a/chrome/browser/sharing/sharing_service_unittest.cc +++ b/chrome/browser/sharing/sharing_service_unittest.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/sharing/sharing_fcm_sender.h" #include "chrome/browser/sharing/sharing_sync_preference.h" #include "chrome/browser/sharing/vapid_key_manager.h" +#include "components/gcm_driver/crypto/gcm_encryption_provider.h" #include "components/gcm_driver/fake_gcm_driver.h" #include "components/gcm_driver/instance_id/instance_id_driver.h" #include "components/sync/driver/test_sync_service.h" @@ -46,6 +47,7 @@ const char kFcmToken[] = "fcm_token"; const char kDeviceName[] = "other_name"; const char kMessageId[] = "message_id"; +const char kAuthorizedEntity[] = "authorized_entity"; constexpr base::TimeDelta kTtl = base::TimeDelta::FromSeconds(10); class FakeGCMDriver : public gcm::FakeGCMDriver { @@ -69,6 +71,10 @@ std::move(callback).Run(base::make_optional(kMessageId)); } + gcm::GCMEncryptionProvider* GetEncryptionProviderInternal() override { + return nullptr; + } + void set_should_respond(bool should_respond) { should_respond_ = should_respond; } @@ -127,12 +133,10 @@ SharingSyncPreference* prefs, instance_id::InstanceIDDriver* instance_id_driver, VapidKeyManager* vapid_key_manager, - gcm::GCMDriver* gcm_driver, syncer::LocalDeviceInfoProvider* device_info_tracker) : SharingDeviceRegistration(prefs, instance_id_driver, vapid_key_manager, - gcm_driver, device_info_tracker) {} ~FakeSharingDeviceRegistration() override = default; @@ -166,7 +170,7 @@ sync_prefs_ = new SharingSyncPreference(&prefs_); sharing_device_registration_ = new FakeSharingDeviceRegistration( sync_prefs_, &mock_instance_id_driver_, vapid_key_manager_, - &fake_gcm_driver_, &fake_local_device_info_provider_); + &fake_local_device_info_provider_); vapid_key_manager_ = new VapidKeyManager(sync_prefs_); fcm_sender_ = new SharingFCMSender(&fake_gcm_driver_, &fake_local_device_info_provider_, @@ -204,8 +208,8 @@ base::WrapUnique(sync_prefs_), base::WrapUnique(vapid_key_manager_), base::WrapUnique(sharing_device_registration_), base::WrapUnique(fcm_sender_), base::WrapUnique(fcm_handler_), - &device_info_tracker_, &fake_local_device_info_provider_, - &test_sync_service_); + &fake_gcm_driver_, &device_info_tracker_, + &fake_local_device_info_provider_, &test_sync_service_); } return sharing_service_.get(); } @@ -344,6 +348,7 @@ CreateFakeDeviceInfo(id, kDeviceName); device_info_tracker_.Add(device_info.get()); sync_prefs_->SetSyncDevice(id, CreateFakeSyncDevice()); + sync_prefs_->SetFCMRegistration({kAuthorizedEntity, "", base::Time::Now()}); GetSharingService()->SendMessageToDevice( id, kTtl, chrome_browser_sharing::SharingMessage(), @@ -373,6 +378,7 @@ CreateFakeDeviceInfo(id, kDeviceName); device_info_tracker_.Add(device_info.get()); sync_prefs_->SetSyncDevice(id, CreateFakeSyncDevice()); + sync_prefs_->SetFCMRegistration({kAuthorizedEntity, "", base::Time::Now()}); // FCM driver will not respond to the send request. fake_gcm_driver_.set_should_respond(false); @@ -411,6 +417,7 @@ CreateFakeDeviceInfo(id, kDeviceName); device_info_tracker_.Add(device_info.get()); sync_prefs_->SetSyncDevice(id, CreateFakeSyncDevice()); + sync_prefs_->SetFCMRegistration({kAuthorizedEntity, "", base::Time::Now()}); GetSharingService()->SendMessageToDevice( id, kTtl, chrome_browser_sharing::SharingMessage(), @@ -547,12 +554,22 @@ EXPECT_CALL(*fcm_handler_, StartListening()).Times(1); test_sync_service_.FireStateChanged(); EXPECT_EQ(1, sharing_device_registration_->registration_attempts()); + EXPECT_EQ(0, sharing_device_registration_->unregistration_attempts()); EXPECT_EQ(SharingService::State::ACTIVE, GetSharingService()->GetState()); // Further state changes do nothing. EXPECT_CALL(*fcm_handler_, StartListening()).Times(0); test_sync_service_.FireStateChanged(); EXPECT_EQ(1, sharing_device_registration_->registration_attempts()); + EXPECT_EQ(0, sharing_device_registration_->unregistration_attempts()); + EXPECT_EQ(SharingService::State::ACTIVE, GetSharingService()->GetState()); + + // Change sync to configuring, which will be ignored. + test_sync_service_.SetTransportState( + syncer::SyncService::TransportState::CONFIGURING); + test_sync_service_.FireStateChanged(); + EXPECT_EQ(1, sharing_device_registration_->registration_attempts()); + EXPECT_EQ(0, sharing_device_registration_->unregistration_attempts()); EXPECT_EQ(SharingService::State::ACTIVE, GetSharingService()->GetState()); // Disable sync and un-registration should happen. @@ -560,12 +577,14 @@ syncer::SyncService::TransportState::DISABLED); EXPECT_CALL(*fcm_handler_, StopListening()).Times(1); test_sync_service_.FireStateChanged(); + EXPECT_EQ(1, sharing_device_registration_->registration_attempts()); EXPECT_EQ(1, sharing_device_registration_->unregistration_attempts()); EXPECT_EQ(SharingService::State::DISABLED, GetSharingService()->GetState()); // Further state changes do nothing. EXPECT_CALL(*fcm_handler_, StopListening()).Times(0); test_sync_service_.FireStateChanged(); + EXPECT_EQ(1, sharing_device_registration_->registration_attempts()); EXPECT_EQ(1, sharing_device_registration_->unregistration_attempts()); EXPECT_EQ(SharingService::State::DISABLED, GetSharingService()->GetState()); @@ -575,7 +594,16 @@ EXPECT_CALL(*fcm_handler_, StartListening()).Times(1); test_sync_service_.FireStateChanged(); EXPECT_EQ(2, sharing_device_registration_->registration_attempts()); + EXPECT_EQ(1, sharing_device_registration_->unregistration_attempts()); EXPECT_EQ(SharingService::State::ACTIVE, GetSharingService()->GetState()); + + // Disable syncing of preference and un-registration should happen. + test_sync_service_.SetActiveDataTypes(syncer::ModelTypeSet()); + EXPECT_CALL(*fcm_handler_, StopListening()).Times(1); + test_sync_service_.FireStateChanged(); + EXPECT_EQ(2, sharing_device_registration_->registration_attempts()); + EXPECT_EQ(2, sharing_device_registration_->unregistration_attempts()); + EXPECT_EQ(SharingService::State::DISABLED, GetSharingService()->GetState()); } TEST_F(SharingServiceTest, StartListeningToFCMAtConstructor) { @@ -586,8 +614,7 @@ // Create new SharingService instance with FCM already registered at // constructor. - sync_prefs_->SetFCMRegistration( - {"authorized_entity", "fcm_registration_token", base::Time::Now()}); + sync_prefs_->SetFCMRegistration({kAuthorizedEntity, "", base::Time::Now()}); EXPECT_CALL(*fcm_handler_, StartListening()).Times(1); GetSharingService(); }
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc index 60b10bd..707f2a9a 100644 --- a/chrome/browser/shell_integration_linux.cc +++ b/chrome/browser/shell_integration_linux.cc
@@ -252,7 +252,7 @@ #if BUILDFLAG(ENABLE_APP_LIST) #if defined(GOOGLE_CHROME_BUILD) const char kAppListDesktopName[] = "chrome-app-list"; -#else // CHROMIUM_BUILD +#else // BUILDFLAG(CHROMIUM_BRANDING) const char kAppListDesktopName[] = "chromium-app-list"; #endif #endif @@ -426,7 +426,7 @@ default: return "google-chrome.desktop"; } -#else // CHROMIUM_BUILD +#else // BUILDFLAG(CHROMIUM_BRANDING) // Allow $CHROME_DESKTOP to override the built-in value, so that development // versions can set themselves as the default without interfering with // non-official, packaged versions using the built-in value. @@ -440,7 +440,7 @@ std::string GetIconName() { #if defined(GOOGLE_CHROME_BUILD) return "google-chrome"; -#else // CHROMIUM_BUILD +#else // BUILDFLAG(CHROMIUM_BRANDING) return "chromium-browser"; #endif }
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc index 24833967..46bf598 100644 --- a/chrome/browser/shell_integration_win.cc +++ b/chrome/browser/shell_integration_win.cc
@@ -493,6 +493,16 @@ delete this; } +void MigrateChromeAndChromeProxyShortcuts( + const base::FilePath& chrome_exe, + const base::FilePath& chrome_proxy_path, + const base::FilePath& shortcut_path) { + win::MigrateShortcutsInPathInternal(chrome_exe, shortcut_path); + + // Migrate any pinned PWA shortcuts in taskbar directory. + win::MigrateShortcutsInPathInternal(chrome_proxy_path, shortcut_path); +} + } // namespace bool SetAsDefaultBrowser() { @@ -701,28 +711,44 @@ // This needs to happen (e.g. so that the appid is fixed and the // run-time Chrome icon is merged with the taskbar shortcut), but it is not an // urgent task. - base::FilePath pins_path; - if (!base::PathService::Get(base::DIR_TASKBAR_PINS, &pins_path)) { + base::FilePath taskbar_path; + if (!base::PathService::Get(base::DIR_TASKBAR_PINS, &taskbar_path)) { + NOTREACHED(); + return; + } + + // Migrate any pinned shortcuts in ImplicitApps sub-directories. + base::FilePath implicit_apps_path; + if (!base::PathService::Get(base::DIR_IMPLICIT_APP_SHORTCUTS, + &implicit_apps_path)) { NOTREACHED(); return; } base::CreateCOMSTATaskRunnerWithTraits( {base::MayBlock(), base::TaskPriority::BEST_EFFORT}) - ->PostTask(FROM_HERE, - base::BindOnce(&MigrateTaskbarPinsCallback, pins_path)); + ->PostTask(FROM_HERE, base::BindOnce(&MigrateTaskbarPinsCallback, + taskbar_path, implicit_apps_path)); } -void MigrateTaskbarPinsCallback(const base::FilePath& pins_path) { +void MigrateTaskbarPinsCallback(const base::FilePath& taskbar_path, + const base::FilePath& implicit_apps_path) { // Get full path of chrome. base::FilePath chrome_exe; if (!base::PathService::Get(base::FILE_EXE, &chrome_exe)) return; + base::FilePath chrome_proxy_path(web_app::GetChromeProxyPath()); - win::MigrateShortcutsInPathInternal(chrome_exe, pins_path); - - // Migrate any pinned PWA shortcuts. - win::MigrateShortcutsInPathInternal(web_app::GetChromeProxyPath(), pins_path); + MigrateChromeAndChromeProxyShortcuts(chrome_exe, chrome_proxy_path, + taskbar_path); + base::FileEnumerator directory_enum(implicit_apps_path, /*recursive=*/false, + base::FileEnumerator::DIRECTORIES); + for (base::FilePath implicit_app_sub_directory = directory_enum.Next(); + !implicit_app_sub_directory.empty(); + implicit_app_sub_directory = directory_enum.Next()) { + MigrateChromeAndChromeProxyShortcuts(chrome_exe, chrome_proxy_path, + implicit_app_sub_directory); + } } void GetIsPinnedToTaskbarState(
diff --git a/chrome/browser/shell_integration_win.h b/chrome/browser/shell_integration_win.h index 3eb29a0..cc6d224 100644 --- a/chrome/browser/shell_integration_win.h +++ b/chrome/browser/shell_integration_win.h
@@ -74,7 +74,8 @@ void MigrateTaskbarPins(); // Callback for MigrateTaskbarPins(). Exposed for testing. -void MigrateTaskbarPinsCallback(const base::FilePath& pins_path); +void MigrateTaskbarPinsCallback(const base::FilePath& pins_path, + const base::FilePath& implicit_apps_path); // Migrates all shortcuts in |path| which point to |chrome_exe| such that they // have the appropriate AppUserModelId. Also clears the legacy dual_mode
diff --git a/chrome/browser/shell_integration_win_unittest.cc b/chrome/browser/shell_integration_win_unittest.cc index df47071..9409383 100644 --- a/chrome/browser/shell_integration_win_unittest.cc +++ b/chrome/browser/shell_integration_win_unittest.cc
@@ -43,7 +43,8 @@ void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - + ASSERT_TRUE( + temp_dir_sub_dir_.CreateUniqueTempDirUnderPath(temp_dir_.GetPath())); // A path to a random target. base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &other_target_); @@ -83,9 +84,10 @@ // |shortcut_properties| after copying it to an internal structure for later // verification. void AddTestShortcutAndResetProperties( + const base::FilePath& shortcut_dir, base::win::ShortcutProperties* shortcut_properties) { ShortcutTestObject shortcut_test_object; - base::FilePath shortcut_path = temp_dir_.GetPath().Append( + base::FilePath shortcut_path = shortcut_dir.Append( L"Shortcut " + base::NumberToString16(shortcuts_.size()) + installer::kLnkExt); shortcut_test_object.path = shortcut_path; @@ -105,22 +107,22 @@ // Shortcut 0 doesn't point to chrome.exe and thus should never be migrated. temp_properties.set_target(other_target_); temp_properties.set_app_id(L"Dumbo"); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 1 points to chrome.exe and thus should be migrated. temp_properties.set_target(chrome_exe_); temp_properties.set_app_id(L"Dumbo"); temp_properties.set_dual_mode(false); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 2 points to chrome.exe, but already has the right appid and thus // should only be migrated if dual_mode is desired. temp_properties.set_target(chrome_exe_); temp_properties.set_app_id(default_profile_chrome_app_id_); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 3 is like shortcut 1, but it's appid is a prefix of the expected // appid instead of being totally different. @@ -128,8 +130,8 @@ chrome_app_id_is_prefix.push_back(L'1'); temp_properties.set_target(chrome_exe_); temp_properties.set_app_id(chrome_app_id_is_prefix); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 4 is like shortcut 1, but it's appid is of the same size as the // expected appid. @@ -137,14 +139,14 @@ default_profile_chrome_app_id_.size(), L'1'); temp_properties.set_target(chrome_exe_); temp_properties.set_app_id(same_size_as_chrome_app_id); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 5 doesn't have an app_id, nor is dual_mode even set; they should // be set as expected upon migration. temp_properties.set_target(chrome_exe_); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 6 has a non-default profile directory and so should get a non- // default app id. @@ -152,8 +154,8 @@ temp_properties.set_app_id(L"Dumbo"); temp_properties.set_arguments( L"--profile-directory=" + non_default_profile_); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 7 has a non-default user data directory and so should get a non- // default app id. @@ -161,8 +163,8 @@ temp_properties.set_app_id(L"Dumbo"); temp_properties.set_arguments( L"--user-data-dir=\"" + non_default_user_data_dir_.value() + L"\""); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 8 has a non-default user data directory as well as a non-default // profile directory and so should get a non-default app id. @@ -171,8 +173,8 @@ temp_properties.set_arguments( L"--user-data-dir=\"" + non_default_user_data_dir_.value() + L"\" " + L"--profile-directory=" + non_default_profile_); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 9 is a shortcut to an app and should get an app id for that app // rather than the chrome app id. @@ -180,8 +182,8 @@ temp_properties.set_app_id(L"Dumbo"); temp_properties.set_arguments( L"--app-id=" + extension_id_); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 10 is a shortcut to an app with a non-default profile and should // get an app id for that app with a non-default app id rather than the @@ -191,8 +193,8 @@ temp_properties.set_arguments( L"--app-id=" + extension_id_ + L" --profile-directory=" + non_default_profile_); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 11 points to chrome.exe, has the chrome appid, and has // dual_mode set and thus should be migrated to the @@ -200,21 +202,24 @@ temp_properties.set_target(chrome_exe_); temp_properties.set_app_id(chrome_app_id_); temp_properties.set_dual_mode(true); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); // Shortcut 12 is similar to 11 but with dual_mode explicitly set to false. temp_properties.set_target(chrome_exe_); temp_properties.set_app_id(chrome_app_id_); temp_properties.set_dual_mode(false); - ASSERT_NO_FATAL_FAILURE( - AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_.GetPath(), &temp_properties)); } base::win::ScopedCOMInitializer com_initializer_; base::ScopedTempDir temp_dir_; + // Used to test migration of shortcuts in ImplicitApps sub-directories. + base::ScopedTempDir temp_dir_sub_dir_; + // Test shortcuts. std::vector<ShortcutTestObject> shortcuts_; @@ -300,8 +305,9 @@ MigrateShortcutsInPathInternal(chrome_exe_, temp_dir_.GetPath())); } -// Test that a chrome_proxy.exe shortcut (PWA) has its app_id migrated -// to include the default profile name. +// Test that chrome_proxy.exe shortcuts (PWA) have their app_id migrated +// to include the default profile name. This tests both shortcuts in the +// DIR_TASKBAR_PINS and sub-directories of DIR_IMPLICIT_APP_SHORTCUTS. TEST_F(ShellIntegrationWinMigrateShortcutTest, MigrateChromeProxyTest) { // Create shortcut to chrome_proxy_exe in executable directory, // using the default profile, with the AppModelId not containing the @@ -310,12 +316,22 @@ base::win::ShortcutProperties temp_properties; temp_properties.set_target(web_app::GetChromeProxyPath()); temp_properties.set_app_id(L"Dumbo"); - ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties(&temp_properties)); + ASSERT_NO_FATAL_FAILURE( + AddTestShortcutAndResetProperties(temp_dir_.GetPath(), &temp_properties)); + temp_properties.set_target(web_app::GetChromeProxyPath()); + temp_properties.set_app_id(L"Dumbo2"); + ASSERT_NO_FATAL_FAILURE(AddTestShortcutAndResetProperties( + temp_dir_sub_dir_.GetPath(), &temp_properties)); - MigrateTaskbarPinsCallback(temp_dir_.GetPath()); - // Verify that the migrated shortcut now contains the default profile name. + MigrateTaskbarPinsCallback(temp_dir_.GetPath(), temp_dir_.GetPath()); + // Verify that the migrated shortcut in temp_dir_ now contains the default + // profile name. shortcuts_[0].properties.set_app_id(default_profile_chrome_app_id_); base::win::ValidateShortcut(shortcuts_[0].path, shortcuts_[0].properties); + // Verify that the migrated shortcut in temp_dir_sub now contains the default + // profile name. + shortcuts_[1].properties.set_app_id(default_profile_chrome_app_id_); + base::win::ValidateShortcut(shortcuts_[1].path, shortcuts_[1].properties); } TEST(ShellIntegrationWinTest, GetAppModelIdForProfileTest) {
diff --git a/chrome/browser/signin/chrome_signin_helper.cc b/chrome/browser/signin/chrome_signin_helper.cc index e4e082b..515b7a3 100644 --- a/chrome/browser/signin/chrome_signin_helper.cc +++ b/chrome/browser/signin/chrome_signin_helper.cc
@@ -389,13 +389,11 @@ kManageAccountsHeaderReceivedUserDataKey, std::make_unique<ManageAccountsHeaderReceivedUserData>()); - if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { - ProcessMirrorHeaderUIThread(params, response->GetWebContentsGetter()); - } else { - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(ProcessMirrorHeaderUIThread, params, - response->GetWebContentsGetter())); - } + // Post a task even if we are already on the UI thread to avoid making any + // requests while processing a throttle event. + base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(ProcessMirrorHeaderUIThread, params, + response->GetWebContentsGetter())); } #if BUILDFLAG(ENABLE_DICE_SUPPORT) @@ -428,15 +426,12 @@ if (params.user_intention == DiceAction::NONE) return; - if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { - ProcessDiceHeaderUIThread(std::move(params), - response->GetWebContentsGetter()); - } else { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(ProcessDiceHeaderUIThread, std::move(params), - response->GetWebContentsGetter())); - } + // Post a task even if we are already on the UI thread to avoid making any + // requests while processing a throttle event. + base::PostTaskWithTraits( + FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(ProcessDiceHeaderUIThread, std::move(params), + response->GetWebContentsGetter())); } #endif // BUILDFLAG(ENABLE_DICE_SUPPORT)
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc index a8a8cbb..c0baaa7 100644 --- a/chrome/browser/ssl/ssl_browsertest.cc +++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -2761,14 +2761,12 @@ // broken in the good case. std::string replacement_path = GetFilePathWithHostAndPortReplacement( "/ssl/page_with_unsafe_contents.html", https_server_.host_port_pair()); - ui_test_utils::BrowserAddedObserver popup_observer; ui_test_utils::NavigateToURL(browser(), https_server_.GetURL(replacement_path)); WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents(); // The state is expected to be authenticated. CheckAuthenticatedState(tab, AuthState::NONE); // The iframe should be able to open a popup. - popup_observer.WaitForSingleNewBrowser(); EXPECT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); // In order to check that the image was loaded, check its width. // The actual image (Google logo) is 276 pixels wide. @@ -3059,15 +3057,12 @@ "/ssl/page_with_unsafe_popup.html", https_server_expired_.host_port_pair()); WebContents* tab1 = browser()->tab_strip_model()->GetActiveWebContents(); - ui_test_utils::BrowserAddedObserver popup_observer; content::TestNavigationObserver nav_observer( https_server_expired_.GetURL("/ssl/bad_iframe.html")); nav_observer.StartWatchingNewWebContents(); ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL(replacement_path)); - // Wait for popup window to appear and finish navigating. - popup_observer.WaitForSingleNewBrowser(); ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); // Last activated browser should be the popup.
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc index 961cecf..1bb4c3e 100644 --- a/chrome/browser/sync/chrome_sync_client.cc +++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -612,7 +612,11 @@ } syncer::SyncTypePreferenceProvider* ChromeSyncClient::GetPreferenceProvider() { +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) return SupervisedUserServiceFactory::GetForProfile(profile_); +#else + return nullptr; +#endif } } // namespace browser_sync
diff --git a/chrome/browser/sync/test/integration/apps_helper.cc b/chrome/browser/sync/test/integration/apps_helper.cc index ab95d85b..cbe212e6 100644 --- a/chrome/browser/sync/test/integration/apps_helper.cc +++ b/chrome/browser/sync/test/integration/apps_helper.cc
@@ -7,7 +7,8 @@ #include "base/logging.h" #include "base/macros.h" #include "base/strings/string_number_conversions.h" -#include "chrome/browser/apps/app_service/app_service_proxy_impl.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sync/test/integration/sync_app_helper.h" @@ -118,7 +119,7 @@ if (!base::FeatureList::IsEnabled(features::kAppServiceAsh)) return; - apps::AppServiceProxyImpl::GetImplForTesting(profile) + apps::AppServiceProxyFactory::GetForProfile(profile) ->FlushMojoCallsForTesting(); }
diff --git a/chrome/browser/tracing/chrome_tracing_delegate.cc b/chrome/browser/tracing/chrome_tracing_delegate.cc index a0b3724..60d81ff 100644 --- a/chrome/browser/tracing/chrome_tracing_delegate.cc +++ b/chrome/browser/tracing/chrome_tracing_delegate.cc
@@ -10,6 +10,7 @@ #include "base/bind.h" #include "base/command_line.h" +#include "base/metrics/histogram_macros.h" #include "base/strings/string_piece.h" #include "base/time/time.h" #include "base/values.h" @@ -43,6 +44,25 @@ const int kMinDaysUntilNextUpload = 7; +// These values are logged to UMA. Entries should not be renumbered and numeric +// values should never be reused. Please keep in sync with +// "TracingFinalizationDisallowedReason" in +// src/tools/metrics/histograms/enums.xml. +enum class TracingFinalizationDisallowedReason { + kIncognitoLaunched = 0, + kProfileNotLoaded = 1, + kCrashMetricsNotLoaded = 2, + kLastSessionCrashed = 3, + kMetricsReportingDisabled = 4, + kTraceUploadedRecently = 5, + kMaxValue = kTraceUploadedRecently +}; + +void RecordDisallowedMetric(TracingFinalizationDisallowedReason reason) { + UMA_HISTOGRAM_ENUMERATION("Tracing.Background.FinalizationDisallowedReason", + reason); +} + } // namespace void ChromeTracingDelegate::RegisterPrefs(PrefRegistrySimple* registry) { @@ -118,30 +138,49 @@ // If the profile hasn't loaded or been created yet, we allow the scenario // to start up, but not be finalized. Profile* profile = GetProfile(); - if (!profile) + if (!profile) { + if (profile_permission == PROFILE_REQUIRED) { + RecordDisallowedMetric( + TracingFinalizationDisallowedReason::kProfileNotLoaded); + } return profile_permission != PROFILE_REQUIRED; + } // Safeguard, in case background tracing is responsible for a crash on // startup. #if !defined(OS_ANDROID) - if (profile->GetLastSessionExitType() == Profile::EXIT_CRASHED) + if (profile->GetLastSessionExitType() == Profile::EXIT_CRASHED) { + RecordDisallowedMetric( + TracingFinalizationDisallowedReason::kLastSessionCrashed); return false; + } #else // If the metrics haven't loaded, we allow the scenario to start up, but not // be finalized. - if (!CrashUploadListAndroid::BrowserCrashMetricsInitialized()) + if (!CrashUploadListAndroid::BrowserCrashMetricsInitialized()) { + if (profile_permission == PROFILE_REQUIRED) { + RecordDisallowedMetric( + TracingFinalizationDisallowedReason::kCrashMetricsNotLoaded); + } return profile_permission != PROFILE_REQUIRED; + } - if (CrashUploadListAndroid::DidBrowserCrashRecently()) + if (CrashUploadListAndroid::DidBrowserCrashRecently()) { + RecordDisallowedMetric( + TracingFinalizationDisallowedReason::kLastSessionCrashed); return false; + } #endif PrefService* local_state = g_browser_process->local_state(); DCHECK(local_state); #if !defined(OS_CHROMEOS) && defined(OFFICIAL_BUILD) - if (!local_state->GetBoolean(metrics::prefs::kMetricsReportingEnabled)) + if (!local_state->GetBoolean(metrics::prefs::kMetricsReportingEnabled)) { + RecordDisallowedMetric( + TracingFinalizationDisallowedReason::kMetricsReportingDisabled); return false; + } #endif // !OS_CHROMEOS && OFFICIAL_BUILD if (config.tracing_mode() == content::BackgroundTracingConfig::PREEMPTIVE) { @@ -151,6 +190,8 @@ base::Time computed_next_allowed_time = last_upload_time + base::TimeDelta::FromDays(kMinDaysUntilNextUpload); if (computed_next_allowed_time > base::Time::Now()) { + RecordDisallowedMetric( + TracingFinalizationDisallowedReason::kTraceUploadedRecently); return false; } } @@ -178,6 +219,8 @@ bool requires_anonymized_data) { if (requires_anonymized_data && (incognito_launched_ || chrome::IsIncognitoSessionActive())) { + RecordDisallowedMetric( + TracingFinalizationDisallowedReason::kIncognitoLaunched); return false; }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index f13b00b..986350d 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -305,10 +305,6 @@ "webui/quota_internals/quota_internals_ui.h", "webui/signin_internals_ui.cc", "webui/signin_internals_ui.h", - "webui/supervised_user_internals_message_handler.cc", - "webui/supervised_user_internals_message_handler.h", - "webui/supervised_user_internals_ui.cc", - "webui/supervised_user_internals_ui.h", "webui/sync_internals_message_handler.cc", "webui/sync_internals_message_handler.h", "webui/sync_internals_ui.cc", @@ -1347,7 +1343,6 @@ "//chrome/browser/ui/webui/app_management:mojo_bindings", "//chrome/common:buildflags", "//chrome/common:search_mojom", - "//chrome/services/app_service/public/cpp:app_service_proxy", "//chrome/services/app_service/public/cpp:app_update", "//chrome/services/app_service/public/mojom", "//components/feedback/proto", @@ -1393,6 +1388,7 @@ } } + # TODO(crbug.com/980869): Remove the section below. if (enable_supervised_users && !is_android && !is_chromeos) { sources += [ "startup/supervised_users_deprecated_infobar_delegate.cc", @@ -1400,6 +1396,15 @@ ] } + if (enable_supervised_users) { + sources += [ + "webui/supervised_user_internals_message_handler.cc", + "webui/supervised_user_internals_message_handler.h", + "webui/supervised_user_internals_ui.cc", + "webui/supervised_user_internals_ui.h", + ] + } + if (is_chromeos) { assert(enable_extensions) assert(toolkit_views) @@ -2046,22 +2051,22 @@ "webui/signin/user_manager_screen_handler.h", "webui/signin/user_manager_ui.cc", "webui/signin/user_manager_ui.h", - "webui/welcome/nux/bookmark_handler.cc", - "webui/welcome/nux/bookmark_handler.h", - "webui/welcome/nux/bookmark_item.cc", - "webui/welcome/nux/bookmark_item.h", - "webui/welcome/nux/constants.cc", - "webui/welcome/nux/constants.h", - "webui/welcome/nux/google_apps_handler.cc", - "webui/welcome/nux/google_apps_handler.h", - "webui/welcome/nux/ntp_background_fetcher.cc", - "webui/welcome/nux/ntp_background_fetcher.h", - "webui/welcome/nux/ntp_background_handler.cc", - "webui/welcome/nux/ntp_background_handler.h", - "webui/welcome/nux/set_as_default_handler.cc", - "webui/welcome/nux/set_as_default_handler.h", + "webui/welcome/bookmark_handler.cc", + "webui/welcome/bookmark_handler.h", + "webui/welcome/bookmark_item.cc", + "webui/welcome/bookmark_item.h", + "webui/welcome/constants.cc", + "webui/welcome/constants.h", + "webui/welcome/google_apps_handler.cc", + "webui/welcome/google_apps_handler.h", + "webui/welcome/ntp_background_fetcher.cc", + "webui/welcome/ntp_background_fetcher.h", + "webui/welcome/ntp_background_handler.cc", + "webui/welcome/ntp_background_handler.h", "webui/welcome/nux_helper.cc", "webui/welcome/nux_helper.h", + "webui/welcome/set_as_default_handler.cc", + "webui/welcome/set_as_default_handler.h", "webui/welcome/welcome_handler.cc", "webui/welcome/welcome_handler.h", "webui/welcome/welcome_ui.cc",
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.cc b/chrome/browser/ui/app_list/app_list_client_impl.cc index f099320..24f5929 100644 --- a/chrome/browser/ui/app_list/app_list_client_impl.cc +++ b/chrome/browser/ui/app_list/app_list_client_impl.cc
@@ -380,6 +380,9 @@ search_controller_ = app_list::CreateSearchController(profile_, current_model_updater_, this); + search_ranking_event_logger_ = + std::make_unique<app_list::SearchRankingEventLogger>( + profile_, search_controller_.get()); } app_list::SearchController* AppListClientImpl::search_controller() { @@ -525,7 +528,7 @@ const base::string16& trimmed_query, const ash::SearchResultIdWithPositionIndices& results, int position_index) { - search_ranking_event_logger_.Log(trimmed_query, results, position_index); + search_ranking_event_logger_->Log(trimmed_query, results, position_index); } ash::ShelfLaunchSource AppListClientImpl::AppListSourceToLaunchSource(
diff --git a/chrome/browser/ui/app_list/app_list_client_impl.h b/chrome/browser/ui/app_list/app_list_client_impl.h index bd2d157..5eddefc 100644 --- a/chrome/browser/ui/app_list/app_list_client_impl.h +++ b/chrome/browser/ui/app_list/app_list_client_impl.h
@@ -191,7 +191,8 @@ bool app_list_target_visibility_ = false; bool app_list_visible_ = false; - app_list::SearchRankingEventLogger search_ranking_event_logger_; + std::unique_ptr<app_list::SearchRankingEventLogger> + search_ranking_event_logger_; base::WeakPtrFactory<AppListClientImpl> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc index bbc0a19f..643588512 100644 --- a/chrome/browser/ui/app_list/app_list_syncable_service.cc +++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -16,6 +16,7 @@ #include "base/stl_util.h" #include "base/values.h" #include "build/build_config.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" @@ -42,7 +43,6 @@ #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/sync/model/sync_change_processor.h" #include "components/sync/model/sync_data.h"
diff --git a/chrome/browser/ui/app_list/app_service_app_item.cc b/chrome/browser/ui/app_list/app_service_app_item.cc index 5332eda..25af145 100644 --- a/chrome/browser/ui/app_list/app_service_app_item.cc +++ b/chrome/browser/ui/app_list/app_service_app_item.cc
@@ -6,13 +6,13 @@ #include "ash/public/cpp/app_list/app_list_config.h" #include "base/bind.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/ui/app_list/app_list_controller_delegate.h" #include "chrome/browser/ui/app_list/arc/arc_app_context_menu.h" #include "chrome/browser/ui/app_list/crostini/crostini_app_context_menu.h" #include "chrome/browser/ui/app_list/extension_app_context_menu.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" // static const char AppServiceAppItem::kItemType[] = "AppServiceAppItem";
diff --git a/chrome/browser/ui/app_list/app_service_app_model_builder.cc b/chrome/browser/ui/app_list/app_service_app_model_builder.cc index 3eb20e5..106cb16 100644 --- a/chrome/browser/ui/app_list/app_service_app_model_builder.cc +++ b/chrome/browser/ui/app_list/app_service_app_model_builder.cc
@@ -4,12 +4,12 @@ #include "chrome/browser/ui/app_list/app_service_app_model_builder.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/ui/app_list/app_service_app_item.h" #include "chrome/grit/generated_resources.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" #include "ui/base/l10n/l10n_util.h" // static
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc index 6801b3a..f128d81a 100644 --- a/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc +++ b/chrome/browser/ui/app_list/crostini/crostini_app_model_builder_unittest.cc
@@ -8,7 +8,7 @@ #include <vector> #include "base/run_loop.h" -#include "chrome/browser/apps/app_service/app_service_proxy_impl.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/chromeos/crostini/crostini_registry_service.h" #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h" #include "chrome/browser/chromeos/crostini/crostini_test_helper.h"
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc index fc6f36a..3c1f11e2 100644 --- a/chrome/browser/ui/app_list/search/app_search_provider.cc +++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -30,6 +30,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/clock.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/crostini/crostini_manager.h" @@ -60,7 +61,6 @@ #include "chrome/common/chrome_features.h" #include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" #include "components/sync/base/model_type.h" #include "components/sync_sessions/session_sync_service.h" #include "extensions/browser/extension_prefs.h"
diff --git a/chrome/browser/ui/app_list/search/app_service_app_result.cc b/chrome/browser/ui/app_list/search/app_service_app_result.cc index 125397eb..9c890ba14 100644 --- a/chrome/browser/ui/app_list/search/app_service_app_result.cc +++ b/chrome/browser/ui/app_list/search/app_service_app_result.cc
@@ -7,11 +7,11 @@ #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/app_list/app_list_types.h" #include "base/bind.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/ui/app_list/app_list_client_impl.h" #include "chrome/browser/ui/app_list/app_service_app_item.h" #include "chrome/browser/ui/app_list/search/internal_app_result.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" #include "extensions/common/extension.h" namespace app_list {
diff --git a/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.cc b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.cc index 1475d34..dfee341 100644 --- a/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.cc +++ b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.cc
@@ -2,33 +2,309 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <string> -#include <utility> -#include <vector> - -#include "base/logging.h" #include "chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h" -namespace app_list { +#include <cmath> -SearchRankingEventLogger::SearchRankingEventLogger() {} +#include "ash/public/cpp/app_list/app_list_types.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/app_list/search/chrome_search_result.h" +#include "chrome/browser/ui/app_list/search/omnibox_result.h" +#include "chromeos/constants/devicetype.h" +#include "components/omnibox/browser/autocomplete_match_type.h" +#include "services/metrics/public/cpp/metrics_utils.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace app_list { +namespace { + +using ukm::GetExponentialBucketMinForCounts1000; + +// How long to wait for a URL to enter the history service before querying it +// for a UKM source ID. +constexpr base::TimeDelta kDelayForHistoryService = + base::TimeDelta::FromSeconds(15); + +// Chosen so that the bucket at the 24 hour mark is ~60 minutes long. The bucket +// exponent used for counts that are not seconds is 1.15 (via +// ukm::GetExponentialBucketMinForCounts1000). The first value skipped by +// bucketing is 10. +constexpr float kBucketExponentForSeconds = 1.045; + +// Represents the type of a search result. The indices of these values +// persist to logs, so existing values should not be modified. +enum class Category { + UNKNOWN = 0, + FILE = 1, + HISTORY = 2, + NAV_SUGGEST = 3, + SEARCH = 4, + BOOKMARK = 5, + DOCUMENT = 6, + OMNIBOX_DEPRECATED = 7, + OMNIBOX_GENERIC = 8 +}; + +int ExtensionTypeFromFileName(const std::string& file_name) { + // This is a limited list of commonly used extensions. The index of an + // extension in this list persists to logs, so existing values should not be + // modified and new values should only be added to the end. This should be + // kept in sync with AppListNonAppImpressionFileExtension in + // histograms/enums.xml + static const base::NoDestructor<std::vector<std::string>> known_extensions( + {".3ga", ".3gp", ".aac", ".alac", ".asf", ".avi", + ".bmp", ".csv", ".doc", ".docx", ".flac", ".gif", + ".jpeg", ".jpg", ".log", ".m3u", ".m3u8", ".m4a", + ".m4v", ".mid", ".mkv", ".mov", ".mp3", ".mp4", + ".mpg", ".odf", ".odp", ".ods", ".odt", ".oga", + ".ogg", ".ogv", ".pdf", ".png", ".ppt", ".pptx", + ".ra", ".ram", ".rar", ".rm", ".rtf", ".wav", + ".webm", ".webp", ".wma", ".wmv", ".xls", ".xlsx", + ".crdownload", ".crx", ".dmg", ".exe", ".html", ".htm", + ".jar", ".ps", ".torrent", ".txt", ".zip", ".mhtml", + ".gdoc", ".gsheet", ".gslides"}); + + size_t found = file_name.find_last_of("."); + if (found == std::string::npos) + return -1; + return std::distance( + known_extensions->begin(), + std::find(known_extensions->begin(), known_extensions->end(), + file_name.substr(found))); +} + +Category CategoryFromResultType(ash::SearchResultType type, int subtype) { + if (type == ash::SearchResultType::kLauncher) + return Category::FILE; + + if (type == ash::SearchResultType::kOmnibox) { + switch (static_cast<AutocompleteMatchType::Type>(subtype)) { + case AutocompleteMatchType::Type::HISTORY_URL: + case AutocompleteMatchType::Type::HISTORY_TITLE: + case AutocompleteMatchType::Type::HISTORY_BODY: + case AutocompleteMatchType::Type::HISTORY_KEYWORD: + return Category::HISTORY; + case AutocompleteMatchType::Type::NAVSUGGEST: + case AutocompleteMatchType::Type::NAVSUGGEST_PERSONALIZED: + return Category::NAV_SUGGEST; + case AutocompleteMatchType::Type::SEARCH_HISTORY: + case AutocompleteMatchType::Type::SEARCH_SUGGEST: + case AutocompleteMatchType::Type::SEARCH_SUGGEST_ENTITY: + case AutocompleteMatchType::Type::SEARCH_SUGGEST_TAIL: + case AutocompleteMatchType::Type::SEARCH_SUGGEST_PERSONALIZED: + case AutocompleteMatchType::Type::SEARCH_SUGGEST_PROFILE: + case AutocompleteMatchType::Type::SEARCH_OTHER_ENGINE: + return Category::SEARCH; + case AutocompleteMatchType::Type::BOOKMARK_TITLE: + return Category::BOOKMARK; + case AutocompleteMatchType::Type::DOCUMENT_SUGGESTION: + return Category::DOCUMENT; + case AutocompleteMatchType::Type::EXTENSION_APP_DEPRECATED: + case AutocompleteMatchType::Type::CONTACT_DEPRECATED: + case AutocompleteMatchType::Type::PHYSICAL_WEB_DEPRECATED: + case AutocompleteMatchType::Type::PHYSICAL_WEB_OVERFLOW_DEPRECATED: + case AutocompleteMatchType::Type::TAB_SEARCH_DEPRECATED: + return Category::OMNIBOX_DEPRECATED; + default: + return Category::OMNIBOX_GENERIC; + } + } + + return Category::UNKNOWN; +} + +int GetExponentialBucketMinForSeconds(int64_t sample) { + return ukm::GetExponentialBucketMin(sample, kBucketExponentForSeconds); +} + +} // namespace + +SearchRankingEventLogger::SearchRankingEventLogger( + Profile* profile, + SearchController* search_controller) + : search_controller_(search_controller), + ukm_recorder_(ukm::UkmRecorder::Get()), + ukm_background_recorder_( + ukm::UkmBackgroundRecorderFactory::GetForProfile(profile)), + weak_factory_(this) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(search_controller_); +} + SearchRankingEventLogger::~SearchRankingEventLogger() = default; +SearchRankingEventLogger::ResultState::ResultState() = default; +SearchRankingEventLogger::ResultState::~ResultState() = default; + +SearchRankingEventLogger::ResultInfo::ResultInfo() = default; +SearchRankingEventLogger::ResultInfo::ResultInfo( + const SearchRankingEventLogger::ResultInfo& other) = default; +SearchRankingEventLogger::ResultInfo::~ResultInfo() = default; + +void SearchRankingEventLogger::SetEventRecordedForTesting( + base::OnceClosure closure) { + event_recorded_for_testing_ = std::move(closure); +} + void SearchRankingEventLogger::Log( const base::string16& trimmed_query, const ash::SearchResultIdWithPositionIndices& search_results, - int position_index) { - if (trimmed_query.empty()) { - LogSuggestedZeroStateItems(search_results, position_index); - } else { - // TODO(crbug.com/972817): Add the logics for query-based events. + int launched_index) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + for (const auto& id_index : search_results) { + auto* result = search_controller_->FindSearchResult(id_index.id); + if (!result) + continue; + + ResultInfo result_info; + result_info.index = id_index.position_index; + result_info.title = result->title(); + result_info.type = result->result_type(); + result_info.subtype = result->result_subtype(); + result_info.relevance = result->relevance(); + + // Omnibox results have associated URLs, so are logged keyed on the URL + // after validating that it exists in the history service. Other results + // have no associated URL, so use a blank source ID. + if (result->result_type() == ash::SearchResultType::kOmnibox) { + // The id metadata of an OmnioboxResult is a stripped URL, which does not + // correspond to the URL that will be navigated to. + result_info.target = + static_cast<OmniboxResult*>(result)->DestinationURL().spec(); + + // When an omnibox result is launched, we need to retrieve a source ID + // using the history service. This may be the first time the URL is used + // and so it must be committed to the history service database before we + // retrieve it, which happens once the page has loaded. So we delay our + // check for long enough that most pages will have loaded. + if (launched_index == id_index.position_index) { + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce( + &SearchRankingEventLogger::GetBackgroundSourceIdAndLogEvent, + weak_factory_.GetWeakPtr(), next_event_id_, trimmed_query, + result_info, launched_index), + kDelayForHistoryService); + } else { + GetBackgroundSourceIdAndLogEvent(next_event_id_, trimmed_query, + result_info, launched_index); + } + } else { + result_info.target = result->id(); + LogEvent(next_event_id_, trimmed_query, result_info, launched_index, + base::nullopt); + } } + + ++next_event_id_; } -void SearchRankingEventLogger::LogSuggestedZeroStateItems( - const ash::SearchResultIdWithPositionIndices& search_results, - int position_index) { - // TODO(crbug.com/972817): Add the logics to log the suggested items. +void SearchRankingEventLogger::GetBackgroundSourceIdAndLogEvent( + int event_id, + const base::string16& trimmed_query, + const ResultInfo& result, + int launched_index) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + ukm_background_recorder_->GetBackgroundSourceIdIfAllowed( + url::Origin::Create(GURL(result.target)), + base::BindOnce(&SearchRankingEventLogger::LogEvent, + base::Unretained(this), event_id, trimmed_query, result, + launched_index)); +} + +void SearchRankingEventLogger::LogEvent( + int event_id, + const base::string16& trimmed_query, + const ResultInfo& result, + int launched_index, + base::Optional<ukm::SourceId> source_id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!source_id) + source_id = ukm_recorder_->GetNewSourceID(); + + const base::Time now = base::Time::Now(); + base::Time::Exploded now_exploded; + now.LocalExplode(&now_exploded); + + ukm::builders::AppListNonAppImpression event(source_id.value()); + event.SetEventId(event_id) + .SetPosition(result.index) + .SetIsLaunched(result.index == launched_index) + .SetQueryLength( + GetExponentialBucketMinForCounts1000(trimmed_query.size())) + // Note this is the search provider's original relevance score, not + // tweaked by any search ranking models. Scores are floats in 0 to 1, and + // we map this to ints 0 to 100. + .SetRelevanceScore(static_cast<int>(100 * result.relevance)) + .SetCategory( + static_cast<int>(CategoryFromResultType(result.type, result.subtype))) + .SetHourOfDay(now_exploded.hour) + .SetDayOfWeek(now_exploded.day_of_week); + + if (result.type == ash::SearchResultType::kLauncher) { + event.SetFileExtension(ExtensionTypeFromFileName(result.target)); + } + + auto& event_info = id_to_result_state_[result.target]; + + if (event_info.last_launch != base::nullopt) { + base::Time last_launch = event_info.last_launch.value(); + base::Time::Exploded last_launch_exploded; + last_launch.LocalExplode(&last_launch_exploded); + + event.SetTimeSinceLastLaunch( + GetExponentialBucketMinForSeconds((now - last_launch).InSeconds())); + event.SetTimeOfLastLaunch(last_launch_exploded.hour); + + // Reset the number of launches this hour to 0 if this is the first launch + // today of this event, to account for user sessions spanning multiple days. + if (result.index == launched_index && + now - last_launch >= base::TimeDelta::FromHours(23)) { + event_info.launches_per_hour[now_exploded.hour] = 0; + } + } + + event.SetLaunchesThisSession( + GetExponentialBucketMinForCounts1000(event_info.launches_this_session)); + + const auto& launches = event_info.launches_per_hour; + event.SetLaunchesAtHour00(GetExponentialBucketMinForCounts1000(launches[0])); + event.SetLaunchesAtHour01(GetExponentialBucketMinForCounts1000(launches[1])); + event.SetLaunchesAtHour02(GetExponentialBucketMinForCounts1000(launches[2])); + event.SetLaunchesAtHour03(GetExponentialBucketMinForCounts1000(launches[3])); + event.SetLaunchesAtHour04(GetExponentialBucketMinForCounts1000(launches[4])); + event.SetLaunchesAtHour05(GetExponentialBucketMinForCounts1000(launches[5])); + event.SetLaunchesAtHour06(GetExponentialBucketMinForCounts1000(launches[6])); + event.SetLaunchesAtHour07(GetExponentialBucketMinForCounts1000(launches[7])); + event.SetLaunchesAtHour08(GetExponentialBucketMinForCounts1000(launches[8])); + event.SetLaunchesAtHour09(GetExponentialBucketMinForCounts1000(launches[9])); + event.SetLaunchesAtHour10(GetExponentialBucketMinForCounts1000(launches[10])); + event.SetLaunchesAtHour11(GetExponentialBucketMinForCounts1000(launches[11])); + event.SetLaunchesAtHour12(GetExponentialBucketMinForCounts1000(launches[12])); + event.SetLaunchesAtHour13(GetExponentialBucketMinForCounts1000(launches[13])); + event.SetLaunchesAtHour14(GetExponentialBucketMinForCounts1000(launches[14])); + event.SetLaunchesAtHour15(GetExponentialBucketMinForCounts1000(launches[15])); + event.SetLaunchesAtHour16(GetExponentialBucketMinForCounts1000(launches[16])); + event.SetLaunchesAtHour17(GetExponentialBucketMinForCounts1000(launches[17])); + event.SetLaunchesAtHour18(GetExponentialBucketMinForCounts1000(launches[18])); + event.SetLaunchesAtHour19(GetExponentialBucketMinForCounts1000(launches[19])); + event.SetLaunchesAtHour20(GetExponentialBucketMinForCounts1000(launches[20])); + event.SetLaunchesAtHour21(GetExponentialBucketMinForCounts1000(launches[21])); + event.SetLaunchesAtHour22(GetExponentialBucketMinForCounts1000(launches[22])); + event.SetLaunchesAtHour23(GetExponentialBucketMinForCounts1000(launches[23])); + + event.Record(ukm_recorder_); + + if (result.index == launched_index) { + event_info.last_launch = now; + event_info.launches_this_session += 1; + event_info.launches_per_hour[now_exploded.hour] += 1; + } + + if (event_recorded_for_testing_) + std::move(event_recorded_for_testing_).Run(); } } // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h index c690681b..7a65eb68 100644 --- a/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h +++ b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h
@@ -5,19 +5,30 @@ #ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_LOGGING_SEARCH_RANKING_EVENT_LOGGER_H_ #define CHROME_BROWSER_UI_APP_LIST_SEARCH_LOGGING_SEARCH_RANKING_EVENT_LOGGER_H_ +#include <map> #include <string> #include <utility> #include <vector> #include "ash/public/cpp/app_list/app_list_types.h" #include "base/logging.h" +#include "base/macros.h" +#include "base/sequence_checker.h" #include "base/time/time.h" +#include "chrome/browser/metrics/ukm_background_recorder_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/app_list/search/search_controller.h" +#include "services/metrics/public/cpp/ukm_recorder.h" + +class ChromeSearchResult; namespace app_list { +// Performs UKM logging of search ranking events in the launcher's results list. class SearchRankingEventLogger { public: - SearchRankingEventLogger(); + SearchRankingEventLogger(Profile* profile, + SearchController* search_controller); ~SearchRankingEventLogger(); // Called if a search result item got clicked, or a list of search result has // been shown to the user after a certain amount of time. |raw_query| is the @@ -28,13 +39,80 @@ // clicked, |position_index| will be -1). void Log(const base::string16& trimmed_query, const ash::SearchResultIdWithPositionIndices& search_results, - int position_index); + int launched_index); + + // Sets a testing-only closure to inform tests when a UKM event has been + // recorded. + void SetEventRecordedForTesting(base::OnceClosure closure); private: - // Logs suggested items either from impressions or from click events. - void LogSuggestedZeroStateItems( - const ash::SearchResultIdWithPositionIndices& search_results, - int position_index); + // Stores state necessary for logging a given search result that is + // accumulated throughout the session. + struct ResultState { + ResultState(); + ~ResultState(); + + base::Optional<base::Time> last_launch = base::nullopt; + // Initialises all elements to 0. + int launches_per_hour[24] = {}; + int launches_this_session = 0; + }; + + // Stores the relevant parts of a ChromeSearchResult used for logging. + struct ResultInfo { + public: + ResultInfo(); + ResultInfo(const ResultInfo& other); + ~ResultInfo(); + + int index; + std::string target; + base::string16 title; + ash::SearchResultType type; + int subtype; + float relevance; + }; + + // Calls the UKM API for a source ID relevant to |result|, and then begins the + // logging process by calling LogEvent. + void GetBackgroundSourceIdAndLogEvent(int event_id, + const base::string16& trimmed_query, + const ResultInfo& result_info, + int launched_index); + + // Logs the given event to UKM. If |source_id| is nullopt then use a blank + // source ID. + void LogEvent(int event_id, + const base::string16& trimmed_query, + const ResultInfo& result_info, + int launched_index, + base::Optional<ukm::SourceId> source_id); + + SearchController* search_controller_; + // Some events do not have an associated URL and so are logged directly with + // |ukm_recorder_| using a blank source ID. Other events need to validate the + // URL before recording, and use |ukm_background_recorder_|. + ukm::UkmRecorder* ukm_recorder_; + ukm::UkmBackgroundRecorderService* ukm_background_recorder_; + + // TODO(972817): Zero-state previous query results change their URL based on + // the position they should be displayed at in the launcher. Because their + // ID changes, we lose information on their result state. If, in future, we + // want to rank these results and want more information, we should normalize + // their IDs to remove the position information. + std::map<std::string, ResultState> id_to_result_state_; + + // The next, unused, event ID. + int next_event_id_ = 1; + + // Testing-only closure to inform tests when a UKM event has been recorded. + base::OnceClosure event_recorded_for_testing_; + + SEQUENCE_CHECKER(sequence_checker_); + + base::WeakPtrFactory<SearchRankingEventLogger> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(SearchRankingEventLogger); }; } // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger_unittest.cc b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger_unittest.cc new file mode 100644 index 0000000..ecacc78 --- /dev/null +++ b/chrome/browser/ui/app_list/search/logging/search_ranking_event_logger_unittest.cc
@@ -0,0 +1,355 @@ +// 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. + +#include "chrome/browser/ui/app_list/search/logging/search_ranking_event_logger.h" + +#include <map> +#include <memory> +#include <utility> + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/run_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_mock_clock_override.h" +#include "base/test/scoped_task_environment.h" +#include "base/time/time.h" +#include "chrome/browser/history/history_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/app_list/search/chrome_search_result.h" +#include "chrome/browser/ui/app_list/search/search_controller.h" +#include "chrome/test/base/testing_profile.h" +#include "components/history/core/browser/history_database_params.h" +#include "components/history/core/browser/history_service.h" +#include "components/history/core/browser/history_types.h" +#include "components/history/core/test/history_service_test_util.h" +#include "components/history/core/test/test_history_database.h" +#include "components/ukm/test_ukm_recorder.h" +#include "components/ukm/ukm_recorder_impl.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "services/metrics/public/cpp/ukm_builders.h" +#include "services/metrics/public/cpp/ukm_recorder.h" +#include "services/metrics/public/mojom/ukm_interface.mojom.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace app_list { + +namespace { + +using ukm::TestUkmRecorder; + +using ResultType = ash::SearchResultType; +using UkmEntry = ukm::builders::AppListNonAppImpression; + +std::unique_ptr<KeyedService> BuildHistoryService( + content::BrowserContext* context) { + TestingProfile* profile = static_cast<TestingProfile*>(context); + + base::FilePath history_path(profile->GetPath().Append("history")); + + // Delete the file before creating the service. + if (!base::DeleteFile(history_path, false) || + base::PathExists(history_path)) { + ADD_FAILURE() << "failed to delete history db file " + << history_path.value(); + return nullptr; + } + + std::unique_ptr<history::HistoryService> history_service = + std::make_unique<history::HistoryService>(); + if (history_service->Init( + history::TestHistoryDatabaseParamsForPath(profile->GetPath()))) { + return std::move(history_service); + } + + ADD_FAILURE() << "failed to initialize history service"; + return nullptr; +} + +class TestSearchResult : public ChromeSearchResult { + public: + TestSearchResult(const std::string& id, + ResultType type, + int subtype, + double relevance) + : instance_id_(instantiation_count++) { + set_id(id); + set_result_subtype(subtype); + set_relevance(relevance); + SetTitle(base::UTF8ToUTF16(id)); + SetResultType(type); + } + ~TestSearchResult() override {} + + // ChromeSearchResult overrides: + void Open(int event_flags) override {} + void InvokeAction(int action_index, int event_flags) override {} + SearchResultType GetSearchResultType() const override { + return app_list::SEARCH_RESULT_TYPE_BOUNDARY; + } + + private: + static int instantiation_count; + + int instance_id_; +}; +int TestSearchResult::instantiation_count = 0; + +class SearchControllerFake : public SearchController { + public: + explicit SearchControllerFake(Profile* profile) + : SearchController(nullptr, nullptr, profile) {} + + ChromeSearchResult* FindSearchResult(const std::string& result_id) override { + auto it = results_.find(result_id); + CHECK(it != results_.end()); + return &it->second; + } + + void AddSearchResult(const std::string& result_id, + ResultType type, + int subtype, + double relevance) { + results_.emplace( + std::piecewise_construct, std::forward_as_tuple(result_id), + std::forward_as_tuple(result_id, type, subtype, relevance)); + } + + std::map<std::string, TestSearchResult> results_; +}; + +} // namespace + +class SearchRankingEventLoggerTest : public testing::Test { + public: + SearchRankingEventLoggerTest() {} + + void SetUp() override { + ASSERT_TRUE(history_dir_.CreateUniqueTempDir()); + history_service_ = std::make_unique<history::HistoryService>(); + history_service_->Init( + history::TestHistoryDatabaseParamsForPath(history_dir_.GetPath())); + + TestingProfile::TestingFactories factories; + + TestingProfile::Builder profile_builder; + profile_builder.SetProfileName("testuser@gmail.com"); + profile_builder.AddTestingFactory( + HistoryServiceFactory::GetInstance(), + base::BindRepeating(&BuildHistoryService)); + profile_ = profile_builder.Build(); + + search_controller_ = std::make_unique<SearchControllerFake>(profile_.get()); + + logger_ = std::make_unique<SearchRankingEventLogger>( + profile_.get(), search_controller_.get()); + } + + void AddResultWithHistory(const std::string& result_id, + ResultType type, + int subtype, + double relevance) { + search_controller_->AddSearchResult(result_id, type, subtype, relevance); + history_service_->AddPage(GURL(result_id), base::Time::Now(), + history::VisitSource::SOURCE_BROWSED); + Wait(); + } + + void AddResultWithoutHistory(const std::string& result_id, + ResultType type, + int subtype, + double relevance) { + search_controller_->AddSearchResult(result_id, type, subtype, relevance); + } + + std::vector<const ukm::mojom::UkmEntry*> GetUkmEntries() { + return recorder_.GetEntriesByName(UkmEntry::kEntryName); + } + + void SetLocalTime(const int day, const int hour, const int minute = 10) { + // Advance time to 00:00 on the next local Sunday. + base::Time::Exploded now; + base::Time::Now().LocalExplode(&now); + const auto sunday = base::TimeDelta::FromDays(6 - now.day_of_week) + + base::TimeDelta::FromHours(23 - now.hour) + + base::TimeDelta::FromMinutes(60 - now.minute); + if (sunday > base::TimeDelta()) + time_.Advance(sunday); + + base::Time::Now().LocalExplode(&now); + CHECK_EQ(now.day_of_week, 0); + CHECK_EQ(now.hour, 0); + CHECK_EQ(now.minute, 0); + + // Then advance to the given time and day. + const auto advance = base::TimeDelta::FromDays(day) + + base::TimeDelta::FromHours(hour) + + base::TimeDelta::FromMinutes(minute); + if (advance > base::TimeDelta()) + time_.Advance(advance); + } + + // Wait for separate background task runner in HistoryService to complete + // all tasks and then all the tasks on the current one to complete as well. + void Wait() { + history::BlockUntilHistoryProcessesPendingRequests(history_service_.get()); + thread_bundle_.RunUntilIdle(); + } + + // Wait for a background UKM event to finish processing. This is necessary if + // the logger needs to query UkmBackgroundRecorderService for a Source ID, + // which currently happens if the search result is from the Omnibox. + // + // Warning: this will fail if more than one search result exists within one + // call to SearchRankingEventLogger::Log. + void WaitForUkmEvent() { + base::RunLoop run_loop; + logger_->SetEventRecordedForTesting(run_loop.QuitClosure()); + run_loop.Run(); + } + + content::TestBrowserThreadBundle thread_bundle_; + base::ScopedMockClockOverride time_; + base::ScopedTempDir history_dir_; + + ukm::TestAutoSetUkmRecorder recorder_; + + std::unique_ptr<Profile> profile_; + std::unique_ptr<history::HistoryService> history_service_; + std::unique_ptr<SearchControllerFake> search_controller_; + std::unique_ptr<SearchRankingEventLogger> logger_; + + private: + DISALLOW_COPY_AND_ASSIGN(SearchRankingEventLoggerTest); +}; + +// TODO(931149): We should add a test to ensure that a result with a URL in the +// history service has the correct source ID. + +// Test a single logging call containing only one result. As there is only one +// event, we don't test any of the stateful fields that rely on previous +// launches. +TEST_F(SearchRankingEventLoggerTest, OneEventWithOneResult) { + SetLocalTime(5, 13, 25); + + AddResultWithoutHistory("myfile.txt", ResultType::kLauncher, 2, 0.18); + + logger_->Log(base::UTF8ToUTF16("elevenchars"), {{"myfile.txt", 2}}, 1); + + const auto& entries = GetUkmEntries(); + ASSERT_EQ(entries.size(), 1ul); + + const auto* entry = entries[0]; + TestUkmRecorder::ExpectEntryMetric(entry, "EventId", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "Position", 2); + TestUkmRecorder::ExpectEntryMetric(entry, "IsLaunched", 0); + TestUkmRecorder::ExpectEntryMetric(entry, "QueryLength", 11); + TestUkmRecorder::ExpectEntryMetric(entry, "RelevanceScore", 18); + TestUkmRecorder::ExpectEntryMetric(entry, "Category", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "FileExtension", 57); + TestUkmRecorder::ExpectEntryMetric(entry, "HourOfDay", 13); + TestUkmRecorder::ExpectEntryMetric(entry, "DayOfWeek", 5); +} + +// Test a single logging call containing three results. +TEST_F(SearchRankingEventLoggerTest, OneEventWithManyResults) { + SetLocalTime(4, 16, 10); + + // Subtype is unused here. + AddResultWithoutHistory("first.avi", ResultType::kLauncher, 0, 0.7); + AddResultWithoutHistory("second.mkv", ResultType::kLauncher, 0, 0.6); + AddResultWithoutHistory("third.mov", ResultType::kLauncher, 0, 0.5); + + logger_->Log(base::UTF8ToUTF16("ninechars"), + {{"first.avi", 0}, {"second.mkv", 1}, {"third.mov", 2}}, 1); + + const auto& entries = GetUkmEntries(); + ASSERT_EQ(entries.size(), 3ul); + + const auto* entry = entries[0]; + TestUkmRecorder::ExpectEntryMetric(entry, "EventId", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "Position", 0); + TestUkmRecorder::ExpectEntryMetric(entry, "IsLaunched", 0); + TestUkmRecorder::ExpectEntryMetric(entry, "QueryLength", 9); + TestUkmRecorder::ExpectEntryMetric(entry, "RelevanceScore", 70); + TestUkmRecorder::ExpectEntryMetric(entry, "Category", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "FileExtension", 5); + TestUkmRecorder::ExpectEntryMetric(entry, "HourOfDay", 16); + TestUkmRecorder::ExpectEntryMetric(entry, "DayOfWeek", 4); + + entry = entries[1]; + TestUkmRecorder::ExpectEntryMetric(entry, "EventId", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "Position", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "IsLaunched", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "QueryLength", 9); + TestUkmRecorder::ExpectEntryMetric(entry, "RelevanceScore", 60); + TestUkmRecorder::ExpectEntryMetric(entry, "Category", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "FileExtension", 20); + TestUkmRecorder::ExpectEntryMetric(entry, "HourOfDay", 16); + TestUkmRecorder::ExpectEntryMetric(entry, "DayOfWeek", 4); + + entry = entries[2]; + TestUkmRecorder::ExpectEntryMetric(entry, "EventId", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "Position", 2); + TestUkmRecorder::ExpectEntryMetric(entry, "IsLaunched", 0); + TestUkmRecorder::ExpectEntryMetric(entry, "QueryLength", 9); + TestUkmRecorder::ExpectEntryMetric(entry, "RelevanceScore", 50); + TestUkmRecorder::ExpectEntryMetric(entry, "Category", 1); + TestUkmRecorder::ExpectEntryMetric(entry, "FileExtension", 21); + TestUkmRecorder::ExpectEntryMetric(entry, "HourOfDay", 16); + TestUkmRecorder::ExpectEntryMetric(entry, "DayOfWeek", 4); +} + +// Tests the fields that are affected by previous launches of a given search +// result. +TEST_F(SearchRankingEventLoggerTest, StatefulFieldsOfRepeatedEvents) { + SetLocalTime(4, 16, 10); + AddResultWithoutHistory("file.txt", ResultType::kLauncher, 3, 0.7); + + logger_->Log(base::UTF8ToUTF16("query"), {{"file.txt", 0}}, 0); + + { + const auto& entries = GetUkmEntries(); + ASSERT_EQ(entries.size(), 1ul); + TestUkmRecorder::ExpectEntryMetric(entries[0], "EventId", 1); + TestUkmRecorder::ExpectEntryMetric(entries[0], "LaunchesThisSession", 0); + } + + // Record four more evenets, but only three of them are launches (two for the + // purposes of the metrics for the last event). + logger_->Log(base::UTF8ToUTF16("query"), {{"file.txt", 1}}, 1); + // Not a launch: + logger_->Log(base::UTF8ToUTF16("abcd"), {{"file.txt", 0}}, -1); + logger_->Log(base::UTF8ToUTF16("abcd"), {{"file.txt", 2}}, 2); + logger_->Log(base::UTF8ToUTF16(""), {{"file.txt", 0}}, 0); + + { + const auto& entries = GetUkmEntries(); + ASSERT_EQ(entries.size(), 5ul); + TestUkmRecorder::ExpectEntryMetric(entries[4], "EventId", 5); + TestUkmRecorder::ExpectEntryMetric(entries[4], "LaunchesThisSession", 3); + TestUkmRecorder::ExpectEntryMetric(entries[4], "TimeSinceLastLaunch", 0); + TestUkmRecorder::ExpectEntryMetric(entries[4], "TimeOfLastLaunch", 16); + TestUkmRecorder::ExpectEntryMetric(entries[4], "LaunchesAtHour16", 3); + } + + // Advance time by 24 hours. We expect LaunchesAtHour16 to be reset to 0. + time_.Advance(base::TimeDelta::FromHours(24)); + + logger_->Log(base::UTF8ToUTF16(""), {{"file.txt", 0}}, 0); + + { + const auto& entries = GetUkmEntries(); + ASSERT_EQ(entries.size(), 6ul); + // Bin of 24*60*60 has value 85507, which is the 211th bin overall. + TestUkmRecorder::ExpectEntryMetric(entries[5], "TimeSinceLastLaunch", + 85507); + TestUkmRecorder::ExpectEntryMetric(entries[5], "TimeOfLastLaunch", 16); + TestUkmRecorder::ExpectEntryMetric(entries[5], "LaunchesAtHour16", 0); + } +} + +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc index 801e9c1..2b31171 100644 --- a/chrome/browser/ui/app_list/search/omnibox_result.cc +++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -231,6 +231,10 @@ } } +GURL OmniboxResult::DestinationURL() const { + return match_.destination_url; +} + void OmniboxResult::UpdateIcon() { BookmarkModel* bookmark_model = BookmarkModelFactory::GetForBrowserContext(profile_);
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.h b/chrome/browser/ui/app_list/search/omnibox_result.h index 33e821c..677ffb3 100644 --- a/chrome/browser/ui/app_list/search/omnibox_result.h +++ b/chrome/browser/ui/app_list/search/omnibox_result.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "chrome/browser/ui/app_list/search/chrome_search_result.h" #include "components/omnibox/browser/autocomplete_match.h" +#include "url/gurl.h" class AppListControllerDelegate; class AutocompleteController; @@ -41,6 +42,9 @@ void InvokeAction(int action_index, int event_flags) override; SearchResultType GetSearchResultType() const override; + // Returns the URL that will be navigated to by this search result. + GURL DestinationURL() const; + private: void UpdateIcon(); void UpdateTitleAndDetails();
diff --git a/chrome/browser/ui/app_list/search/search_controller.h b/chrome/browser/ui/app_list/search/search_controller.h index f641795..543db34 100644 --- a/chrome/browser/ui/app_list/search/search_controller.h +++ b/chrome/browser/ui/app_list/search/search_controller.h
@@ -52,7 +52,7 @@ // Takes ownership of |provider| and associates it with given mixer group. void AddProvider(size_t group_id, std::unique_ptr<SearchProvider> provider); - ChromeSearchResult* FindSearchResult(const std::string& result_id); + virtual ChromeSearchResult* FindSearchResult(const std::string& result_id); ChromeSearchResult* GetResultByTitleForTest(const std::string& title); // Sends training signal to each |providers_|
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_util.cc b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_util.cc index bf196d93..96233c5b 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_util.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker_util.cc
@@ -237,14 +237,13 @@ } JsonConfigConverter::JsonConfigConverter(service_manager::Connector* connector) - : connector_(connector) { - DCHECK(connector_); -} + : connector_(connector) {} JsonConfigConverter::~JsonConfigConverter() {} void JsonConfigConverter::Convert(const std::string& json_string, const std::string& model_identifier, OnConfigLoadedCallback callback) { + DCHECK(connector_); GetJsonParser().Parse( json_string, base::BindOnce(&JsonConfigConverter::OnJsonParsed, base::Unretained(this),
diff --git a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc index 355cf01..3e1b4d6 100644 --- a/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/tests/app_search_provider_unittest.cc
@@ -20,7 +20,8 @@ #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/time/time.h" -#include "chrome/browser/apps/app_service/app_service_proxy_impl.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" +#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/chromeos/crostini/crostini_test_helper.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/sync/session_sync_service_factory.h" @@ -835,8 +836,8 @@ return; } - apps::AppServiceProxyImpl* proxy = - apps::AppServiceProxyImpl::GetImplForTesting(profile()); + apps::AppServiceProxy* proxy = + apps::AppServiceProxyFactory::GetForProfile(profile()); ASSERT_NE(proxy, nullptr); apps::StubIconLoader stub_icon_loader;
diff --git a/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc b/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc index ad5aef6f..19a045d6 100644 --- a/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc +++ b/chrome/browser/ui/ash/accessibility/accessibility_controller_client.cc
@@ -88,6 +88,15 @@ } } +void AccessibilityControllerClient::TriggerAccessibilityAlertWithMessage( + const std::string& message) { + Profile* profile = ProfileManager::GetActiveUserProfile(); + if (!profile) + return; + + AutomationManagerAura::GetInstance()->HandleAlert(message); +} + void AccessibilityControllerClient::PlayEarcon(int32_t sound_key) { chromeos::AccessibilityManager::Get()->PlayEarcon( sound_key, chromeos::PlaySoundOption::ONLY_IF_SPOKEN_FEEDBACK_ENABLED);
diff --git a/chrome/browser/ui/ash/accessibility/accessibility_controller_client.h b/chrome/browser/ui/ash/accessibility/accessibility_controller_client.h index 5c20abe..60e70f18 100644 --- a/chrome/browser/ui/ash/accessibility/accessibility_controller_client.h +++ b/chrome/browser/ui/ash/accessibility/accessibility_controller_client.h
@@ -17,6 +17,8 @@ // ash::AccessibilityControllerClient: void TriggerAccessibilityAlert(ash::AccessibilityAlert alert) override; + void TriggerAccessibilityAlertWithMessage( + const std::string& message) override; void PlayEarcon(int sound_key) override; base::TimeDelta PlayShutdownSound() override; void HandleAccessibilityGesture(ax::mojom::Gesture gesture) override;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc index c19dd81..db6a3fb 100644 --- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc +++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -38,7 +38,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/build_config.h" -#include "chrome/browser/apps/app_service/app_service_proxy_impl.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/arc_apps.h" #include "chrome/browser/chromeos/arc/arc_util.h" #include "chrome/browser/chromeos/crostini/crostini_test_helper.h" @@ -324,11 +324,11 @@ bool flush_app_service_mojo_calls = false; if (app_service_proxy_connector_) { DCHECK(profile()); - app_service_proxy_impl_.reset(apps::AppServiceProxyImpl::CreateForTesting( + app_service_proxy_.reset(apps::AppServiceProxy::CreateForTesting( profile(), app_service_proxy_connector_)); old_app_service_proxy_for_testing_ = AppServiceAppModelBuilder::SetAppServiceProxyForTesting( - app_service_proxy_impl_.get()); + app_service_proxy_.get()); // Flush the App Service Mojo calls, but only after calling // arc_test_.SetUp, as it also pumps the run-loop in general. flush_app_service_mojo_calls = true; @@ -338,7 +338,7 @@ arc_test_.SetUp(profile()); if (flush_app_service_mojo_calls) - app_service_proxy_impl_->FlushMojoCallsForTesting(); + app_service_proxy_->FlushMojoCallsForTesting(); // Wait until |extension_system| is signaled as started. base::RunLoop run_loop; @@ -481,10 +481,10 @@ void TearDown() override { arc_test_.TearDown(); - if (app_service_proxy_impl_) { + if (app_service_proxy_) { AppServiceAppModelBuilder::SetAppServiceProxyForTesting( old_app_service_proxy_for_testing_); - app_service_proxy_impl_.reset(nullptr); + app_service_proxy_.reset(nullptr); } launcher_controller_ = nullptr; BrowserWithTestWindowTest::TearDown(); @@ -969,7 +969,7 @@ app_list::AppListSyncableService* app_list_syncable_service_ = nullptr; service_manager::Connector* app_service_proxy_connector_ = nullptr; - std::unique_ptr<apps::AppServiceProxyImpl> app_service_proxy_impl_; + std::unique_ptr<apps::AppServiceProxy> app_service_proxy_; apps::AppServiceProxy* old_app_service_proxy_for_testing_ = nullptr; private: @@ -1015,8 +1015,8 @@ ChromeLauncherControllerTest::SetUp(); if (app_service_proxy_connector_) { - arc_apps_.reset(apps::ArcApps::CreateForTesting( - profile(), app_service_proxy_impl_.get())); + arc_apps_.reset( + apps::ArcApps::CreateForTesting(profile(), app_service_proxy_.get())); } } @@ -1489,8 +1489,8 @@ EXPECT_EQ("App2, Fake App 1, Chrome, App1, Fake App 0, Gmail", GetPinnedAppStatus()); - if (app_service_proxy_impl_) - app_service_proxy_impl_->FlushMojoCallsForTesting(); + if (app_service_proxy_) + app_service_proxy_->FlushMojoCallsForTesting(); copy_sync_list = app_list_syncable_service_->GetAllSyncData(syncer::APP_LIST); ResetLauncherController();
diff --git a/chrome/browser/ui/ash/launcher_page_switches_interactive_uitest.cc b/chrome/browser/ui/ash/launcher_page_switches_interactive_uitest.cc index bf8f784..d4675a1 100644 --- a/chrome/browser/ui/ash/launcher_page_switches_interactive_uitest.cc +++ b/chrome/browser/ui/ash/launcher_page_switches_interactive_uitest.cc
@@ -12,8 +12,11 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/test/base/perf/drag_event_generator.h" #include "chrome/test/base/perf/performance_test.h" #include "ui/base/test/ui_controls.h" +#include "ui/display/display.h" +#include "ui/display/screen.h" namespace { @@ -116,3 +119,74 @@ INSTANTIATE_TEST_SUITE_P(, LauncherPageSwitchesTest, /*tablet_mode=*/::testing::Bool()); + +// The test gets very flaky in tablet-mode, so it's in clamshell mode only for +// now. +// TODO(mukai): investigate why and enable this test case with tablet-mode too. +class LauncherPageDragTest : public UIPerformanceTest { + public: + LauncherPageDragTest() = default; + ~LauncherPageDragTest() override = default; + + // UIPerformanceTest: + void SetUpOnMainThread() override { + UIPerformanceTest::SetUpOnMainThread(); + + test::PopulateDummyAppListItems(100); + + ash::ShellTestApi shell_test_api; + + // Open the fullscreen app; required for page switching. + BrowserView* browser_view = + BrowserView::GetBrowserViewForBrowser(browser()); + aura::Window* browser_window = browser_view->GetWidget()->GetNativeWindow(); + ui_controls::SendKeyPress(browser_window, ui::VKEY_BROWSER_SEARCH, + /*control=*/false, + /*shift=*/true, + /*alt=*/false, + /* command = */ false); + shell_test_api.WaitForLauncherAnimationState( + ash::AppListViewState::kFullscreenAllApps); + + if (base::SysInfo::IsRunningOnChromeOS()) { + base::RunLoop run_loop; + base::PostDelayedTask(FROM_HERE, run_loop.QuitClosure(), + base::TimeDelta::FromSeconds(5)); + run_loop.Run(); + } + } + + // UIPerformanceTest: + std::vector<std::string> GetUMAHistogramNames() const override { + return { + "Apps.PaginationTransition.DragScroll.PresentationTime.ClamshellMode", + "Apps.PaginationTransition.DragScroll.PresentationTime.MaxLatency." + "ClamshellMode", + }; + } + + private: + DISALLOW_COPY_AND_ASSIGN(LauncherPageDragTest); +}; + +IN_PROC_BROWSER_TEST_F(LauncherPageDragTest, Run) { + ash::ShellTestApi shell_test_api; + + gfx::Rect display_bounds = + display::Screen::GetScreen() + ->GetDisplayNearestWindow(browser()->window()->GetNativeWindow()) + .bounds(); + gfx::Point start_point = display_bounds.CenterPoint(); + gfx::Point end_point(start_point); + end_point.set_y(10); + ui_test_utils::DragEventGenerator generator( + std::make_unique<ui_test_utils::InterpolatedProducer>( + start_point, end_point, base::TimeDelta::FromMilliseconds(1000)), + /*touch=*/true); + + ash::PaginationModel* model = ash::ShellTestApi().GetAppListPaginationModel(); + ASSERT_TRUE(model); + PageSwitchWaiter waiter(model); + generator.Wait(); + waiter.Wait(); +}
diff --git a/chrome/browser/ui/ash/multi_user/multi_profile_support.cc b/chrome/browser/ui/ash/multi_user/multi_profile_support.cc index 355bacee..173acbd 100644 --- a/chrome/browser/ui/ash/multi_user/multi_profile_support.cc +++ b/chrome/browser/ui/ash/multi_user/multi_profile_support.cc
@@ -12,7 +12,6 @@ #include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h" @@ -23,7 +22,6 @@ #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" -#include "content/public/browser/notification_service.h" #include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/app_window_registry.h" #include "ui/aura/client/aura_constants.h" @@ -120,6 +118,8 @@ DCHECK_EQ(instance_, this); instance_ = nullptr; + BrowserList::RemoveObserver(this); + // This may trigger callbacks to us, delete it early on. multi_user_window_manager_.reset(); @@ -150,10 +150,7 @@ DCHECK(account_id_to_app_observer_.find(current_account_id) == account_id_to_app_observer_.end()); - // The BrowserListObserver would have been better to use then the old - // notification system, but that observer fires before the window got created. - registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, - content::NotificationService::AllSources()); + BrowserList::AddObserver(this); // Add an app window observer & all already running apps. Profile* profile = @@ -184,19 +181,20 @@ account_id_to_app_observer_[account_id]->OnAppWindowAdded(*it); // Account all existing browser windows of this user accordingly. - BrowserList* browser_list = BrowserList::GetInstance(); - BrowserList::const_iterator browser_it = browser_list->begin(); - for (; browser_it != browser_list->end(); ++browser_it) { - if ((*browser_it)->profile()->GetOriginalProfile() == profile) - AddBrowserWindow(*browser_it); + for (auto* browser : *BrowserList::GetInstance()) { + if (browser->profile()->IsSameProfile(profile)) + OnBrowserAdded(browser); } } -void MultiProfileSupport::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK_EQ(chrome::NOTIFICATION_BROWSER_OPENED, type); - AddBrowserWindow(content::Source<Browser>(source).ptr()); +void MultiProfileSupport::OnBrowserAdded(Browser* browser) { + // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can + // come here with no valid window. + if (!browser->window() || !browser->window()->GetNativeWindow()) + return; + multi_user_window_manager_->SetWindowOwner( + browser->window()->GetNativeWindow(), + multi_user_util::GetAccountIdFromProfile(browser->profile())); } void MultiProfileSupport::OnWindowOwnerEntryChanged(aura::Window* window, @@ -233,13 +231,3 @@ chrome_launcher_controller->ActiveUserChanged( multi_user_window_manager_->CurrentAccountId()); } - -void MultiProfileSupport::AddBrowserWindow(Browser* browser) { - // A unit test (e.g. CrashRestoreComplexTest.RestoreSessionForThreeUsers) can - // come here with no valid window. - if (!browser->window() || !browser->window()->GetNativeWindow()) - return; - multi_user_window_manager_->SetWindowOwner( - browser->window()->GetNativeWindow(), - multi_user_util::GetAccountIdFromProfile(browser->profile())); -}
diff --git a/chrome/browser/ui/ash/multi_user/multi_profile_support.h b/chrome/browser/ui/ash/multi_user/multi_profile_support.h index 4f9c5b8..836d2b07 100644 --- a/chrome/browser/ui/ash/multi_user/multi_profile_support.h +++ b/chrome/browser/ui/ash/multi_user/multi_profile_support.h
@@ -11,9 +11,8 @@ #include "ash/public/cpp/multi_user_window_manager_delegate.h" #include "base/macros.h" #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h" +#include "chrome/browser/ui/browser_list_observer.h" #include "components/account_id/account_id.h" -#include "content/public/browser/notification_observer.h" -#include "content/public/browser/notification_registrar.h" class AppObserver; class Browser; @@ -36,7 +35,7 @@ // to MultiUserWindowManager as well as all app windows. This class is only // created if SessionControllerClient::IsMultiProfileAvailable() returns true. class MultiProfileSupport : public ash::MultiUserWindowManagerDelegate, - public content::NotificationObserver { + public BrowserListObserver { public: // Create the manager and use |active_account_id| as the active user. explicit MultiProfileSupport(const AccountId& active_account_id); @@ -55,10 +54,8 @@ return multi_user_window_manager_.get(); } - // content::NotificationObserver overrides: - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; + // BrowserListObserver: + void OnBrowserAdded(Browser* browser) override; private: friend class ash::MultiProfileSupportTest; @@ -70,9 +67,6 @@ bool teleported) override; void OnTransitionUserShelfToNewAccount() override; - // Add a browser window to the system so that the owner can be remembered. - void AddBrowserWindow(Browser* browser); - // The single instance of MultiProfileSupport, tracked solely for // tests. static MultiProfileSupport* instance_; @@ -82,9 +76,6 @@ // A list of all known users and their app window observers. AccountIdToAppWindowObserver account_id_to_app_observer_; - // The notification registrar to track the creation of browser windows. - content::NotificationRegistrar registrar_; - std::unique_ptr<ash::MultiUserWindowManager> multi_user_window_manager_; DISALLOW_COPY_AND_ASSIGN(MultiProfileSupport);
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc index f209428..5837a67 100644 --- a/chrome/browser/ui/browser_browsertest.cc +++ b/chrome/browser/ui/browser_browsertest.cc
@@ -961,9 +961,9 @@ content::PrepContentsForBeforeUnloadTest(contents); // Open a second browser window at about:blank. - ui_test_utils::BrowserAddedObserver browser_added_observer; chrome::NewEmptyWindow(browser()->profile()); - Browser* second_window = browser_added_observer.WaitForSingleNewBrowser(); + Browser* second_window = BrowserList::GetInstance()->GetLastActive(); + EXPECT_NE(second_window, browser()); ui_test_utils::NavigateToURL(second_window, GURL(url::kAboutBlankURL)); // Tell the application to quit. IDC_EXIT calls AttemptUserExit, which on @@ -2164,9 +2164,7 @@ CloseBrowserSynchronously(browser()); EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); - ui_test_utils::BrowserAddedObserver browser_added_observer; chrome::NewEmptyWindow(profile); - browser_added_observer.WaitForSingleNewBrowser(); EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); } @@ -2196,9 +2194,7 @@ EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); // Starting a browser window should work just fine. - ui_test_utils::BrowserAddedObserver browser_added_observer; CreateBrowser(ProfileManager::GetActiveUserProfile()); - browser_added_observer.WaitForSingleNewBrowser(); EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); } @@ -2215,9 +2211,7 @@ session_service->GetBaseSessionServiceForTest(); ASSERT_FALSE(ProcessedAnyCommands(base_session_service)); - ui_test_utils::BrowserAddedObserver browser_added_observer; CreateBrowserForApp("blah", profile); - browser_added_observer.WaitForSingleNewBrowser(); ASSERT_FALSE(ProcessedAnyCommands(base_session_service)); } @@ -2682,9 +2676,7 @@ browser()->tab_strip_model()->GetActiveWebContents()); Profile* profile = ProfileManager::GetActiveUserProfile(); - ui_test_utils::BrowserAddedObserver browser_added_observer; Browser* app_browser = CreateBrowserForApp("blah", profile); - browser_added_observer.WaitForSingleNewBrowser(); auto* app_contents = app_browser->tab_strip_model()->GetActiveWebContents(); CheckDisplayModeMQ(ASCIIToUTF16("standalone"), app_contents);
diff --git a/chrome/browser/ui/browser_list.cc b/chrome/browser/ui/browser_list.cc index 600ae7f..7de80a8 100644 --- a/chrome/browser/ui/browser_list.cc +++ b/chrome/browser/ui/browser_list.cc
@@ -110,10 +110,6 @@ RemoveBrowserFrom(browser, &browser_list->last_active_browsers_); browser_list->currently_closing_browsers_.erase(browser); - content::NotificationService::current()->Notify( - chrome::NOTIFICATION_BROWSER_CLOSED, content::Source<Browser>(browser), - content::NotificationService::NoDetails()); - RemoveBrowserFrom(browser, &browser_list->browsers_); for (BrowserListObserver& observer : observers_.Get())
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h index 38fe7bc8..3ff9e612 100644 --- a/chrome/browser/ui/browser_window.h +++ b/chrome/browser/ui/browser_window.h
@@ -340,16 +340,16 @@ virtual void ShowUpdateChromeDialog() = 0; // Shows the intent picker bubble. |app_info| contains the app candidates to - // display, |enable_stay_in_chrome| allows to enable or disable 'Stay in - // Chrome' (used for non-http(s) queries), if |show_persistence_options| is - // false, the "remember my choice" checkbox is hidden, the "stay in chrome" - // button is hidden, and |callback| helps to continue the flow back to either + // display, if |show_stay_in_chrome| is false, the 'Stay in + // Chrome' (used for non-http(s) queries) button is hidden, if + // |show_remember_selection| is false, the "remember my choice" checkbox is + // hidden and |callback| helps to continue the flow back to either // AppsNavigationThrottle or ArcExternalProtocolDialog capturing the user's // decision and storing UMA metrics. virtual void ShowIntentPickerBubble( std::vector<apps::IntentPickerAppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse callback) = 0; // Shows the Bookmark bubble. |url| is the URL being bookmarked,
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc index 4c817cbcc..fcc364537 100644 --- a/chrome/browser/ui/chrome_pages.cc +++ b/chrome/browser/ui/chrome_pages.cc
@@ -124,8 +124,8 @@ } const std::string query_string = base::StrCat( - {kChromeReleaseNotesURL, "version=", milestone, "&tags=", board_name, ",", - region, ",", language, ",", channel_name, ",", user_type}); + {kChromeReleaseNotesURL, "?version=", milestone, "&tags=", board_name, + ",", region, ",", language, ",", channel_name, ",", user_type}); return query_string; } #endif
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h index 6984eb0..2db0731 100644 --- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h +++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h
@@ -34,6 +34,8 @@ override {} void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override {} + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} private: service_manager::Connector* const connector_;
diff --git a/chrome/browser/ui/libgtkui/gtk_util.cc b/chrome/browser/ui/libgtkui/gtk_util.cc index bf5e42a..4f3fa80 100644 --- a/chrome/browser/ui/libgtkui/gtk_util.cc +++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -86,7 +86,7 @@ std::string GetDesktopName(base::Environment* env) { #if defined(GOOGLE_CHROME_BUILD) return "google-chrome.desktop"; -#else // CHROMIUM_BUILD +#else // BUILDFLAG(CHROMIUM_BRANDING) // Allow $CHROME_DESKTOP to override the built-in value, so that development // versions can set themselves as the default without interfering with // non-official, packaged versions using the built-in value.
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc index 9e57eb7..4e2ec6a 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.cc +++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -45,6 +45,8 @@ #include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_list_observer.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/startup/startup_browser_creator_impl.h" #include "chrome/common/buildflags.h" @@ -108,43 +110,36 @@ namespace { // Keeps track on which profiles have been launched. -class ProfileLaunchObserver : public content::NotificationObserver { +class ProfileLaunchObserver : public content::NotificationObserver, + public BrowserListObserver { public: - ProfileLaunchObserver() - : profile_to_activate_(NULL), - activated_profile_(false) { + ProfileLaunchObserver() { registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, content::NotificationService::AllSources()); - registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, - content::NotificationService::AllSources()); + BrowserList::AddObserver(this); } - ~ProfileLaunchObserver() override {} + ~ProfileLaunchObserver() override { BrowserList::RemoveObserver(this); } + + // BrowserListObserver: + void OnBrowserAdded(Browser* browser) override { + opened_profiles_.insert(browser->profile()); + MaybeActivateProfile(); + } + + // content::NotificationObserver: void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) override { - switch (type) { - case chrome::NOTIFICATION_PROFILE_DESTROYED: { - Profile* profile = content::Source<Profile>(source).ptr(); - launched_profiles_.erase(profile); - opened_profiles_.erase(profile); - if (profile == profile_to_activate_) - profile_to_activate_ = NULL; - // If this profile was the last launched one without an opened window, - // then we may be ready to activate |profile_to_activate_|. - MaybeActivateProfile(); - break; - } - case chrome::NOTIFICATION_BROWSER_OPENED: { - Browser* browser = content::Source<Browser>(source).ptr(); - DCHECK(browser); - opened_profiles_.insert(browser->profile()); - MaybeActivateProfile(); - break; - } - default: - NOTREACHED(); - } + DCHECK_EQ(type, chrome::NOTIFICATION_PROFILE_DESTROYED); + Profile* profile = content::Source<Profile>(source).ptr(); + launched_profiles_.erase(profile); + opened_profiles_.erase(profile); + if (profile == profile_to_activate_) + profile_to_activate_ = nullptr; + // If this profile was the last launched one without an opened window, + // then we may be ready to activate |profile_to_activate_|. + MaybeActivateProfile(); } bool HasBeenLaunched(const Profile* profile) const { @@ -155,7 +150,7 @@ launched_profiles_.insert(profile); if (chrome::FindBrowserWithProfile(profile)) { // A browser may get opened before we get initialized (e.g., in tests), - // so we never see the NOTIFICATION_BROWSER_OPENED for it. + // so we never see the OnBrowserAdded() for it. opened_profiles_.insert(profile); } } @@ -191,10 +186,8 @@ base::BindOnce(&ProfileLaunchObserver::ActivateProfile, base::Unretained(this))); // Avoid posting more than once before ActivateProfile gets called. - registrar_.Remove(this, chrome::NOTIFICATION_BROWSER_OPENED, - content::NotificationService::AllSources()); - registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_DESTROYED, - content::NotificationService::AllSources()); + registrar_.RemoveAll(); + BrowserList::RemoveObserver(this); } void ActivateProfile() { @@ -207,7 +200,7 @@ if (browser) browser->window()->Activate(); // No need try to activate this profile again. - profile_to_activate_ = NULL; + profile_to_activate_ = nullptr; } // Assign true here, even if no browser was actually activated, so that // the test can stop waiting, and fail gracefully when needed. @@ -223,12 +216,12 @@ // be activated on top of it. std::set<const Profile*> opened_profiles_; content::NotificationRegistrar registrar_; - // This is NULL until the profile to activate has been chosen. This value, + // This is null until the profile to activate has been chosen. This value // should only be set once all profiles have been launched, otherwise, // activation may not happen after the launch of newer profiles. - Profile* profile_to_activate_; + Profile* profile_to_activate_ = nullptr; // Set once we attempted to activate a profile. We only get one shot at this. - bool activated_profile_; + bool activated_profile_ = false; DISALLOW_COPY_AND_ASSIGN(ProfileLaunchObserver); };
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc index 542fcd9e..57f74b8b 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -1025,36 +1025,6 @@ ASSERT_EQ(1u, chrome::GetBrowserCount(profile2)); } -class SupervisedUserBrowserCreatorTest : public InProcessBrowserTest { - protected: - void SetUpCommandLine(base::CommandLine* command_line) override { - command_line->AppendSwitchASCII(switches::kSupervisedUserId, - supervised_users::kChildAccountSUID); - } -}; - -IN_PROC_BROWSER_TEST_F(SupervisedUserBrowserCreatorTest, - StartupSupervisedUserProfile) { - StartupBrowserCreator browser_creator; - - // Do a simple non-process-startup browser launch. - base::CommandLine dummy(base::CommandLine::NO_PROGRAM); - StartupBrowserCreatorImpl launch(base::FilePath(), dummy, &browser_creator, - chrome::startup::IS_FIRST_RUN); - content::WindowedNotificationObserver observer( - content::NOTIFICATION_LOAD_STOP, - content::NotificationService::AllSources()); - ASSERT_TRUE(launch.Launch(browser()->profile(), std::vector<GURL>(), false)); - - // This should have created a new browser window. - Browser* new_browser = FindOneOtherBrowser(browser()); - ASSERT_TRUE(new_browser); - - TabStripModel* tab_strip = new_browser->tab_strip_model(); - - EXPECT_EQ(1, tab_strip->count()); -} - #endif // !defined(OS_CHROMEOS) // These tests are not applicable to Chrome OS as neither master_preferences nor
diff --git a/chrome/browser/ui/tabs/tab_group_data.h b/chrome/browser/ui/tabs/tab_group_data.h index a246f01..11f87437 100644 --- a/chrome/browser/ui/tabs/tab_group_data.h +++ b/chrome/browser/ui/tabs/tab_group_data.h
@@ -15,6 +15,8 @@ public: // Construct a TabGroupData with placeholder name and random color. TabGroupData(); + TabGroupData(const TabGroupData& other) = default; + TabGroupData(TabGroupData&& other) = default; ~TabGroupData() = default; base::string16 title() const { return title_; } @@ -30,8 +32,6 @@ base::string16 title_; SkColor color_; int tab_count_; - - DISALLOW_COPY_AND_ASSIGN(TabGroupData); }; #endif // CHROME_BROWSER_UI_TABS_TAB_GROUP_DATA_H_
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc index 07be43c..e81c3861 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.cc +++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -780,7 +780,7 @@ const TabGroupData* TabStripModel::GetDataForGroup(TabGroupId group) const { DCHECK(base::Contains(group_data_, group)); - return group_data_.at(group).get(); + return &group_data_.at(group); } base::Optional<TabGroupId> TabStripModel::GetTabGroupForTab(int index) const { @@ -1488,7 +1488,7 @@ } data->set_group(group); if (group.has_value()) - group_data_[group.value()]->TabAdded(); + group_data_[group.value()].TabAdded(); // TODO(gbillock): Ask the modal dialog manager whether the WebContents should // be blocked, or just let the modal dialog manager make the blocking call @@ -1759,7 +1759,7 @@ contents_data_.cbegin(), contents_data_.cend(), [new_group](const auto& datum) { return datum->group() == new_group; })); - group_data_[new_group] = std::make_unique<TabGroupData>(); + group_data_.emplace(new_group, TabGroupData()); // Find a destination for the first tab that's not inside another group. We // will stack the rest of the tabs up to its right. @@ -1843,7 +1843,7 @@ MoveWebContentsAtImpl(index, new_index, false); contents_data_[new_index]->set_group(new_group); if (new_group.has_value()) - group_data_[new_group.value()]->TabAdded(); + group_data_[new_group.value()].TabAdded(); NotifyGroupChange(new_index, old_group, new_group); } @@ -1870,7 +1870,7 @@ return base::nullopt; contents_data_[index]->set_group(base::nullopt); - TabGroupData* group_data = group_data_[group.value()].get(); + TabGroupData* group_data = &group_data_[group.value()]; group_data->TabRemoved(); // Delete the group if we just ungrouped the last tab in that group. if (group_data->empty())
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h index 056cba0..a8b49ffa 100644 --- a/chrome/browser/ui/tabs/tab_strip_model.h +++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -34,7 +34,6 @@ #endif class Profile; -class TabGroupData; class TabStripModelDelegate; namespace content { @@ -325,7 +324,8 @@ // https://crbug.com/915956). base::Optional<TabGroupId> GetTabGroupForTab(int index) const; - // Returns the TabGroupData instance for the given |group|. + // Returns the TabGroupData instance for the given |group|. The returned + // pointer is valid until all tabs in |group| are destroyed. const TabGroupData* GetDataForGroup(TabGroupId group) const; // Returns a list of tab groups that contain at least one tab in this strip. @@ -668,7 +668,7 @@ // The data for tab groups hosted within this TabStripModel, indexed by the // group ID. - std::map<TabGroupId, std::unique_ptr<TabGroupData>> group_data_; + std::map<TabGroupId, TabGroupData> group_data_; TabStripModelDelegate* delegate_;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index f270fc7..c63acd4 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1327,11 +1327,11 @@ void BrowserView::ShowIntentPickerBubble( std::vector<IntentPickerBubbleView::AppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse callback) { - toolbar_->ShowIntentPickerBubble(std::move(app_info), enable_stay_in_chrome, - show_persistence_options, + toolbar_->ShowIntentPickerBubble(std::move(app_info), show_stay_in_chrome, + show_remember_selection, std::move(callback)); }
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index 1b4c73e..fd80be425 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -366,8 +366,8 @@ void ShowUpdateChromeDialog() override; void ShowIntentPickerBubble( std::vector<IntentPickerBubbleView::AppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse callback) override; void ShowBookmarkBubble(const GURL& url, bool already_bookmarked) override; autofill::SaveCardBubbleView* ShowSaveCreditCardBubble(
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc index d0aa8a9..f79efbd 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -120,8 +120,8 @@ views::View* anchor_view, content::WebContents* web_contents, std::vector<AppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse intent_picker_cb) { if (intent_picker_bubble_) { intent_picker_bubble_->Initialize(); @@ -140,7 +140,7 @@ BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); intent_picker_bubble_ = new IntentPickerBubbleView( std::move(app_info), std::move(intent_picker_cb), web_contents, - enable_stay_in_chrome, show_persistence_options); + show_stay_in_chrome, show_remember_selection); intent_picker_bubble_->set_margins(gfx::Insets()); if (anchor_view) { @@ -184,13 +184,13 @@ // static std::unique_ptr<IntentPickerBubbleView> IntentPickerBubbleView::CreateBubbleView(std::vector<AppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse intent_picker_cb, content::WebContents* web_contents) { std::unique_ptr<IntentPickerBubbleView> bubble(new IntentPickerBubbleView( std::move(app_info), std::move(intent_picker_cb), web_contents, - enable_stay_in_chrome, show_persistence_options)); + show_stay_in_chrome, show_remember_selection)); bubble->Initialize(); return bubble; } @@ -242,7 +242,8 @@ } int IntentPickerBubbleView::GetDialogButtons() const { - if (show_persistence_options_) + // The cancel button here refers to the 'Stay in Chrome' button + if (show_stay_in_chrome_) return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL; return ui::DIALOG_BUTTON_OK; } @@ -251,13 +252,6 @@ return l10n_util::GetStringUTF16(IDS_INTENT_PICKER_BUBBLE_VIEW_OPEN_WITH); } -bool IntentPickerBubbleView::IsDialogButtonEnabled( - ui::DialogButton button) const { - if (!enable_stay_in_chrome_ && button == ui::DIALOG_BUTTON_CANCEL) - return false; - return true; -} - base::string16 IntentPickerBubbleView::GetDialogButtonLabel( ui::DialogButton button) const { return l10n_util::GetStringUTF16( @@ -270,16 +264,16 @@ std::vector<AppInfo> app_info, IntentPickerResponse intent_picker_cb, content::WebContents* web_contents, - bool enable_stay_in_chrome, - bool show_persistence_options) + bool show_stay_in_chrome, + bool show_remember_selection) : LocationBarBubbleDelegateView(nullptr /* anchor_view */, gfx::Point(), web_contents), intent_picker_cb_(std::move(intent_picker_cb)), selected_app_tag_(0), app_info_(std::move(app_info)), - enable_stay_in_chrome_(enable_stay_in_chrome), - show_persistence_options_(show_persistence_options) { + show_stay_in_chrome_(show_stay_in_chrome), + show_remember_selection_(show_remember_selection) { chrome::RecordDialogCreation(chrome::DialogIdentifier::INTENT_PICKER); } @@ -388,8 +382,7 @@ scroll_view_ = layout->AddView(std::move(scroll_view)); layout->StartRow(views::GridLayout::kFixedSize, kColumnSetId, 0); - // Add Show remember selection checkbox if there are apps besides pwas present - if (show_persistence_options_) { + if (show_remember_selection_) { layout->AddView(CreateHorizontalSeparator()); // This second ColumnSet has a padding column in order to manipulate the
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.h b/chrome/browser/ui/views/intent_picker_bubble_view.h index 6aae126..327e0fd3 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view.h +++ b/chrome/browser/ui/views/intent_picker_bubble_view.h
@@ -64,13 +64,13 @@ static views::Widget* ShowBubble(views::View* anchor_view, content::WebContents* web_contents, std::vector<AppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse intent_picker_cb); static std::unique_ptr<IntentPickerBubbleView> CreateBubbleView( std::vector<AppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse intent_picker_cb, content::WebContents* web_contents); static IntentPickerBubbleView* intent_picker_bubble() { @@ -90,7 +90,6 @@ protected: // LocationBarBubbleDelegateView overrides: base::string16 GetWindowTitle() const override; - bool IsDialogButtonEnabled(ui::DialogButton button) const override; base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; void CloseBubble() override; @@ -108,8 +107,8 @@ IntentPickerBubbleView(std::vector<AppInfo> app_info, IntentPickerResponse intent_picker_cb, content::WebContents* web_contents, - bool enable_stay_in_chrome, - bool show_persistence_options); + bool show_stay_in_chrome, + bool show_remember_selection); // views::BubbleDialogDelegateView overrides: void OnWidgetDestroying(views::Widget* widget) override; @@ -174,12 +173,11 @@ views::Checkbox* remember_selection_checkbox_ = nullptr; - // Tells whether or not 'Stay in Chrome' should be enabled as an option. - const bool enable_stay_in_chrome_; + // Tells whether 'Stay in Chrome' button should be shown or hidden. + const bool show_stay_in_chrome_; - // Whether 'Remember selection' checkbox and "Stay in chrome" button should be - // shown or hidden. - const bool show_persistence_options_; + // Whether 'Remember my choice' checkbox should be shown or hidden. + const bool show_remember_selection_; DISALLOW_COPY_AND_ASSIGN(IntentPickerBubbleView); };
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc b/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc index 9389e367..a272f6e 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc
@@ -40,7 +40,7 @@ } protected: - void CreateBubbleView(bool use_icons, bool enable_stay_in_chrome) { + void CreateBubbleView(bool use_icons, bool show_stay_in_chrome) { // Pushing a couple of fake apps just to check they are created on the UI. app_info_.emplace_back(apps::mojom::AppType::kArc, gfx::Image(), "package_1", "dank app 1"); @@ -73,8 +73,8 @@ } bubble_ = IntentPickerBubbleView::CreateBubbleView( - std::move(app_info), enable_stay_in_chrome, - /*show_persistence_options=*/true, + std::move(app_info), show_stay_in_chrome, + /*show_remember_selection=*/true, base::Bind(&IntentPickerBubbleViewTest::OnBubbleClosed, base::Unretained(this)), web_contents); @@ -102,7 +102,7 @@ // Verifies that we didn't set up an image for any LabelButton. TEST_F(IntentPickerBubbleViewTest, NullIcons) { - CreateBubbleView(/*use_icons=*/false, /*enable_stay_in_chrome=*/true); + CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/true); size_t size = bubble_->GetScrollViewSize(); for (size_t i = 0; i < size; ++i) { gfx::ImageSkia image = bubble_->GetAppImageForTesting(i); @@ -112,7 +112,7 @@ // Verifies that all the icons contain a non-null icon. TEST_F(IntentPickerBubbleViewTest, NonNullIcons) { - CreateBubbleView(/*use_icons=*/true, /*enable_stay_in_chrome=*/true); + CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true); size_t size = bubble_->GetScrollViewSize(); for (size_t i = 0; i < size; ++i) { gfx::ImageSkia image = bubble_->GetAppImageForTesting(i); @@ -125,7 +125,7 @@ // shown to the user on the picker UI, so there could be a difference // represented by |chrome_package_repetitions|. TEST_F(IntentPickerBubbleViewTest, LabelsPtrVectorSize) { - CreateBubbleView(/*use_icons=*/true, /*enable_stay_in_chrome=*/true); + CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true); size_t size = app_info_.size(); size_t chrome_package_repetitions = 0; for (const AppInfo& app_info : app_info_) { @@ -138,7 +138,7 @@ // Verifies the InkDrop state when creating a new bubble. TEST_F(IntentPickerBubbleViewTest, VerifyStartingInkDrop) { - CreateBubbleView(/*use_icons=*/true, /*enable_stay_in_chrome=*/true); + CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true); size_t size = bubble_->GetScrollViewSize(); for (size_t i = 0; i < size; ++i) { EXPECT_EQ(bubble_->GetInkDropStateForTesting(i), @@ -149,7 +149,7 @@ // Press each button at a time and make sure it goes to ACTIVATED state, // followed by HIDDEN state after selecting other button. TEST_F(IntentPickerBubbleViewTest, InkDropStateTransition) { - CreateBubbleView(/*use_icons=*/true, /*enable_stay_in_chrome=*/true); + CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true); const ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(), 0, 0); size_t size = bubble_->GetScrollViewSize(); @@ -165,7 +165,7 @@ // Arbitrary press the first button twice, check that the InkDropState remains // the same. TEST_F(IntentPickerBubbleViewTest, PressButtonTwice) { - CreateBubbleView(/*use_icons=*/true, /*enable_stay_in_chrome=*/true); + CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true); const ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), ui::EventTimeForNow(), 0, 0); EXPECT_EQ(bubble_->GetInkDropStateForTesting(0), views::InkDropState::HIDDEN); @@ -180,7 +180,7 @@ // Check that none of the app candidates within the picker corresponds to the // Chrome browser. TEST_F(IntentPickerBubbleViewTest, ChromeNotInCandidates) { - CreateBubbleView(/*use_icons=*/false, /*enable_stay_in_chrome=*/true); + CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/true); size_t size = bubble_->GetScrollViewSize(); for (size_t i = 0; i < size; ++i) { EXPECT_FALSE(arc::ArcIntentHelperBridge::IsIntentHelperPackage( @@ -188,21 +188,11 @@ } } -// Check that 'Stay in Chrome' remains enabled/disabled accordingly. For this -// UI, DIALOG_BUTTON_CANCEL maps to 'Stay in Chrome'. -TEST_F(IntentPickerBubbleViewTest, StayInChromeTest) { - CreateBubbleView(/*use_icons=*/false, /*enable_stay_in_chrome=*/false); - EXPECT_EQ(bubble_->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL), false); - - CreateBubbleView(/*use_icons=*/false, /*enable_stay_in_chrome=*/true); - EXPECT_EQ(bubble_->IsDialogButtonEnabled(ui::DIALOG_BUTTON_CANCEL), true); -} - // Check that a non nullptr WebContents() has been created and observed. TEST_F(IntentPickerBubbleViewTest, WebContentsTiedToBubble) { - CreateBubbleView(/*use_icons=*/false, /*enable_stay_in_chrome=*/false); + CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false); EXPECT_TRUE(bubble_->web_contents()); - CreateBubbleView(/*use_icons=*/false, /*enable_stay_in_chrome=*/true); + CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/true); EXPECT_TRUE(bubble_->web_contents()); }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index dda1742c..45f5a7d 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -1313,7 +1313,10 @@ // Also revert if the text has been edited but currently exactly matches // the permanent text. An example of this scenario is someone typing on the // new tab page and then deleting everything using backspace/delete. + // + // This should never exit keyword mode. if (GetWidget() && GetWidget()->IsActive() && popup_closes_on_blur && + !model()->is_keyword_selected() && ((!model()->user_input_in_progress() && text() != model()->GetPermanentDisplayText()) || (model()->user_input_in_progress() &&
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc index c14ec2c3..430da08 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -576,6 +576,23 @@ EXPECT_TRUE(omnibox_view()->model()->keyword().empty()); } +TEST_F(OmniboxViewViewsTest, BlurNeverExitsKeywordMode) { + location_bar_model()->set_url(GURL()); + omnibox_view()->model()->ResetDisplayTexts(); + omnibox_view()->RevertAll(); + + // Enter keyword mode, but with no user text. + omnibox_view()->model()->EnterKeywordModeForDefaultSearchProvider( + OmniboxEventProto::KEYBOARD_SHORTCUT); + EXPECT_TRUE(omnibox_view()->text().empty()); + EXPECT_FALSE(omnibox_view()->model()->keyword().empty()); + + // Expect that on blur, stay in keyword mode. + omnibox_textfield()->OnBlur(); + EXPECT_TRUE(omnibox_view()->text().empty()); + EXPECT_FALSE(omnibox_view()->model()->keyword().empty()); +} + TEST_F(OmniboxViewViewsTest, PasteAndGoToUrlOrSearchCommand) { ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); ui::ClipboardType clipboard_type = ui::ClipboardType::kCopyPaste;
diff --git a/chrome/browser/ui/views/passwords/password_items_view.cc b/chrome/browser/ui/views/passwords/password_items_view.cc index b6bef992..215f27d 100644 --- a/chrome/browser/ui/views/passwords/password_items_view.cc +++ b/chrome/browser/ui/views/passwords/password_items_view.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/views/passwords/password_items_view.h" #include <numeric> +#include <utility> #include "base/macros.h" #include "base/strings/utf_string_conversions.h" @@ -125,7 +126,7 @@ }); bool display_arrow = !usernames.empty(); auto combobox = std::make_unique<views::EditableCombobox>( - std::make_unique<ui::SimpleComboboxModel>(usernames), + std::make_unique<ui::SimpleComboboxModel>(std::move(usernames)), /*filter_on_edit=*/false, /*show_on_empty=*/true, views::EditableCombobox::Type::kRegular, views::style::CONTEXT_BUTTON, views::style::STYLE_PRIMARY, display_arrow);
diff --git a/chrome/browser/ui/views/passwords/password_pending_view.cc b/chrome/browser/ui/views/passwords/password_pending_view.cc index fb92ff9..3b21bee 100644 --- a/chrome/browser/ui/views/passwords/password_pending_view.cc +++ b/chrome/browser/ui/views/passwords/password_pending_view.cc
@@ -187,7 +187,7 @@ }); bool display_arrow = !passwords.empty(); auto combobox = std::make_unique<views::EditableCombobox>( - std::make_unique<ui::SimpleComboboxModel>(passwords), + std::make_unique<ui::SimpleComboboxModel>(std::move(passwords)), /*filter_on_edit=*/false, /*show_on_empty=*/true, views::EditableCombobox::Type::kPassword, views::style::CONTEXT_BUTTON, STYLE_PRIMARY_MONOSPACED, display_arrow);
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.cc b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.cc index 159fa3a7..f968b096 100644 --- a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.cc +++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.cc
@@ -22,7 +22,6 @@ #include "ui/strings/grit/ui_strings.h" #include "ui/views/border.h" #include "ui/views/controls/link.h" -#include "ui/views/controls/styled_label.h" #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" @@ -110,12 +109,6 @@ controller_->OnHelpTextClicked(); } -void ClickToCallDialogView::StyledLabelLinkClicked(views::StyledLabel* label, - const gfx::Range& range, - int event_flags) { - controller_->OnHelpTextClicked(); -} - void ClickToCallDialogView::Init() { SetLayoutManager(std::make_unique<views::BoxLayout>( views::BoxLayout::Orientation::kVertical)); @@ -170,9 +163,14 @@ } void ClickToCallDialogView::InitListView() { + LogClickToCallDialogShown( + devices_.empty() + ? SharingClickToCallDialogType::kDialogWithoutDevicesWithApp + : SharingClickToCallDialogType::kDialogWithDevicesMaybeApps); + int tag = 0; // Devices: - LogClickToCallDevicesToShow(devices_.size()); + LogClickToCallDevicesToShow(kSharingClickToCallUiDialog, devices_.size()); for (const auto& device : devices_) { auto dialog_button = std::make_unique<HoverButton>( this, CreateDeviceIcon(device.device_type()), @@ -183,7 +181,7 @@ } // Apps: - LogClickToCallAppsToShow(apps_.size()); + LogClickToCallAppsToShow(kSharingClickToCallUiDialog, apps_.size()); for (const auto& app : apps_) { auto dialog_button = std::make_unique<HoverButton>(this, CreateIconView(app.icon), app.name, @@ -195,6 +193,8 @@ } void ClickToCallDialogView::InitEmptyView() { + LogClickToCallDialogShown(SharingClickToCallDialogType::kEducationalDialog); + auto label = std::make_unique<views::Label>( l10n_util::GetStringUTF16( IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_HELP_TEXT_NO_DEVICES), @@ -225,17 +225,13 @@ } void ClickToCallDialogView::InitErrorView() { - const base::string16 link = l10n_util::GetStringUTF16( - IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TROUBLESHOOT_LINK); - size_t offset; - const base::string16 text = l10n_util::GetStringFUTF16( - IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE, link, &offset); - auto label = std::make_unique<views::StyledLabel>(text, this); + LogClickToCallDialogShown(SharingClickToCallDialogType::kErrorDialog); - views::StyledLabel::RangeStyleInfo link_style = - views::StyledLabel::RangeStyleInfo::CreateForLink(); - label->AddStyleRange(gfx::Range(offset, offset + link.length()), link_style); - + auto label = std::make_unique<views::Label>( + l10n_util::GetStringUTF16( + IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE), + views::style::CONTEXT_LABEL, ChromeTextStyle::STYLE_SECONDARY); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); AddChildView(std::move(label)); } @@ -262,5 +258,5 @@ } void ClickToCallDialogView::WindowClosing() { - controller_->OnDialogClosed(); + controller_->OnDialogClosed(this); }
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h index 7dd4985..7e0a139 100644 --- a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h +++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_dialog_view.h
@@ -14,11 +14,9 @@ #include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/link_listener.h" -#include "ui/views/controls/styled_label_listener.h" namespace views { class Link; -class StyledLabel; class View; } // namespace views @@ -28,7 +26,6 @@ class ClickToCallDialogView : public ClickToCallDialog, public views::ButtonListener, public views::LinkListener, - public views::StyledLabelListener, public LocationBarBubbleDelegateView { public: // Bubble will be anchored to |anchor_view|. @@ -49,11 +46,6 @@ // views::LinkListener: void LinkClicked(views::Link* source, int event_flags) override; - // views::StyledLabelListener: - void StyledLabelLinkClicked(views::StyledLabel* label, - const gfx::Range& range, - int event_flags) override; - // views::DialogDelegate: int GetDialogButtons() const override; std::unique_ptr<views::View> CreateFootnoteView() override;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 53845f7..f4d0f272 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -401,8 +401,8 @@ void ToolbarView::ShowIntentPickerBubble( std::vector<IntentPickerBubbleView::AppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse callback) { PageActionIconView* intent_picker_view = location_bar() @@ -413,7 +413,7 @@ IntentPickerTabHelper::SetShouldShowIcon(GetWebContents(), true); IntentPickerBubbleView::ShowBubble( intent_picker_view, GetWebContents(), std::move(app_info), - enable_stay_in_chrome, show_persistence_options, std::move(callback)); + show_stay_in_chrome, show_remember_selection, std::move(callback)); } }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h index ed67a74..307dc295 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.h +++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -117,8 +117,8 @@ void ShowIntentPickerBubble( std::vector<IntentPickerBubbleView::AppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse callback); // Shows a bookmark bubble and anchors it appropriately.
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc index 04a95253..8df423bb 100644 --- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc +++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -10,11 +10,11 @@ #include "base/containers/flat_map.h" #include "base/stl_util.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/services/app_service/public/cpp/app_registry_cache.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" #include "chrome/services/app_service/public/mojom/types.mojom.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/constants.h"
diff --git a/chrome/browser/ui/webui/browsing_history_handler.cc b/chrome/browser/ui/webui/browsing_history_handler.cc index 6a3bd9f..389bc5d 100644 --- a/chrome/browser/ui/webui/browsing_history_handler.cc +++ b/chrome/browser/ui/webui/browsing_history_handler.cc
@@ -153,7 +153,7 @@ std::unique_ptr<base::DictionaryValue> HistoryEntryToValue( const BrowsingHistoryService::HistoryEntry& entry, BookmarkModel* bookmark_model, - SupervisedUserService* supervised_user_service, + Profile* profile, const syncer::DeviceInfoTracker* tracker, base::Clock* clock) { std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); @@ -223,6 +223,11 @@ result->SetString("deviceType", device_type); #if BUILDFLAG(ENABLE_SUPERVISED_USERS) + SupervisedUserService* supervised_user_service = nullptr; + if (profile->IsSupervised()) { + supervised_user_service = + SupervisedUserServiceFactory::GetForProfile(profile); + } if (supervised_user_service) { const SupervisedUserURLFilter* url_filter = supervised_user_service->GetURLFilter(); @@ -375,12 +380,6 @@ Profile* profile = Profile::FromWebUI(web_ui()); BookmarkModel* bookmark_model = BookmarkModelFactory::GetForBrowserContext(profile); - SupervisedUserService* supervised_user_service = NULL; -#if defined(ENABLE_SUPERVISED_USERS) - if (profile->IsSupervised()) - supervised_user_service = - SupervisedUserServiceFactory::GetForProfile(profile); -#endif const syncer::DeviceInfoTracker* tracker = DeviceInfoSyncServiceFactory::GetForProfile(profile) @@ -390,8 +389,8 @@ DCHECK(tracker); base::ListValue results_value; for (const BrowsingHistoryService::HistoryEntry& entry : results) { - std::unique_ptr<base::Value> value(HistoryEntryToValue( - entry, bookmark_model, supervised_user_service, tracker, clock_)); + std::unique_ptr<base::Value> value( + HistoryEntryToValue(entry, bookmark_model, profile, tracker, clock_)); results_value.Append(std::move(value)); }
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 734a3e5..8f6d49bf 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -58,7 +58,6 @@ #include "chrome/browser/ui/webui/settings/settings_ui.h" #include "chrome/browser/ui/webui/settings_utils.h" #include "chrome/browser/ui/webui/signin_internals_ui.h" -#include "chrome/browser/ui/webui/supervised_user_internals_ui.h" #include "chrome/browser/ui/webui/sync_internals_ui.h" #include "chrome/browser/ui/webui/translate_internals/translate_internals_ui.h" #include "chrome/browser/ui/webui/ukm/ukm_internals_ui.h" @@ -236,6 +235,10 @@ #include "chrome/browser/ui/webui/reset_password/reset_password_ui.h" #endif +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/ui/webui/supervised_user_internals_ui.h" +#endif + using content::WebUI; using content::WebUIController; using ui::WebDialogUI; @@ -403,8 +406,6 @@ return &NewWebUI<SignInInternalsUI>; if (url.host_piece() == chrome::kChromeUISuggestionsHost) return &NewWebUI<suggestions::SuggestionsUI>; - if (url.host_piece() == chrome::kChromeUISupervisedUserInternalsHost) - return &NewWebUI<SupervisedUserInternalsUI>; if (url.host_piece() == chrome::kChromeUISupervisedUserPassphrasePageHost) return &NewWebUI<ConstrainedWebDialogUI>; if (url.host_piece() == chrome::kChromeUISyncInternalsHost) @@ -718,6 +719,11 @@ } #endif +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + if (url.host_piece() == chrome::kChromeUISupervisedUserInternalsHost) + return &NewWebUI<SupervisedUserInternalsUI>; +#endif + return NULL; }
diff --git a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc index 450ea8da..0acab1a 100644 --- a/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc +++ b/chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler.cc
@@ -9,6 +9,7 @@ #include <vector> #include "base/stl_util.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile.h" @@ -18,7 +19,6 @@ #include "chrome/browser/ui/app_list/arc/arc_app_utils.h" #include "chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_handler_utils.h" #include "chrome/services/app_service/public/cpp/app_registry_cache.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" #include "components/signin/public/identity_manager/access_token_fetcher.h" #include "components/signin/public/identity_manager/access_token_info.h" #include "components/signin/public/identity_manager/identity_manager.h"
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc index 8230958ad3..2e65bdf 100644 --- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc +++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
@@ -22,6 +22,7 @@ #include "chromeos/services/assistant/public/cpp/assistant_prefs.h" #include "components/arc/arc_prefs.h" #include "components/prefs/pref_service.h" +#include "components/session_manager/core/session_manager.h" #include "content/public/browser/host_zoom_map.h" #include "content/public/browser/url_data_source.h" #include "content/public/browser/web_ui.h" @@ -118,6 +119,12 @@ void AssistantOptInDialog::Show( ash::FlowType type, ash::AssistantSetup::StartAssistantOptInFlowCallback callback) { + // Check session state here to prevent timing issue -- session state might + // have changed during the mojom calls to launch the opt-in dalog. + if (session_manager::SessionManager::Get()->session_state() != + session_manager::SessionState::ACTIVE) { + return; + } if (g_dialog) { g_dialog->Focus(); std::move(callback).Run(false);
diff --git a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc index 981076b..36ab5f6 100644 --- a/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/chromeos/cellular_setup/cellular_setup_localized_strings_provider.cc
@@ -23,6 +23,9 @@ {"finish", IDS_CELLULAR_SETUP_FINISH_LABEL}, {"tryAgain", IDS_CELLULAR_SETUP_TRY_AGAIN_LABEL}, {"simDetectPageTitle", IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_TITLE}, + {"simDetectPageErrorTitle", IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_ERROR_TITLE}, + {"simDetectPageErrorMessage", + IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_ERROR_MESSAGE}, {"provisioningPageTitle", IDS_CELLULAR_SETUP_PROVISIONING_PAGE_TITLE}, {"finalPageTitle", IDS_CELLULAR_SETUP_FINAL_PAGE_TITLE}, {"finalPageMessage", IDS_CELLULAR_SETUP_FINAL_PAGE_MESSAGE},
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.cc index adca3a6..e46a6ea 100644 --- a/chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.cc +++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/confirm_password_change_handler.cc
@@ -9,8 +9,6 @@ #include "base/logging.h" #include "base/macros.h" #include "base/values.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_process_platform_part_chromeos.h" #include "chrome/browser/chromeos/login/saml/in_session_password_change_manager.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/profiles/profile.h" @@ -22,17 +20,15 @@ namespace chromeos { ConfirmPasswordChangeHandler::ConfirmPasswordChangeHandler() { - auto* in_session_password_change_manager = - g_browser_process->platform_part()->in_session_password_change_manager(); - CHECK(in_session_password_change_manager); - in_session_password_change_manager->AddObserver(this); + if (InSessionPasswordChangeManager::IsInitialized()) { + InSessionPasswordChangeManager::Get()->AddObserver(this); + } } ConfirmPasswordChangeHandler::~ConfirmPasswordChangeHandler() { - auto* in_session_password_change_manager = - g_browser_process->platform_part()->in_session_password_change_manager(); - CHECK(in_session_password_change_manager); - in_session_password_change_manager->RemoveObserver(this); + if (InSessionPasswordChangeManager::IsInitialized()) { + InSessionPasswordChangeManager::Get()->RemoveObserver(this); + } } void ConfirmPasswordChangeHandler::OnEvent( @@ -48,11 +44,8 @@ const base::ListValue* params) { const std::string old_password = params->GetList()[0].GetString(); const std::string new_password = params->GetList()[1].GetString(); - auto* in_session_password_change_manager = - g_browser_process->platform_part()->in_session_password_change_manager(); - CHECK(in_session_password_change_manager); - in_session_password_change_manager->ChangePassword(old_password, - new_password); + InSessionPasswordChangeManager::Get()->ChangePassword(old_password, + new_password); } void ConfirmPasswordChangeHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.cc index 01f87b4..fa57cf5d 100644 --- a/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.cc +++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/password_change_handler.cc
@@ -9,8 +9,6 @@ #include "base/logging.h" #include "base/macros.h" #include "base/values.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_process_platform_part_chromeos.h" #include "chrome/browser/chromeos/login/auth/chrome_cryptohome_authenticator.h" #include "chrome/browser/chromeos/login/saml/in_session_password_change_manager.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" @@ -60,11 +58,8 @@ ? new_passwords.GetList()[0].GetString() : ""; - auto* in_session_password_change_manager = - g_browser_process->platform_part()->in_session_password_change_manager(); - CHECK(in_session_password_change_manager); - in_session_password_change_manager->OnSamlPasswordChanged(old_password, - new_password); + InSessionPasswordChangeManager::Get()->OnSamlPasswordChanged(old_password, + new_password); } void PasswordChangeHandler::RegisterMessages() {
diff --git a/chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.cc b/chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.cc index fa3506f..627e157 100644 --- a/chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.cc +++ b/chrome/browser/ui/webui/chromeos/in_session_password_change/urgent_password_expiry_notification_handler.cc
@@ -9,8 +9,6 @@ #include "base/logging.h" #include "base/macros.h" #include "base/values.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_process_platform_part_chromeos.h" #include "chrome/browser/chromeos/login/saml/in_session_password_change_manager.h" #include "chrome/browser/chromeos/login/saml/password_expiry_notification.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" @@ -30,10 +28,7 @@ void UrgentPasswordExpiryNotificationHandler::HandleContinue( const base::ListValue* params) { - auto* in_session_password_change_manager = - g_browser_process->platform_part()->in_session_password_change_manager(); - CHECK(in_session_password_change_manager); - in_session_password_change_manager->StartInSessionPasswordChange(); + InSessionPasswordChangeManager::Get()->StartInSessionPasswordChange(); } void UrgentPasswordExpiryNotificationHandler::HandleGetTitleText(
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 54b787d4..eca0146a 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -1305,7 +1305,10 @@ void SigninScreenHandler::HandleFocusPod(const AccountId& account_id, bool is_large_pod) { proximity_auth::ScreenlockBridge::Get()->SetFocusedUser(account_id); - if (delegate_) + const bool is_same_pod_focused = + focused_pod_account_id_ && *focused_pod_account_id_ == account_id; + + if (delegate_ && !is_same_pod_focused) delegate_->CheckUserStatus(account_id); if (!test_focus_pod_callback_.is_null()) test_focus_pod_callback_.Run(); @@ -1317,21 +1320,26 @@ // |user| may be nullptr in kiosk mode or unit tests. if (user && user->is_logged_in() && !user->is_active()) { SessionControllerClientImpl::DoSwitchActiveUser(account_id); - } else { - lock_screen_utils::SetUserInputMethod(account_id.GetUserEmail(), - ime_state_.get()); - lock_screen_utils::SetKeyboardSettings(account_id); - if (LoginDisplayHost::default_host() && is_large_pod) - LoginDisplayHost::default_host()->LoadWallpaper(account_id); + return; + } - bool use_24hour_clock = false; - if (user_manager::known_user::GetBooleanPref( - account_id, prefs::kUse24HourClock, &use_24hour_clock)) { - g_browser_process->platform_part() - ->GetSystemClock() - ->SetLastFocusedPodHourClockType( - use_24hour_clock ? base::k24HourClock : base::k12HourClock); - } + if (LoginDisplayHost::default_host() && is_large_pod) + LoginDisplayHost::default_host()->LoadWallpaper(account_id); + + if (is_same_pod_focused) + return; + + lock_screen_utils::SetUserInputMethod(account_id.GetUserEmail(), + ime_state_.get()); + lock_screen_utils::SetKeyboardSettings(account_id); + + bool use_24hour_clock = false; + if (user_manager::known_user::GetBooleanPref( + account_id, prefs::kUse24HourClock, &use_24hour_clock)) { + g_browser_process->platform_part() + ->GetSystemClock() + ->SetLastFocusedPodHourClockType(use_24hour_clock ? base::k24HourClock + : base::k12HourClock); } }
diff --git a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc index 4fbf410..1a5607b 100644 --- a/chrome/browser/ui/webui/interstitials/interstitial_ui.cc +++ b/chrome/browser/ui/webui/interstitials/interstitial_ui.cc
@@ -21,7 +21,6 @@ #include "chrome/browser/ssl/bad_clock_blocking_page.h" #include "chrome/browser/ssl/mitm_software_blocking_page.h" #include "chrome/browser/ssl/ssl_blocking_page.h" -#include "chrome/browser/supervised_user/supervised_user_interstitial.h" #include "chrome/common/buildflags.h" #include "chrome/common/url_constants.h" #include "components/grit/components_resources.h"
diff --git a/chrome/browser/ui/webui/omnibox/omnibox.mojom b/chrome/browser/ui/webui/omnibox/omnibox.mojom index de8253d..0f5dbb70 100644 --- a/chrome/browser/ui/webui/omnibox/omnibox.mojom +++ b/chrome/browser/ui/webui/omnibox/omnibox.mojom
@@ -59,6 +59,7 @@ string type; string host; bool is_typed_host; + string input_text; array<AutocompleteMatch> combined_results; array<AutocompleteResultsForProvider> results_by_provider; };
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_page_handler.cc b/chrome/browser/ui/webui/omnibox/omnibox_page_handler.cc index 97def4a..0c1f86f6 100644 --- a/chrome/browser/ui/webui/omnibox/omnibox_page_handler.cc +++ b/chrome/browser/ui/webui/omnibox/omnibox_page_handler.cc
@@ -254,6 +254,7 @@ if (!LookupIsTypedHost(host, &is_typed_host)) is_typed_host = false; response->is_typed_host = is_typed_host; + response->input_text = base::UTF16ToUTF8(input_.text()); { // Copy to an ACMatches to make conversion easier. Since this isn't
diff --git a/chrome/browser/ui/webui/omnibox/omnibox_ui.cc b/chrome/browser/ui/webui/omnibox/omnibox_ui.cc index 7ad3bb9..af3ee72 100644 --- a/chrome/browser/ui/webui/omnibox/omnibox_ui.cc +++ b/chrome/browser/ui/webui/omnibox/omnibox_ui.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/omnibox/omnibox_page_handler.h" +#include "chrome/browser/ui/webui/version_ui.h" #include "chrome/common/url_constants.h" #include "chrome/grit/browser_resources.h" #include "content/public/browser/web_ui.h" @@ -19,6 +20,11 @@ // Set up the chrome://omnibox/ source. content::WebUIDataSource* source = content::WebUIDataSource::Create(chrome::kChromeUIOmniboxHost); + + // Expose version information to client because it is useful in output. + VersionUI::AddVersionDetailStrings(source); + source->SetJsonPath("strings.js"); + source->AddResourcePath("omnibox.css", IDR_OMNIBOX_CSS); source->AddResourcePath("omnibox_input.css", IDR_OMNIBOX_INPUT_CSS); source->AddResourcePath("output_results_group.css",
diff --git a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc index c544f08..fdf98ee 100644 --- a/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/kerberos_accounts_handler.cc
@@ -58,6 +58,11 @@ CHECK_EQ(1U, args->GetSize()); const std::string& callback_id = args->GetList()[0].GetString(); + if (!KerberosCredentialsManager::Get().IsKerberosEnabled()) { + ResolveJavascriptCallback(base::Value(callback_id), base::Value()); + return; + } + KerberosCredentialsManager::Get().ListAccounts( base::BindOnce(&KerberosAccountsHandler::OnListAccounts, weak_factory_.GetWeakPtr(), callback_id)); @@ -103,7 +108,7 @@ accounts.GetList().push_back(std::move(account_dict)); } - ResolveJavascriptCallback(base::Value(callback_id), accounts); + ResolveJavascriptCallback(base::Value(callback_id), std::move(accounts)); } void KerberosAccountsHandler::HandleAddKerberosAccount( @@ -122,6 +127,12 @@ const std::string& config = args->GetList()[4].GetString(); const bool allow_existing = args->GetList()[5].GetBool(); + if (!KerberosCredentialsManager::Get().IsKerberosEnabled()) { + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(kerberos::ERROR_KERBEROS_DISABLED)); + return; + } + KerberosCredentialsManager::Get().AddAccountAndAuthenticate( principal_name, false /* is_managed */, password, remember_password, config, allow_existing, @@ -144,6 +155,12 @@ const std::string& callback_id = args->GetList()[0].GetString(); const std::string& principal_name = args->GetList()[1].GetString(); + if (!KerberosCredentialsManager::Get().IsKerberosEnabled()) { + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(kerberos::ERROR_KERBEROS_DISABLED)); + return; + } + KerberosCredentialsManager::Get().RemoveAccount( principal_name, base::BindOnce(&KerberosAccountsHandler::OnRemoveAccount, weak_factory_.GetWeakPtr(), callback_id)); @@ -163,6 +180,12 @@ const std::string& callback_id = args->GetList()[0].GetString(); const std::string& krb5conf = args->GetList()[1].GetString(); + if (!KerberosCredentialsManager::Get().IsKerberosEnabled()) { + ResolveJavascriptCallback(base::Value(callback_id), + base::Value(kerberos::ERROR_KERBEROS_DISABLED)); + return; + } + KerberosCredentialsManager::Get().ValidateConfig( krb5conf, base::BindOnce(&KerberosAccountsHandler::OnValidateConfig, weak_factory_.GetWeakPtr(), callback_id));
diff --git a/chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.cc b/chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.cc index 851bdac..b76ceac4 100644 --- a/chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/parental_controls_handler.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/values.h" +#include "chrome/browser/apps/app_service/app_service_proxy.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/chromeos/arc/arc_session_manager.h" #include "chrome/browser/profiles/profile.h" @@ -15,7 +16,6 @@ #include "chrome/browser/ui/browser_navigator_params.h" #include "chrome/browser/ui/webui/chromeos/add_supervision/add_supervision_ui.h" #include "chrome/services/app_service/public/cpp/app_registry_cache.h" -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" #include "chrome/services/app_service/public/cpp/app_update.h" #include "chrome/services/app_service/public/mojom/types.mojom.h" #include "components/arc/arc_util.h"
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 5429506..9dc2fca 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -615,7 +615,7 @@ html_source->AddString( "androidAppsSubtext", l10n_util::GetStringFUTF16( - IDS_SETTINGS_ANDROID_APPS_SUBTEXT, + IDS_SETTINGS_ANDROID_APPS_SUBTEXT, ui::GetChromeOSDeviceName(), GetHelpUrlWithBoard(chrome::kAndroidAppsLearnMoreURL))); } @@ -2486,6 +2486,7 @@ {"osSearchPageTitle", is_assistant_allowed ? IDS_SETTINGS_SEARCH_AND_ASSISTANT : IDS_SETTINGS_SEARCH}, + {"osSearchEngineLabel", IDS_OS_SETTINGS_SEARCH_ENGINE_LABEL}, {"searchGoogleAssistant", IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT}, {"searchGoogleAssistantEnabled", IDS_SETTINGS_SEARCH_GOOGLE_ASSISTANT_ENABLED}, @@ -2500,6 +2501,9 @@ base::ASCIIToUTF16(chrome::kOmniboxLearnMoreURL)); html_source->AddString("searchExplanation", search_explanation_text); #if defined(OS_CHROMEOS) + html_source->AddString( + "osSearchEngineTooltip", + ui::SubstituteChromeOSDeviceType(IDS_OS_SETTINGS_SEARCH_ENGINE_TOOLTIP)); html_source->AddBoolean("isAssistantAllowed", is_assistant_allowed); #endif } @@ -3062,10 +3066,6 @@ {"multideviceAndroidMessagesItemTitle", IDS_SETTINGS_MULTIDEVICE_ANDROID_MESSAGES}, {"multideviceForgetDevice", IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE}, - {"multideviceForgetDeviceSummary", - IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_EXPLANATION}, - {"multideviceForgetDeviceDialogMessage", - IDS_SETTINGS_MULTIDEVICE_FORGET_DEVICE_DIALOG_MESSAGE}, {"multideviceSmartLockOptions", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_OPTIONS_LOCK}, }; @@ -3073,6 +3073,14 @@ base::size(kLocalizedStrings)); html_source->AddString( + "multideviceForgetDeviceSummary", + ui::SubstituteChromeOSDeviceType( + IDS_SETTINGS_MULTIDEVICE_FORGET_THIS_DEVICE_EXPLANATION)); + html_source->AddString( + "multideviceForgetDeviceDialogMessage", + ui::SubstituteChromeOSDeviceType( + IDS_SETTINGS_MULTIDEVICE_FORGET_DEVICE_DIALOG_MESSAGE)); + html_source->AddString( "multideviceVerificationText", l10n_util::GetStringFUTF16( IDS_SETTINGS_MULTIDEVICE_VERIFICATION_TEXT, @@ -3083,7 +3091,7 @@ html_source->AddString( "multideviceSetupSummary", l10n_util::GetStringFUTF16( - IDS_SETTINGS_MULTIDEVICE_SETUP_SUMMARY, + IDS_SETTINGS_MULTIDEVICE_SETUP_SUMMARY, ui::GetChromeOSDeviceName(), base::UTF8ToUTF16( chromeos::multidevice_setup:: GetBoardSpecificBetterTogetherSuiteLearnMoreUrl() @@ -3100,6 +3108,7 @@ "multideviceAndroidMessagesItemSummary", l10n_util::GetStringFUTF16( IDS_SETTINGS_MULTIDEVICE_ANDROID_MESSAGES_SUMMARY, + ui::GetChromeOSDeviceName(), base::UTF8ToUTF16(chromeos::multidevice_setup:: GetBoardSpecificMessagesLearnMoreUrl() .spec()))); @@ -3107,6 +3116,7 @@ "multideviceSmartLockItemSummary", l10n_util::GetStringFUTF16( IDS_SETTINGS_MULTIDEVICE_SMART_LOCK_SUMMARY, + ui::GetChromeOSDeviceName(), GetHelpUrlWithBoard(chrome::kEasyUnlockLearnMoreUrl))); } #endif
diff --git a/chrome/browser/ui/webui/version_ui.cc b/chrome/browser/ui/webui/version_ui.cc index 8127a54..e0759744e 100644 --- a/chrome/browser/ui/webui/version_ui.cc +++ b/chrome/browser/ui/webui/version_ui.cc
@@ -55,8 +55,7 @@ WebUIDataSource* CreateVersionUIDataSource() { WebUIDataSource* html_source = WebUIDataSource::Create(chrome::kChromeUIVersionHost); - - // Localized strings. + // These localized strings are used to label version details. static constexpr LocalizedString kStrings[] = { {version_ui::kTitle, IDS_VERSION_UI_TITLE}, {version_ui::kApplicationLabel, IDS_PRODUCT_NAME}, @@ -82,6 +81,42 @@ }; AddLocalizedStringsBulk(html_source, kStrings, base::size(kStrings)); + VersionUI::AddVersionDetailStrings(html_source); + + html_source->SetJsonPath("strings.js"); + html_source->AddResourcePath(version_ui::kVersionJS, IDR_VERSION_UI_JS); + html_source->AddResourcePath(version_ui::kAboutVersionCSS, + IDR_VERSION_UI_CSS); + html_source->SetDefaultResource(IDR_VERSION_UI_HTML); + return html_source; +} + +} // namespace + +VersionUI::VersionUI(content::WebUI* web_ui) + : content::WebUIController(web_ui) { + Profile* profile = Profile::FromWebUI(web_ui); + +#if defined(OS_CHROMEOS) + web_ui->AddMessageHandler(std::make_unique<VersionHandlerChromeOS>()); +#elif defined(OS_WIN) + web_ui->AddMessageHandler(std::make_unique<VersionHandlerWindows>()); +#else + web_ui->AddMessageHandler(std::make_unique<VersionHandler>()); +#endif + +#if !defined(OS_ANDROID) + // Set up the chrome://theme/ source. + content::URLDataSource::Add(profile, std::make_unique<ThemeSource>(profile)); +#endif + + WebUIDataSource::Add(profile, CreateVersionUIDataSource()); +} + +VersionUI::~VersionUI() {} + +// static +void VersionUI::AddVersionDetailStrings(content::WebUIDataSource* html_source) { html_source->AddLocalizedString(version_ui::kOfficial, version_info::IsOfficialBuild() ? IDS_VERSION_UI_OFFICIAL @@ -150,35 +185,4 @@ #endif // defined(OS_WIN) html_source->AddString(version_ui::kSanitizer, version_info::GetSanitizerList()); - - html_source->SetJsonPath("strings.js"); - html_source->AddResourcePath(version_ui::kVersionJS, IDR_VERSION_UI_JS); - html_source->AddResourcePath(version_ui::kAboutVersionCSS, - IDR_VERSION_UI_CSS); - html_source->SetDefaultResource(IDR_VERSION_UI_HTML); - return html_source; } - -} // namespace - -VersionUI::VersionUI(content::WebUI* web_ui) - : content::WebUIController(web_ui) { - Profile* profile = Profile::FromWebUI(web_ui); - -#if defined(OS_CHROMEOS) - web_ui->AddMessageHandler(std::make_unique<VersionHandlerChromeOS>()); -#elif defined(OS_WIN) - web_ui->AddMessageHandler(std::make_unique<VersionHandlerWindows>()); -#else - web_ui->AddMessageHandler(std::make_unique<VersionHandler>()); -#endif - -#if !defined(OS_ANDROID) - // Set up the chrome://theme/ source. - content::URLDataSource::Add(profile, std::make_unique<ThemeSource>(profile)); -#endif - - WebUIDataSource::Add(profile, CreateVersionUIDataSource()); -} - -VersionUI::~VersionUI() {}
diff --git a/chrome/browser/ui/webui/version_ui.h b/chrome/browser/ui/webui/version_ui.h index 9de2301..1b0cc1a 100644 --- a/chrome/browser/ui/webui/version_ui.h +++ b/chrome/browser/ui/webui/version_ui.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "content/public/browser/web_ui_controller.h" +#include "content/public/browser/web_ui_data_source.h" // The WebUI handler for chrome://version. class VersionUI : public content::WebUIController { @@ -14,6 +15,10 @@ explicit VersionUI(content::WebUI* web_ui); ~VersionUI() override; + // Loads a data source with many named details comprising version info. + // The keys are from version_ui_constants. + static void AddVersionDetailStrings(content::WebUIDataSource* html_source); + private: DISALLOW_COPY_AND_ASSIGN(VersionUI); };
diff --git a/chrome/browser/ui/webui/welcome/nux/DEPS b/chrome/browser/ui/webui/welcome/DEPS similarity index 100% rename from chrome/browser/ui/webui/welcome/nux/DEPS rename to chrome/browser/ui/webui/welcome/DEPS
diff --git a/chrome/browser/ui/webui/welcome/nux/bookmark_handler.cc b/chrome/browser/ui/webui/welcome/bookmark_handler.cc similarity index 95% rename from chrome/browser/ui/webui/welcome/nux/bookmark_handler.cc rename to chrome/browser/ui/webui/welcome/bookmark_handler.cc index e09ec04f..1899ba5 100644 --- a/chrome/browser/ui/webui/welcome/nux/bookmark_handler.cc +++ b/chrome/browser/ui/webui/welcome/bookmark_handler.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/welcome/nux/bookmark_handler.h" +#include "chrome/browser/ui/webui/welcome/bookmark_handler.h" #include "base/bind.h" #include "chrome/grit/browser_resources.h"
diff --git a/chrome/browser/ui/webui/welcome/nux/bookmark_handler.h b/chrome/browser/ui/webui/welcome/bookmark_handler.h similarity index 80% rename from chrome/browser/ui/webui/welcome/nux/bookmark_handler.h rename to chrome/browser/ui/webui/welcome/bookmark_handler.h index b9240c9..927d252 100644 --- a/chrome/browser/ui/webui/welcome/nux/bookmark_handler.h +++ b/chrome/browser/ui/webui/welcome/bookmark_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_BOOKMARK_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_BOOKMARK_HANDLER_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_HANDLER_H_ #include "base/macros.h" #include "base/values.h" @@ -34,4 +34,4 @@ } // namespace nux -#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_BOOKMARK_HANDLER_H_ +#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_HANDLER_H_
diff --git a/chrome/browser/ui/webui/welcome/nux/bookmark_item.cc b/chrome/browser/ui/webui/welcome/bookmark_item.cc similarity index 94% rename from chrome/browser/ui/webui/welcome/nux/bookmark_item.cc rename to chrome/browser/ui/webui/welcome/bookmark_item.cc index ba59a85..3cebd7c 100644 --- a/chrome/browser/ui/webui/welcome/nux/bookmark_item.cc +++ b/chrome/browser/ui/webui/welcome/bookmark_item.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/welcome/nux/bookmark_item.h" +#include "chrome/browser/ui/webui/welcome/bookmark_item.h" #include "base/strings/string16.h" #include "base/values.h"
diff --git a/chrome/browser/ui/webui/welcome/nux/bookmark_item.h b/chrome/browser/ui/webui/welcome/bookmark_item.h similarity index 79% rename from chrome/browser/ui/webui/welcome/nux/bookmark_item.h rename to chrome/browser/ui/webui/welcome/bookmark_item.h index 838735a9..e7bfa51c 100644 --- a/chrome/browser/ui/webui/welcome/nux/bookmark_item.h +++ b/chrome/browser/ui/webui/welcome/bookmark_item.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_BOOKMARK_ITEM_H_ -#define CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_BOOKMARK_ITEM_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_ITEM_H_ +#define CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_ITEM_H_ #include <stddef.h> #include <string> @@ -31,4 +31,4 @@ } // namespace nux -#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_BOOKMARK_ITEM_H_ +#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_ITEM_H_
diff --git a/chrome/browser/ui/webui/welcome/nux/constants.cc b/chrome/browser/ui/webui/welcome/constants.cc similarity index 94% rename from chrome/browser/ui/webui/welcome/nux/constants.cc rename to chrome/browser/ui/webui/welcome/constants.cc index ac31489..d6e5606 100644 --- a/chrome/browser/ui/webui/welcome/nux/constants.cc +++ b/chrome/browser/ui/webui/welcome/constants.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/welcome/nux/constants.h" +#include "chrome/browser/ui/webui/welcome/constants.h" #include "base/feature_list.h"
diff --git a/chrome/browser/ui/webui/welcome/nux/constants.h b/chrome/browser/ui/webui/welcome/constants.h similarity index 79% rename from chrome/browser/ui/webui/welcome/nux/constants.h rename to chrome/browser/ui/webui/welcome/constants.h index de397b2..d0e4b96 100644 --- a/chrome/browser/ui/webui/welcome/nux/constants.h +++ b/chrome/browser/ui/webui/welcome/constants.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_CONSTANTS_H_ -#define CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_CONSTANTS_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_CONSTANTS_H_ +#define CHROME_BROWSER_UI_WEBUI_WELCOME_CONSTANTS_H_ #include <string> #include "base/metrics/field_trial_params.h" @@ -25,4 +25,4 @@ } // namespace nux -#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_CONSTANTS_H_ +#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_CONSTANTS_H_
diff --git a/chrome/browser/ui/webui/welcome/nux/google_apps_handler.cc b/chrome/browser/ui/webui/welcome/google_apps_handler.cc similarity index 96% rename from chrome/browser/ui/webui/welcome/nux/google_apps_handler.cc rename to chrome/browser/ui/webui/welcome/google_apps_handler.cc index b76a818..74e30884a 100644 --- a/chrome/browser/ui/webui/welcome/nux/google_apps_handler.cc +++ b/chrome/browser/ui/webui/welcome/google_apps_handler.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/welcome/nux/google_apps_handler.h" +#include "chrome/browser/ui/webui/welcome/google_apps_handler.h" #include "base/bind.h" #include "base/metrics/field_trial_params.h" @@ -10,7 +10,7 @@ #include "base/stl_util.h" #include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/welcome/nux/bookmark_item.h" +#include "chrome/browser/ui/webui/welcome/bookmark_item.h" #include "chrome/browser/ui/webui/welcome/nux_helper.h" #include "chrome/grit/chrome_unscaled_resources.h" #include "chrome/grit/generated_resources.h" @@ -109,7 +109,7 @@ int appId; args->GetInteger(0, &appId); - const BookmarkItem* selectedApp = NULL; + const BookmarkItem* selectedApp = nullptr; for (const auto& google_app : google_apps_) { if (google_app.id == appId) { selectedApp = &google_app;
diff --git a/chrome/browser/ui/webui/welcome/nux/google_apps_handler.h b/chrome/browser/ui/webui/welcome/google_apps_handler.h similarity index 79% rename from chrome/browser/ui/webui/welcome/nux/google_apps_handler.h rename to chrome/browser/ui/webui/welcome/google_apps_handler.h index f35e22d4..caaaef1 100644 --- a/chrome/browser/ui/webui/welcome/nux/google_apps_handler.h +++ b/chrome/browser/ui/webui/welcome/google_apps_handler.h
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_GOOGLE_APPS_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_GOOGLE_APPS_HANDLER_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_GOOGLE_APPS_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_WELCOME_GOOGLE_APPS_HANDLER_H_ #include <vector> #include "base/macros.h" #include "base/values.h" -#include "chrome/browser/ui/webui/welcome/nux/bookmark_item.h" +#include "chrome/browser/ui/webui/welcome/bookmark_item.h" #include "content/public/browser/web_ui_message_handler.h" namespace nux { @@ -45,4 +45,4 @@ } // namespace nux -#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_GOOGLE_APPS_HANDLER_H_ +#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_GOOGLE_APPS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/welcome/nux/ntp_background_fetcher.cc b/chrome/browser/ui/webui/welcome/ntp_background_fetcher.cc similarity index 97% rename from chrome/browser/ui/webui/welcome/nux/ntp_background_fetcher.cc rename to chrome/browser/ui/webui/welcome/ntp_background_fetcher.cc index 658de1d..161936419 100644 --- a/chrome/browser/ui/webui/welcome/nux/ntp_background_fetcher.cc +++ b/chrome/browser/ui/webui/welcome/ntp_background_fetcher.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/welcome/nux/ntp_background_fetcher.h" +#include "chrome/browser/ui/webui/welcome/ntp_background_fetcher.h" #include <utility>
diff --git a/chrome/browser/ui/webui/welcome/nux/ntp_background_fetcher.h b/chrome/browser/ui/webui/welcome/ntp_background_fetcher.h similarity index 79% rename from chrome/browser/ui/webui/welcome/nux/ntp_background_fetcher.h rename to chrome/browser/ui/webui/welcome/ntp_background_fetcher.h index 1e4892a..b9b8602 100644 --- a/chrome/browser/ui/webui/welcome/nux/ntp_background_fetcher.h +++ b/chrome/browser/ui/webui/welcome/ntp_background_fetcher.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_NTP_BACKGROUND_FETCHER_H_ -#define CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_NTP_BACKGROUND_FETCHER_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_FETCHER_H_ +#define CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_FETCHER_H_ #include <memory> #include <string> @@ -37,4 +37,4 @@ } // namespace nux -#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_NTP_BACKGROUND_FETCHER_H_ +#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_FETCHER_H_
diff --git a/chrome/browser/ui/webui/welcome/nux/ntp_background_handler.cc b/chrome/browser/ui/webui/welcome/ntp_background_handler.cc similarity index 92% rename from chrome/browser/ui/webui/welcome/nux/ntp_background_handler.cc rename to chrome/browser/ui/webui/welcome/ntp_background_handler.cc index bf02622..8109841c 100644 --- a/chrome/browser/ui/webui/welcome/nux/ntp_background_handler.cc +++ b/chrome/browser/ui/webui/welcome/ntp_background_handler.cc
@@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/welcome/nux/ntp_background_handler.h" +#include "chrome/browser/ui/webui/welcome/ntp_background_handler.h" #include <memory> #include <utility> #include "base/bind.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/background/onboarding_ntp_backgrounds.h" @@ -73,7 +74,7 @@ element->SetString("title", l10n_util::GetStringUTF8( IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_EARTH_TITLE)); - element->SetString("imageUrl", kUrlPrefix + std::to_string(id)); + element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id)); element->SetString("thumbnailClass", "earth"); list_value.Append(std::move(element)); @@ -83,7 +84,7 @@ element->SetString( "title", l10n_util::GetStringUTF8( IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_CITYSCAPE_TITLE)); - element->SetString("imageUrl", kUrlPrefix + std::to_string(id)); + element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id)); element->SetString("thumbnailClass", "cityscape"); list_value.Append(std::move(element)); @@ -93,7 +94,7 @@ element->SetString( "title", l10n_util::GetStringUTF8( IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_LANDSCAPE_TITLE)); - element->SetString("imageUrl", kUrlPrefix + std::to_string(id)); + element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id)); element->SetString("thumbnailClass", "landscape"); list_value.Append(std::move(element)); @@ -103,7 +104,7 @@ element->SetString("title", l10n_util::GetStringUTF8( IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_ART_TITLE)); - element->SetString("imageUrl", kUrlPrefix + std::to_string(id)); + element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id)); element->SetString("thumbnailClass", "art"); list_value.Append(std::move(element)); @@ -114,7 +115,7 @@ "title", l10n_util::GetStringUTF8( IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_GEOMETRIC_SHAPES_TITLE)); - element->SetString("imageUrl", kUrlPrefix + std::to_string(id)); + element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id)); element->SetString("thumbnailClass", "geometric-shapes"); list_value.Append(std::move(element));
diff --git a/chrome/browser/ui/webui/welcome/nux/ntp_background_handler.h b/chrome/browser/ui/webui/welcome/ntp_background_handler.h similarity index 77% rename from chrome/browser/ui/webui/welcome/nux/ntp_background_handler.h rename to chrome/browser/ui/webui/welcome/ntp_background_handler.h index d2c23fa..cb863dcb 100644 --- a/chrome/browser/ui/webui/welcome/nux/ntp_background_handler.h +++ b/chrome/browser/ui/webui/welcome/ntp_background_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_NTP_BACKGROUND_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_NTP_BACKGROUND_HANDLER_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_HANDLER_H_ #include "content/public/browser/web_ui_message_handler.h" @@ -28,4 +28,4 @@ } // namespace nux -#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_NTP_BACKGROUND_HANDLER_H_ +#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_HANDLER_H_
diff --git a/chrome/browser/ui/webui/welcome/nux/README b/chrome/browser/ui/webui/welcome/nux/README deleted file mode 100644 index b2d6888..0000000 --- a/chrome/browser/ui/webui/welcome/nux/README +++ /dev/null
@@ -1,3 +0,0 @@ -New User Experience Experiment (NUX). Code here will prompt new users to go -through an onboarding experience to customize their new browser install to -their common usages. \ No newline at end of file
diff --git a/chrome/browser/ui/webui/welcome/nux_helper.cc b/chrome/browser/ui/webui/welcome/nux_helper.cc index 34c8a24..ed36410 100644 --- a/chrome/browser/ui/webui/welcome/nux_helper.cc +++ b/chrome/browser/ui/webui/welcome/nux_helper.cc
@@ -19,7 +19,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search/ntp_features.h" #include "chrome/browser/search/search.h" -#include "chrome/browser/ui/webui/welcome/nux/constants.h" +#include "chrome/browser/ui/webui/welcome/constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "components/policy/core/common/policy_map.h"
diff --git a/chrome/browser/ui/webui/welcome/nux/set_as_default_handler.cc b/chrome/browser/ui/webui/welcome/set_as_default_handler.cc similarity index 85% rename from chrome/browser/ui/webui/welcome/nux/set_as_default_handler.cc rename to chrome/browser/ui/webui/welcome/set_as_default_handler.cc index 3d4f3387..9166e53 100644 --- a/chrome/browser/ui/webui/welcome/nux/set_as_default_handler.cc +++ b/chrome/browser/ui/webui/welcome/set_as_default_handler.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/welcome/nux/set_as_default_handler.h" +#include "chrome/browser/ui/webui/welcome/set_as_default_handler.h" namespace nux {
diff --git a/chrome/browser/ui/webui/welcome/nux/set_as_default_handler.h b/chrome/browser/ui/webui/welcome/set_as_default_handler.h similarity index 72% rename from chrome/browser/ui/webui/welcome/nux/set_as_default_handler.h rename to chrome/browser/ui/webui/welcome/set_as_default_handler.h index 5f70e699..1d89f292 100644 --- a/chrome/browser/ui/webui/welcome/nux/set_as_default_handler.h +++ b/chrome/browser/ui/webui/welcome/set_as_default_handler.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_SET_AS_DEFAULT_HANDLER_H_ -#define CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_SET_AS_DEFAULT_HANDLER_H_ +#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_SET_AS_DEFAULT_HANDLER_H_ +#define CHROME_BROWSER_UI_WEBUI_WELCOME_SET_AS_DEFAULT_HANDLER_H_ #include "base/macros.h" #include "chrome/browser/ui/webui/settings/settings_default_browser_handler.h" @@ -23,4 +23,4 @@ } // namespace nux -#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NUX_SET_AS_DEFAULT_HANDLER_H_ +#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_SET_AS_DEFAULT_HANDLER_H_
diff --git a/chrome/browser/ui/webui/welcome/welcome_ui.cc b/chrome/browser/ui/webui/welcome/welcome_ui.cc index 4ae52e2..460e976 100644 --- a/chrome/browser/ui/webui/welcome/welcome_ui.cc +++ b/chrome/browser/ui/webui/welcome/welcome_ui.cc
@@ -8,12 +8,12 @@ #include "base/strings/string_number_conversions.h" #include "chrome/browser/signin/account_consistency_mode_manager.h" #include "chrome/browser/ui/webui/localized_string.h" -#include "chrome/browser/ui/webui/welcome/nux/bookmark_handler.h" -#include "chrome/browser/ui/webui/welcome/nux/constants.h" -#include "chrome/browser/ui/webui/welcome/nux/google_apps_handler.h" -#include "chrome/browser/ui/webui/welcome/nux/ntp_background_handler.h" -#include "chrome/browser/ui/webui/welcome/nux/set_as_default_handler.h" +#include "chrome/browser/ui/webui/welcome/bookmark_handler.h" +#include "chrome/browser/ui/webui/welcome/constants.h" +#include "chrome/browser/ui/webui/welcome/google_apps_handler.h" +#include "chrome/browser/ui/webui/welcome/ntp_background_handler.h" #include "chrome/browser/ui/webui/welcome/nux_helper.h" +#include "chrome/browser/ui/webui/welcome/set_as_default_handler.h" #include "chrome/browser/ui/webui/welcome/welcome_handler.h" #include "chrome/common/pref_names.h" #include "chrome/grit/chrome_unscaled_resources.h"
diff --git a/chrome/browser/ui/webui/welcome/welcome_ui.h b/chrome/browser/ui/webui/welcome/welcome_ui.h index ed54ca23..376a447 100644 --- a/chrome/browser/ui/webui/welcome/welcome_ui.h +++ b/chrome/browser/ui/webui/welcome/welcome_ui.h
@@ -10,7 +10,7 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/welcome/nux/ntp_background_fetcher.h" +#include "chrome/browser/ui/webui/welcome/ntp_background_fetcher.h" #include "content/public/browser/web_ui_controller.h" #include "content/public/browser/web_ui_data_source.h" #include "url/gurl.h"
diff --git a/chrome/browser/vr/service/xr_device_impl.cc b/chrome/browser/vr/service/xr_device_impl.cc index 5a464fd..64e4c74 100644 --- a/chrome/browser/vr/service/xr_device_impl.cc +++ b/chrome/browser/vr/service/xr_device_impl.cc
@@ -307,10 +307,20 @@ "id", session_runtime_id); auto runtime_options = GetRuntimeOptions(options.get()); - runtime_options->render_process_id = - render_frame_host_ ? render_frame_host_->GetProcess()->GetID() : -1; - runtime_options->render_frame_id = - render_frame_host_ ? render_frame_host_->GetRoutingID() : -1; + +#if defined(OS_ANDROID) && BUILDFLAG(ENABLE_ARCORE) + if (session_runtime_id == device::mojom::XRDeviceId::ARCORE_DEVICE_ID) { + if (!render_frame_host_) { + std::move(callback).Run( + device::mojom::RequestSessionResult::NewFailureReason( + device::mojom::RequestSessionError::INVALID_CLIENT)); + return; + } + runtime_options->render_process_id = + render_frame_host_->GetProcess()->GetID(); + runtime_options->render_frame_id = render_frame_host_->GetRoutingID(); + } +#endif if (runtime_options->immersive) { GetSessionMetricsHelper()->ReportRequestPresent(*runtime_options);
diff --git a/chrome/browser/vr/test/webxr_vr_browser_test.cc b/chrome/browser/vr/test/webxr_vr_browser_test.cc index d0d957558..863b159 100644 --- a/chrome/browser/vr/test/webxr_vr_browser_test.cc +++ b/chrome/browser/vr/test/webxr_vr_browser_test.cc
@@ -37,6 +37,15 @@ PollJavaScriptBooleanOrFail( "sessionInfos[sessionTypes.IMMERSIVE].currentSession != null", kPollTimeoutLong, web_contents); + +#if defined(OS_WIN) + // For WMR, creating a session may take foreground from us, and Windows may + // not return it when the session terminates. This means subsequent requests + // to enter an immersive session may fail. The fix for testing is to call + // SetForegroundWindow manually. In real code, we'll have foreground if there + // was a user gesture to enter VR. + SetForegroundWindow(hwnd_); +#endif } void WebXrVrBrowserTestBase::EndSession(content::WebContents* web_contents) {
diff --git a/chrome/browser/vr/test/xr_browser_test.cc b/chrome/browser/vr/test/xr_browser_test.cc index 54ddc20e..2cac9c3 100644 --- a/chrome/browser/vr/test/xr_browser_test.cc +++ b/chrome/browser/vr/test/xr_browser_test.cc
@@ -220,6 +220,13 @@ kPollTimeoutMedium, GetCurrentWebContents())) << "Timed out waiting for JavaScript test initialization."; + +#if defined(OS_WIN) + // Now that the browser is opened and has focus, keep track of this window so + // that we can restore the proper focus after entering each session. This is + // required for WMR tests that create multiple sessions to work properly. + hwnd_ = GetForegroundWindow(); +#endif } void XrBrowserTestBase::RunJavaScriptOrFail(
diff --git a/chrome/browser/vr/test/xr_browser_test.h b/chrome/browser/vr/test/xr_browser_test.h index 5b4b89b..ad29ac4c 100644 --- a/chrome/browser/vr/test/xr_browser_test.h +++ b/chrome/browser/vr/test/xr_browser_test.h
@@ -12,6 +12,7 @@ #include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "base/time/time.h" +#include "build/build_config.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/vr/test/conditional_skipping.h" #include "chrome/common/chrome_features.h" @@ -23,6 +24,10 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "url/gurl.h" +#if defined(OS_WIN) +#include <windows.h> +#endif + namespace vr { // Base browser test class for running XR-related tests. @@ -228,6 +233,10 @@ std::vector<XrTestRequirement> runtime_requirements_; std::unordered_set<std::string> ignored_requirements_; +#if defined(OS_WIN) + HWND hwnd_; +#endif + private: void LogJavaScriptFailure(); Browser* browser_ = nullptr;
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc index a26e26a..f488a4e 100644 --- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc +++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -34,18 +34,14 @@ base::flat_set<AuthenticatorTransport> candidate_transports( transport_availability.available_transports); - // As an exception, we can tell in advance if using Touch Id will succeed. If - // yes, always auto-select that transport over all other considerations for - // GetAssertion operations; and de-select it if it will not work. + // For GetAssertion requests, auto advance to Touch ID if the authenticator + // has a matching credential for the (possibly empty) allow list. if (transport_availability.request_type == device::FidoRequestHandlerBase::RequestType::kGetAssertion && - !transport_availability.has_empty_allow_list && base::Contains(candidate_transports, - device::FidoTransportProtocol::kInternal)) { - // For GetAssertion requests, auto advance to Touch ID if the keychain - // contains one of the allowedCredentials. - if (transport_availability.has_recognized_mac_touch_id_credential) - return device::FidoTransportProtocol::kInternal; + device::FidoTransportProtocol::kInternal) && + transport_availability.has_recognized_mac_touch_id_credential) { + return device::FidoTransportProtocol::kInternal; } // If caBLE is listed as one of the allowed transports, it indicates that the
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc index 76a6bc64..8075a59 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -28,9 +28,11 @@ #include "content/public/browser/browser_context.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" +#include "device/fido/features.h" #include "device/fido/fido_authenticator.h" #if defined(OS_MACOSX) +#include "device/fido/mac/authenticator.h" #include "device/fido/mac/credential_metadata.h" #endif @@ -304,19 +306,11 @@ } // namespace // static -content::AuthenticatorRequestClientDelegate::TouchIdAuthenticatorConfig +ChromeAuthenticatorRequestDelegate::TouchIdAuthenticatorConfig ChromeAuthenticatorRequestDelegate::TouchIdAuthenticatorConfigForProfile( Profile* profile) { - return content::AuthenticatorRequestClientDelegate:: - TouchIdAuthenticatorConfig{kTouchIdKeychainAccessGroup, - TouchIdMetadataSecret(profile)}; -} - -base::Optional< - content::AuthenticatorRequestClientDelegate::TouchIdAuthenticatorConfig> -ChromeAuthenticatorRequestDelegate::GetTouchIdAuthenticatorConfig() { - return TouchIdAuthenticatorConfigForProfile( - Profile::FromBrowserContext(browser_context())); + return TouchIdAuthenticatorConfig{kTouchIdKeychainAccessGroup, + TouchIdMetadataSecret(profile)}; } #endif @@ -357,15 +351,39 @@ return !disable_ui_; } -bool ChromeAuthenticatorRequestDelegate::ShouldDisablePlatformAuthenticators() { +bool ChromeAuthenticatorRequestDelegate:: + IsUserVerifyingPlatformAuthenticatorAvailable() { #if defined(OS_MACOSX) // Touch ID is available in Incognito, but not in Guest mode. - return Profile::FromBrowserContext(browser_context())->IsGuestSession(); -#else // Windows, Android - return browser_context()->IsOffTheRecord(); -#endif + if (Profile::FromBrowserContext(browser_context())->IsGuestSession()) + return false; + + return device::fido::mac::TouchIdAuthenticator::IsAvailable( + TouchIdAuthenticatorConfigForProfile( + Profile::FromBrowserContext(browser_context()))); +#elif defined(OS_WIN) + if (browser_context()->IsOffTheRecord()) + return false; + + return base::FeatureList::IsEnabled(device::kWebAuthUseNativeWinApi) && + device::WinWebAuthnApiAuthenticator:: + IsUserVerifyingPlatformAuthenticatorAvailable(); +#else + return false; +#endif // defined(OS_MACOSX) || defined(OS_WIN) } +#if defined(OS_MACOSX) +base::Optional<ChromeAuthenticatorRequestDelegate::TouchIdAuthenticatorConfig> +ChromeAuthenticatorRequestDelegate::GetTouchIdAuthenticatorConfig() { + if (!IsUserVerifyingPlatformAuthenticatorAvailable()) + return base::nullopt; + + return TouchIdAuthenticatorConfigForProfile( + Profile::FromBrowserContext(browser_context())); +} +#endif // defined(OS_MACOSX) + void ChromeAuthenticatorRequestDelegate::OnTransportAvailabilityEnumerated( device::FidoRequestHandlerBase::TransportAvailabilityInfo data) { #if !defined(OS_ANDROID)
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h index a5635db..9af9b98 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -87,7 +87,7 @@ device::FidoTransportProtocol transport) override; void DisableUI() override; bool IsWebAuthnUIEnabled() override; - bool ShouldDisablePlatformAuthenticators() override; + bool IsUserVerifyingPlatformAuthenticatorAvailable() override; // device::FidoRequestHandlerBase::Observer: void OnTransportAvailabilityEnumerated(
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc index 2b130e2..1260be5 100644 --- a/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc +++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate_unittest.cc
@@ -8,9 +8,11 @@ #include "build/build_config.h" #include "chrome/test/base/chrome_render_view_host_test_harness.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/fido_device_authenticator.h" +#include "device/fido/fido_discovery_factory.h" #include "device/fido/test_callback_receiver.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,10 +20,21 @@ #include "device/fido/win/authenticator.h" #include "device/fido/win/fake_webauthn_api.h" #include "third_party/microsoft_webauthn/webauthn.h" -#endif +#endif // defined(OS_WIN) + +#if defined(OS_MACOSX) +#include "device/fido/mac/authenticator_config.h" +#include "device/fido/mac/scoped_touch_id_test_environment.h" +#endif // defined(OS_MACOSX) class ChromeAuthenticatorRequestDelegateTest - : public ChromeRenderViewHostTestHarness {}; + : public ChromeRenderViewHostTestHarness { + protected: +#if defined(OS_MACOSX) + API_AVAILABLE(macos(10.12.2)) + device::fido::mac::ScopedTouchIdTestEnvironment touch_id_test_environment_; +#endif // defined(OS_MACOSX) +}; static constexpr char kRelyingPartyID[] = "example.com"; @@ -76,10 +89,7 @@ #if defined(OS_MACOSX) std::string TouchIdMetadataSecret( ChromeAuthenticatorRequestDelegate* delegate) { - base::Optional< - content::AuthenticatorRequestClientDelegate::TouchIdAuthenticatorConfig> - config = delegate->GetTouchIdAuthenticatorConfig(); - return config->metadata_secret; + return delegate->GetTouchIdAuthenticatorConfig()->metadata_secret; } TEST_F(ChromeAuthenticatorRequestDelegateTest, TouchIdMetadataSecret) { @@ -114,9 +124,48 @@ // Ensure this second secret is actually valid. EXPECT_EQ(32u, TouchIdMetadataSecret(&delegate2).size()); } -#endif + +TEST_F(ChromeAuthenticatorRequestDelegateTest, IsUVPAA) { + if (__builtin_available(macOS 10.12.2, *)) { + for (const bool touch_id_available : {false, true}) { + SCOPED_TRACE(::testing::Message() + << "touch_id_available=" << touch_id_available); + touch_id_test_environment_.SetTouchIdAvailable(touch_id_available); + + std::unique_ptr<content::AuthenticatorRequestClientDelegate> delegate = + std::make_unique<ChromeAuthenticatorRequestDelegate>(main_rfh(), + kRelyingPartyID); + EXPECT_EQ(touch_id_available, + delegate->IsUserVerifyingPlatformAuthenticatorAvailable()); + } + } +} + +#endif // defined(OS_MACOSX) #if defined(OS_WIN) +TEST_F(ChromeAuthenticatorRequestDelegateTest, WinIsUVPAA) { + device::ScopedFakeWinWebAuthnApi win_webauthn_api = + device::ScopedFakeWinWebAuthnApi::MakeUnavailable(); + + for (const bool enable_win_webauthn_api : {false, true}) { + SCOPED_TRACE(enable_win_webauthn_api ? "enable_win_webauthn_api" + : "!enable_win_webauthn_api"); + for (const bool is_uvpaa : {false, true}) { + SCOPED_TRACE(is_uvpaa ? "is_uvpaa" : "!is_uvpaa"); + + win_webauthn_api.set_available(enable_win_webauthn_api); + win_webauthn_api.set_is_uvpaa(is_uvpaa); + + std::unique_ptr<content::AuthenticatorRequestClientDelegate> delegate = + std::make_unique<ChromeAuthenticatorRequestDelegate>(main_rfh(), + kRelyingPartyID); + EXPECT_EQ(enable_win_webauthn_api && is_uvpaa, + delegate->IsUserVerifyingPlatformAuthenticatorAvailable()); + } + } +} + // 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/chrome_cleaner/components/recovery_component_unittest.cc b/chrome/chrome_cleaner/components/recovery_component_unittest.cc index 71ff18a..d4a3412 100644 --- a/chrome/chrome_cleaner/components/recovery_component_unittest.cc +++ b/chrome/chrome_cleaner/components/recovery_component_unittest.cc
@@ -11,7 +11,7 @@ #include "base/files/file.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" +#include "base/test/scoped_task_environment.h" #include "base/test/test_simple_task_runner.h" #include "chrome/chrome_cleaner/http/mock_http_agent_factory.h" #include "chrome/chrome_cleaner/test/test_pup_data.h" @@ -66,8 +66,9 @@ protected: RecoveryComponentTest() : task_runner_(new base::TestSimpleTaskRunner) {} - // A message loop is needed for the current task runner to be available. - base::MessageLoopForUI ui_message_loop_; + // Needed for the current task runner to be available. + base::test::ScopedTaskEnvironment scoped_task_environment_{ + base::test::ScopedTaskEnvironment::MainThreadType::UI}; // The recover component under test. This declaration must be after the // |ui_message_loop_| because the |RecoveryComponent| constructor needs
diff --git a/chrome/chrome_cleaner/ui/BUILD.gn b/chrome/chrome_cleaner/ui/BUILD.gn index 46cb9af..3cb30dd 100644 --- a/chrome/chrome_cleaner/ui/BUILD.gn +++ b/chrome/chrome_cleaner/ui/BUILD.gn
@@ -38,6 +38,7 @@ deps = [ ":cleaner_ui", "//base", + "//base/test:test_support", "//chrome/chrome_cleaner/constants:uws_id", "//chrome/chrome_cleaner/ipc:mock_chrome_prompt_ipc", "//chrome/chrome_cleaner/test:test_pup_data",
diff --git a/chrome/chrome_cleaner/ui/chrome_proxy_main_dialog_unittest.cc b/chrome/chrome_cleaner/ui/chrome_proxy_main_dialog_unittest.cc index d3fa1f5..716f4a5 100644 --- a/chrome/chrome_cleaner/ui/chrome_proxy_main_dialog_unittest.cc +++ b/chrome/chrome_cleaner/ui/chrome_proxy_main_dialog_unittest.cc
@@ -9,8 +9,8 @@ #include "base/callback.h" #include "base/files/scoped_temp_dir.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" #include "chrome/chrome_cleaner/ipc/mock_chrome_prompt_ipc.h" #include "chrome/chrome_cleaner/test/test_file_util.h" #include "chrome/chrome_cleaner/test/test_pup_data.h" @@ -48,7 +48,8 @@ } TEST_F(ChromeProxyMainDialogTest, NoPUPsFound) { - base::MessageLoopForUI ui_message_loop_; + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); base::RunLoop run_loop; EXPECT_CALL(delegate_, OnClose()) @@ -93,7 +94,8 @@ prompt_acceptance == PromptAcceptance::ACCEPTED_WITHOUT_LOGS; bool logs_allowed = prompt_acceptance == PromptAcceptance::ACCEPTED_WITH_LOGS; - base::MessageLoopForUI ui_message_loop_; + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); EXPECT_CALL(mock_settings_, set_logs_allowed_in_cleanup_mode(Eq(logs_allowed)))
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index d856e29..1d56a19497 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -543,6 +543,7 @@ ":buildflags", ":version_header", "//base", + "//build:branding_buildflags", "//ppapi/buildflags", ] @@ -598,6 +599,7 @@ ":buildflags", ":chrome_features", ":non_code_constants", + "//build:branding_buildflags", "//content/public/common:result_codes", "//rlz/buildflags", ]
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc index dd163bb..81d60e3 100644 --- a/chrome/common/chrome_constants.cc +++ b/chrome/common/chrome_constants.cc
@@ -4,6 +4,7 @@ #include "chrome/common/chrome_constants.h" +#include "build/branding_buildflags.h" #include "build/build_config.h" #include "chrome/common/chrome_version.h" @@ -13,7 +14,7 @@ #define CHROMIUM_PRODUCT_STRING "Chromium" #if defined(GOOGLE_CHROME_BUILD) #define PRODUCT_STRING "Google Chrome" -#elif defined(CHROMIUM_BUILD) +#elif BUILDFLAG(CHROMIUM_BRANDING) #define PRODUCT_STRING "Chromium" #else #error Unknown branding
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc index b3cff585..4ef4b7e 100644 --- a/chrome/common/chrome_paths.cc +++ b/chrome/common/chrome_paths.cc
@@ -469,8 +469,8 @@ break; } #endif -#if defined(OS_CHROMEOS) || (defined(OS_LINUX) && defined(CHROMIUM_BUILD)) || \ - defined(OS_MACOSX) +#if defined(OS_CHROMEOS) || \ + (defined(OS_LINUX) && BUILDFLAG(CHROMIUM_BRANDING)) || defined(OS_MACOSX) case chrome::DIR_USER_EXTERNAL_EXTENSIONS: { if (!base::PathService::Get(chrome::DIR_USER_DATA, &cur)) return false;
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h index 34e42c5..d592642 100644 --- a/chrome/common/chrome_paths.h +++ b/chrome/common/chrome_paths.h
@@ -5,6 +5,7 @@ #ifndef CHROME_COMMON_CHROME_PATHS_H__ #define CHROME_COMMON_CHROME_PATHS_H__ +#include "build/branding_buildflags.h" #include "build/build_config.h" namespace base { @@ -19,40 +20,40 @@ enum { PATH_START = 1000, - DIR_APP = PATH_START, // Directory where dlls and data reside. - DIR_LOGS, // Directory where logs should be written. - DIR_USER_DATA, // Directory where user data can be written. - DIR_CRASH_DUMPS, // Directory where crash dumps are written. + DIR_APP = PATH_START, // Directory where dlls and data reside. + DIR_LOGS, // Directory where logs should be written. + DIR_USER_DATA, // Directory where user data can be written. + DIR_CRASH_DUMPS, // Directory where crash dumps are written. #if defined(OS_WIN) - DIR_WATCHER_DATA, // Directory where the Chrome watcher stores - // data. - DIR_ROAMING_USER_DATA, // Directory where user data is stored that - // needs to be roamed between computers. + DIR_WATCHER_DATA, // Directory where the Chrome watcher stores + // data. + DIR_ROAMING_USER_DATA, // Directory where user data is stored that + // needs to be roamed between computers. #endif - DIR_RESOURCES, // Directory containing separate file resources - // used by Chrome at runtime. - DIR_INSPECTOR_DEBUG, // Directory where non-bundled and non-minified - // web inspector is located. - DIR_APP_DICTIONARIES, // Directory where the global dictionaries are. - DIR_USER_DOCUMENTS, // Directory for a user's "My Documents". - DIR_USER_MUSIC, // Directory for a user's music. - DIR_USER_PICTURES, // Directory for a user's pictures. - DIR_USER_VIDEOS, // Directory for a user's videos. - DIR_DEFAULT_DOWNLOADS_SAFE, // Directory for a user's - // "My Documents/Downloads", (Windows) or - // "Downloads". (Linux) - DIR_DEFAULT_DOWNLOADS, // Directory for a user's downloads. - DIR_INTERNAL_PLUGINS, // Directory where internal plugins reside. - DIR_COMPONENTS, // Directory where built-in implementations of - // component-updated libraries or data reside. + DIR_RESOURCES, // Directory containing separate file resources + // used by Chrome at runtime. + DIR_INSPECTOR_DEBUG, // Directory where non-bundled and non-minified + // web inspector is located. + DIR_APP_DICTIONARIES, // Directory where the global dictionaries are. + DIR_USER_DOCUMENTS, // Directory for a user's "My Documents". + DIR_USER_MUSIC, // Directory for a user's music. + DIR_USER_PICTURES, // Directory for a user's pictures. + DIR_USER_VIDEOS, // Directory for a user's videos. + DIR_DEFAULT_DOWNLOADS_SAFE, // Directory for a user's + // "My Documents/Downloads", (Windows) or + // "Downloads". (Linux) + DIR_DEFAULT_DOWNLOADS, // Directory for a user's downloads. + DIR_INTERNAL_PLUGINS, // Directory where internal plugins reside. + DIR_COMPONENTS, // Directory where built-in implementations of + // component-updated libraries or data reside. #if defined(OS_POSIX) && !defined(OS_MACOSX) - DIR_POLICY_FILES, // Directory for system-wide read-only - // policy files that allow sys-admins - // to set policies for chrome. This directory - // contains subdirectories. + DIR_POLICY_FILES, // Directory for system-wide read-only + // policy files that allow sys-admins + // to set policies for chrome. This directory + // contains subdirectories. #endif -#if defined(OS_CHROMEOS) || (defined(OS_LINUX) && defined(CHROMIUM_BUILD)) || \ - defined(OS_MACOSX) +#if defined(OS_CHROMEOS) || \ + (defined(OS_LINUX) && BUILDFLAG(CHROMIUM_BRANDING)) || defined(OS_MACOSX) DIR_USER_EXTERNAL_EXTENSIONS, // Directory for per-user external extensions // on Chrome Mac and Chromium Linux. // On Chrome OS, this path is used for OEM @@ -66,39 +67,39 @@ // describe extensions which are to be // installed when chrome is run. #endif - DIR_EXTERNAL_EXTENSIONS, // Directory where installer places .crx files. + DIR_EXTERNAL_EXTENSIONS, // Directory where installer places .crx files. - DIR_DEFAULT_APPS, // Directory where installer places .crx files - // to be installed when chrome is first run. - DIR_PEPPER_FLASH_PLUGIN, // Directory to the bundled Pepper Flash plugin, - // containing the plugin and the manifest. + DIR_DEFAULT_APPS, // Directory where installer places .crx files + // to be installed when chrome is first run. + DIR_PEPPER_FLASH_PLUGIN, // Directory to the bundled Pepper Flash plugin, + // containing the plugin and the manifest. DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN, // Base directory of the Pepper // Flash plugins downloaded by the // component updater. - FILE_RESOURCE_MODULE, // Full path and filename of the module that - // contains embedded resources (version, - // strings, images, etc.). - FILE_LOCAL_STATE, // Path and filename to the file in which - // machine/installation-specific state is saved. - FILE_RECORDED_SCRIPT, // Full path to the script.log file that - // contains recorded browser events for - // playback. - FILE_PEPPER_FLASH_PLUGIN, // Full path to the bundled Pepper Flash plugin - // file. + FILE_RESOURCE_MODULE, // Full path and filename of the module that + // contains embedded resources (version, + // strings, images, etc.). + FILE_LOCAL_STATE, // Path and filename to the file in which + // machine/installation-specific state is saved. + FILE_RECORDED_SCRIPT, // Full path to the script.log file that + // contains recorded browser events for + // playback. + FILE_PEPPER_FLASH_PLUGIN, // Full path to the bundled Pepper Flash plugin + // file. FILE_PEPPER_FLASH_SYSTEM_PLUGIN, // Full path to the system version of the // Pepper Flash plugin, downloadable from // Adobe website. Querying this path might // succeed no matter the file exists or not. - DIR_PNACL_BASE, // Full path to the base dir for PNaCl. - DIR_PNACL_COMPONENT, // Full path to the latest PNaCl version - // (subdir of DIR_PNACL_BASE). - FILE_WIDEVINE_CDM, // Full path to the Widevine CDM. - FILE_RESOURCES_PACK, // Full path to the .pak file containing - // binary data (e.g., html files and images - // used by internal pages). + DIR_PNACL_BASE, // Full path to the base dir for PNaCl. + DIR_PNACL_COMPONENT, // Full path to the latest PNaCl version + // (subdir of DIR_PNACL_BASE). + FILE_WIDEVINE_CDM, // Full path to the Widevine CDM. + FILE_RESOURCES_PACK, // Full path to the .pak file containing + // binary data (e.g., html files and images + // used by internal pages). #if defined(OS_CHROMEOS) - DIR_CHROMEOS_WALLPAPERS, // Directory where downloaded chromeos - // wallpapers reside. + DIR_CHROMEOS_WALLPAPERS, // Directory where downloaded chromeos + // wallpapers reside. DIR_CHROMEOS_WALLPAPER_THUMBNAILS, // Directory where downloaded chromeos // wallpaper thumbnails reside. DIR_CHROMEOS_CUSTOM_WALLPAPERS, // Directory where custom wallpapers @@ -108,23 +109,23 @@ // supervised user whitelists are // installed. #if defined(OS_LINUX) || defined(OS_MACOSX) - DIR_NATIVE_MESSAGING, // System directory where native messaging host - // manifest files are stored. - DIR_USER_NATIVE_MESSAGING, // Directory with Native Messaging Hosts - // installed per-user. + DIR_NATIVE_MESSAGING, // System directory where native messaging host + // manifest files are stored. + DIR_USER_NATIVE_MESSAGING, // Directory with Native Messaging Hosts + // installed per-user. #endif #if !defined(OS_ANDROID) - DIR_GLOBAL_GCM_STORE, // Directory where the global GCM instance - // stores its data. + DIR_GLOBAL_GCM_STORE, // Directory where the global GCM instance + // stores its data. #endif // Valid only in development environment; TODO(darin): move these - DIR_GEN_TEST_DATA, // Directory where generated test data resides. - DIR_TEST_DATA, // Directory where unit test data resides. - DIR_TEST_TOOLS, // Directory where unit test tools reside. + DIR_GEN_TEST_DATA, // Directory where generated test data resides. + DIR_TEST_DATA, // Directory where unit test data resides. + DIR_TEST_TOOLS, // Directory where unit test tools reside. #if defined(OS_LINUX) - FILE_COMPONENT_FLASH_HINT, // A file in a known location that points to - // the component updated flash plugin. + FILE_COMPONENT_FLASH_HINT, // A file in a known location that points to + // the component updated flash plugin. #endif // defined(OS_LINUX) #if defined(OS_CHROMEOS) FILE_CHROME_OS_COMPONENT_FLASH, // The location of component updated Flash on
diff --git a/chrome/common/extensions/api/BUILD.gn b/chrome/common/extensions/api/BUILD.gn index 8fb7199..87b6f10 100644 --- a/chrome/common/extensions/api/BUILD.gn +++ b/chrome/common/extensions/api/BUILD.gn
@@ -47,7 +47,6 @@ schema_include_rules = chrome_extensions_api_schema_include_rules sources += [ - "action.json", "app.json", "commands.json", "declarative_content.json",
diff --git a/chrome/common/extensions/api/action.json b/chrome/common/extensions/api/action.json index a277a49b..49c4b2e8 100644 --- a/chrome/common/extensions/api/action.json +++ b/chrome/common/extensions/api/action.json
@@ -6,6 +6,9 @@ { "namespace": "action", "description": "Use actions to put icons in the main Google Chrome toolbar, to the right of the address bar. Actions can be set to take action on all pages (default_state: enabled) or only the current page (default_state: disabled). If an action is default disabled, the action appears grayed out when inactive. In addition to its <a href='action#icon'>icon</a>, an action can also have a <a href='action#tooltip'>tooltip</a>, a <a href='action#badge'>badge</a>, and a <a href='action#popups'>popup</a>.", + "compiler_options": { + "implemented_in": "chrome/browser/extensions/api/extension_action/extension_action_api.h" + }, "functions": [{ "name": "setTitle", "type": "function",
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni index 1f734e4..9c0c100 100644 --- a/chrome/common/extensions/api/api_sources.gni +++ b/chrome/common/extensions/api/api_sources.gni
@@ -124,11 +124,12 @@ } uncompiled_sources_ = [ - "page_action.json", + "action.json", "browser_action.json", "browsing_data.json", "extension.json", "idltest.idl", + "page_action.json", "top_sites.json", ]
diff --git a/chrome/common/features.gni b/chrome/common/features.gni index 628c4e2c..80d1116 100644 --- a/chrome/common/features.gni +++ b/chrome/common/features.gni
@@ -57,6 +57,7 @@ enable_simple_browser_service_out_of_process = is_chromeos && (is_debug || dcheck_always_on) + # TODO(crbug.com/980869): Change this to is_chromeos || is_android. enable_supervised_users = !is_chromecast # Indicates if Wayland display server support is enabled.
diff --git a/chrome/common/service_process_util_linux.cc b/chrome/common/service_process_util_linux.cc index 06f6e1d7..b324b31 100644 --- a/chrome/common/service_process_util_linux.cc +++ b/chrome/common/service_process_util_linux.cc
@@ -28,7 +28,7 @@ std::string GetBaseDesktopName() { #if defined(GOOGLE_CHROME_BUILD) return "google-chrome-service.desktop"; -#else // CHROMIUM_BUILD +#else // BUILDFLAG(CHROMIUM_BRANDING) return "chromium-service.desktop"; #endif } @@ -72,7 +72,7 @@ DCHECK(autorun_command_line_.get()); #if defined(GOOGLE_CHROME_BUILD) std::string app_name = "Google Chrome Service"; -#else // CHROMIUM_BUILD +#else // BUILDFLAG(CHROMIUM_BRANDING) std::string app_name = "Chromium Service"; #endif return AutoStart::AddApplication(
diff --git a/chrome/common/service_process_util_unittest.cc b/chrome/common/service_process_util_unittest.cc index 1c1cde0..01e26a5 100644 --- a/chrome/common/service_process_util_unittest.cc +++ b/chrome/common/service_process_util_unittest.cc
@@ -142,7 +142,7 @@ #elif defined(OS_POSIX) && !defined(OS_MACOSX) #if defined(GOOGLE_CHROME_BUILD) std::string base_desktop_name = "google-chrome-service.desktop"; -#else // CHROMIUM_BUILD +#else // BUILDFLAG(CHROMIUM_BRANDING) std::string base_desktop_name = "chromium-service.desktop"; #endif std::string exec_value;
diff --git a/chrome/credential_provider/eventlog/gcp_eventlog_messages.mc b/chrome/credential_provider/eventlog/gcp_eventlog_messages.mc index 0dfd0b3a..60ddd632 100644 --- a/chrome/credential_provider/eventlog/gcp_eventlog_messages.mc +++ b/chrome/credential_provider/eventlog/gcp_eventlog_messages.mc Binary files differ
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider.rgs b/chrome/credential_provider/gaiacp/gaia_credential_provider.rgs index 3e5d411..382666ab 100644 --- a/chrome/credential_provider/gaiacp/gaia_credential_provider.rgs +++ b/chrome/credential_provider/gaiacp/gaia_credential_provider.rgs
@@ -62,7 +62,7 @@ { NoRemove Application { - ForceRemove GCP + ForceRemove GCPW { val CategoryCount = d '1' val CategoryMessageFile = s '%EVENTLOG_PATH%'
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc index c284b32..495975f 100644 --- a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc +++ b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc
@@ -103,7 +103,7 @@ true, // Enable thread id. true, // Enable timestamp. false); // Enable tickcount. - logging::SetEventSource("GCP", GCP_CATEGORY, MSG_LOG_MESSAGE); + logging::SetEventSource("GCPW", GCPW_CATEGORY, MSG_LOG_MESSAGE); base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
diff --git a/chrome/credential_provider/setup/setup.cc b/chrome/credential_provider/setup/setup.cc index e573ced..3c6d36b6 100644 --- a/chrome/credential_provider/setup/setup.cc +++ b/chrome/credential_provider/setup/setup.cc
@@ -105,7 +105,7 @@ } } - logging::SetEventSource("GCP", GCP_CATEGORY, MSG_LOG_MESSAGE); + logging::SetEventSource("GCPW", GCPW_CATEGORY, MSG_LOG_MESSAGE); // Make sure the process exits cleanly on unexpected errors. base::EnableTerminationOnHeapCorruption();
diff --git a/chrome/credential_provider/test/gcp_setup_unittests.cc b/chrome/credential_provider/test/gcp_setup_unittests.cc index 16ef99a..394790f 100644 --- a/chrome/credential_provider/test/gcp_setup_unittests.cc +++ b/chrome/credential_provider/test/gcp_setup_unittests.cc
@@ -158,7 +158,7 @@ // Make sure eventlog source is registered. base::win::RegKey el_key( HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\GCP", + L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\GCPW", KEY_READ); EXPECT_EQ(registered, el_key.Valid());
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index 33295f1..f71bd8a2 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc
@@ -47,6 +47,10 @@ namespace { +// DowngradeVersion holds the version from which Chrome was downgraded. In case +// of multiple downgrades (e.g., 75->74->73), it retains the highest version +// installed prior to any downgrades. DowngradeVersion is deleted on upgrade +// once Chrome reaches the version from which it was downgraded. const wchar_t kRegDowngradeVersion[] = L"DowngradeVersion"; // These values are persisted to logs. Entries should not be renumbered and @@ -531,7 +535,7 @@ } // static -base::Version InstallUtil::GetDowngradeVersion() { +base::Optional<base::Version> InstallUtil::GetDowngradeVersion() { RegKey key; base::string16 downgrade_version; if (key.Open(install_static::IsSystemInstall() ? HKEY_LOCAL_MACHINE @@ -541,9 +545,12 @@ key.ReadValue(kRegDowngradeVersion, &downgrade_version) != ERROR_SUCCESS || downgrade_version.empty()) { - return base::Version(); + return base::nullopt; } - return base::Version(base::UTF16ToASCII(downgrade_version)); + base::Version version(base::UTF16ToASCII(downgrade_version)); + if (!version.IsValid()) + return base::nullopt; + return version; } // static @@ -553,18 +560,21 @@ const base::Version& new_version, WorkItemList* list) { DCHECK(list); - const base::Version downgrade_version = GetDowngradeVersion(); - if (!current_version || - (*current_version <= new_version && - ((!downgrade_version.IsValid() || downgrade_version <= new_version)))) { + const auto downgrade_version = GetDowngradeVersion(); + if (current_version && new_version < *current_version) { + // This is a downgrade. Write the value if this is the first one (i.e., no + // previous value exists). Otherwise, leave any existing value in place. + if (!downgrade_version) { + list->AddSetRegValueWorkItem( + root, install_static::GetClientStateKeyPath(), KEY_WOW64_32KEY, + kRegDowngradeVersion, + base::ASCIIToUTF16(current_version->GetString()), true); + } + } else if (!current_version || new_version >= downgrade_version) { + // This is a new install or an upgrade to/past a previous DowngradeVersion. list->AddDeleteRegValueWorkItem(root, install_static::GetClientStateKeyPath(), KEY_WOW64_32KEY, kRegDowngradeVersion); - } else if (*current_version > new_version && !downgrade_version.IsValid()) { - list->AddSetRegValueWorkItem( - root, install_static::GetClientStateKeyPath(), KEY_WOW64_32KEY, - kRegDowngradeVersion, base::ASCIIToUTF16(current_version->GetString()), - true); } }
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h index 79c14995..941308f 100644 --- a/chrome/installer/util/install_util.h +++ b/chrome/installer/util/install_util.h
@@ -16,6 +16,7 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "base/macros.h" +#include "base/optional.h" #include "base/strings/string16.h" #include "base/strings/string_piece.h" #include "base/version.h" @@ -163,9 +164,8 @@ static base::string16 GetCurrentDate(); // Returns the highest Chrome version that was installed prior to a downgrade, - // or an invalid Version if Chrome was not previously downgraded from a newer - // version. - static base::Version GetDowngradeVersion(); + // or no value if Chrome was not previously downgraded from a newer version. + static base::Optional<base::Version> GetDowngradeVersion(); // Adds or removes downgrade version registry value. This function should only // be used for Chrome install.
diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc index c55d180..eaa87e6 100644 --- a/chrome/installer/util/install_util_unittest.cc +++ b/chrome/installer/util/install_util_unittest.cc
@@ -439,14 +439,14 @@ base::Version lower_new_version_1("1.1.1.0"); base::Version lower_new_version_2("1.1.0.0"); - ASSERT_FALSE(InstallUtil::GetDowngradeVersion().IsValid()); + ASSERT_FALSE(InstallUtil::GetDowngradeVersion()); // Upgrade should not create the value. list.reset(WorkItem::CreateWorkItemList()); InstallUtil::AddUpdateDowngradeVersionItem(kRoot, ¤t_version, higer_new_version, list.get()); ASSERT_TRUE(list->Do()); - ASSERT_FALSE(InstallUtil::GetDowngradeVersion().IsValid()); + ASSERT_FALSE(InstallUtil::GetDowngradeVersion()); // Downgrade should create the value. list.reset(WorkItem::CreateWorkItemList()); @@ -501,7 +501,7 @@ InstallUtil::AddUpdateDowngradeVersionItem(kRoot, &lower_new_version_1, higer_new_version, list.get()); ASSERT_TRUE(list->Do()); - ASSERT_FALSE(InstallUtil::GetDowngradeVersion().IsValid()); + ASSERT_FALSE(InstallUtil::GetDowngradeVersion()); // Fresh install should delete the value if it exists. list.reset(WorkItem::CreateWorkItemList()); @@ -513,7 +513,7 @@ InstallUtil::AddUpdateDowngradeVersionItem(kRoot, nullptr, lower_new_version_1, list.get()); ASSERT_TRUE(list->Do()); - ASSERT_FALSE(InstallUtil::GetDowngradeVersion().IsValid()); + ASSERT_FALSE(InstallUtil::GetDowngradeVersion()); } TEST(DeleteRegistryKeyTest, DeleteAccessRightIsEnoughToDelete) {
diff --git a/chrome/installer/util/logging_installer.cc b/chrome/installer/util/logging_installer.cc index 78dfa44c..9473692 100644 --- a/chrome/installer/util/logging_installer.cc +++ b/chrome/installer/util/logging_installer.cc
@@ -117,7 +117,7 @@ static const base::FilePath::CharType kLogFilename[] = #if defined(GOOGLE_CHROME_BUILD) FILE_PATH_LITERAL("chrome_installer.log"); -#else // CHROMIUM_BUILD +#else // BUILDFLAG(CHROMIUM_BRANDING) FILE_PATH_LITERAL("chromium_installer.log"); #endif
diff --git a/chrome/renderer/searchbox/searchbox_extension.cc b/chrome/renderer/searchbox/searchbox_extension.cc index ddd3dd6..f4473b2 100644 --- a/chrome/renderer/searchbox/searchbox_extension.cc +++ b/chrome/renderer/searchbox/searchbox_extension.cc
@@ -1264,8 +1264,6 @@ if (!search_box) return; search_box->RevertThemeChanges(); - content::RenderThread::Get()->RecordAction( - base::UserMetricsAction("ChromeColors_MenuCancel")); } // static @@ -1274,8 +1272,6 @@ if (!search_box) return; search_box->ConfirmThemeChanges(); - content::RenderThread::Get()->RecordAction( - base::UserMetricsAction("ChromeColors_MenuDone")); } v8::Local<v8::Value> NewTabPageBindings::GetColorsInfo(v8::Isolate* isolate) {
diff --git a/chrome/services/app_service/public/cpp/BUILD.gn b/chrome/services/app_service/public/cpp/BUILD.gn index 3f42f44a..f31b9d5 100644 --- a/chrome/services/app_service/public/cpp/BUILD.gn +++ b/chrome/services/app_service/public/cpp/BUILD.gn
@@ -2,18 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -source_set("app_service_proxy") { - sources = [ - "app_service_proxy.cc", - "app_service_proxy.h", - ] - - deps = [ - ":app_update", - ":icon_loader", - ] -} - source_set("app_update") { sources = [ "app_registry_cache.cc",
diff --git a/chrome/services/app_service/public/cpp/app_service_proxy.cc b/chrome/services/app_service/public/cpp/app_service_proxy.cc deleted file mode 100644 index 6d2fe0d..0000000 --- a/chrome/services/app_service/public/cpp/app_service_proxy.cc +++ /dev/null
@@ -1,52 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/services/app_service/public/cpp/app_service_proxy.h" - -#include <utility> - -namespace apps { - -AppServiceProxy::AppServiceProxy() = default; - -AppServiceProxy::~AppServiceProxy() = default; - -apps::mojom::AppServicePtr& AppServiceProxy::AppService() { - return app_service_; -} - -apps::AppRegistryCache& AppServiceProxy::AppRegistryCache() { - return cache_; -} - -apps::mojom::IconKeyPtr AppServiceProxy::GetIconKey(const std::string& app_id) { - return apps::mojom::IconKey::New(); -} - -std::unique_ptr<apps::IconLoader::Releaser> -AppServiceProxy::LoadIconFromIconKey( - apps::mojom::AppType app_type, - const std::string& app_id, - apps::mojom::IconKeyPtr icon_key, - apps::mojom::IconCompression icon_compression, - int32_t size_hint_in_dip, - bool allow_placeholder_icon, - apps::mojom::Publisher::LoadIconCallback callback) { - std::move(callback).Run(apps::mojom::IconValue::New()); - return nullptr; -} - -void AppServiceProxy::Launch(const std::string& app_id, - int32_t event_flags, - apps::mojom::LaunchSource launch_source, - int64_t display_id) {} - -void AppServiceProxy::SetPermission(const std::string& app_id, - apps::mojom::PermissionPtr permission) {} - -void AppServiceProxy::Uninstall(const std::string& app_id) {} - -void AppServiceProxy::OpenNativeSettings(const std::string& app_id) {} - -} // namespace apps
diff --git a/chrome/services/app_service/public/cpp/app_service_proxy.h b/chrome/services/app_service/public/cpp/app_service_proxy.h deleted file mode 100644 index 38adb8b1..0000000 --- a/chrome/services/app_service/public/cpp/app_service_proxy.h +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_APP_SERVICE_PROXY_H_ -#define CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_APP_SERVICE_PROXY_H_ - -#include <memory> - -#include "base/macros.h" -#include "chrome/services/app_service/public/cpp/app_registry_cache.h" -#include "chrome/services/app_service/public/cpp/icon_loader.h" -#include "chrome/services/app_service/public/mojom/app_service.mojom.h" - -namespace apps { - -// Abstract superclass (with default no-op methods) for the App Service proxy. -// See chrome/services/app_service/README.md. -// -// Most code, outside of tests, should use an AppServiceProxyImpl. -class AppServiceProxy : public apps::IconLoader { - public: - AppServiceProxy(); - ~AppServiceProxy() override; - - apps::mojom::AppServicePtr& AppService(); - apps::AppRegistryCache& AppRegistryCache(); - - // apps::IconLoader overrides. - apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override; - std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey( - apps::mojom::AppType app_type, - const std::string& app_id, - apps::mojom::IconKeyPtr icon_key, - apps::mojom::IconCompression icon_compression, - int32_t size_hint_in_dip, - bool allow_placeholder_icon, - apps::mojom::Publisher::LoadIconCallback callback) override; - - virtual void Launch(const std::string& app_id, - int32_t event_flags, - apps::mojom::LaunchSource launch_source, - int64_t display_id); - - virtual void SetPermission(const std::string& app_id, - apps::mojom::PermissionPtr permission); - - virtual void Uninstall(const std::string& app_id); - - virtual void OpenNativeSettings(const std::string& app_id); - - protected: - apps::mojom::AppServicePtr app_service_; - apps::AppRegistryCache cache_; - - private: - DISALLOW_COPY_AND_ASSIGN(AppServiceProxy); -}; - -} // namespace apps - -#endif // CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_APP_SERVICE_PROXY_H_
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 512ebddb..f60af13 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -782,6 +782,7 @@ "../browser/autofill/autofill_server_browsertest.cc", "../browser/autofill/content_autofill_driver_browsertest.cc", "../browser/autofill/form_structure_browsertest.cc", + "../browser/availability/availability_prober_browsertest.cc", "../browser/background_fetch/background_fetch_browsertest.cc", "../browser/background_sync/background_sync_browsertest.cc", "../browser/background_sync/background_sync_metrics_browsertest.cc", @@ -1024,7 +1025,6 @@ "../browser/previews/lazyload_browsertest.cc", "../browser/previews/previews_browsertest.cc", "../browser/previews/previews_lite_page_browsertest.cc", - "../browser/previews/previews_prober_browsertest.cc", "../browser/previews/previews_service_browser_test.cc", "../browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc", "../browser/process_singleton_browsertest.cc", @@ -2777,6 +2777,7 @@ "../browser/autocomplete/chrome_autocomplete_scheme_classifier_unittest.cc", "../browser/autocomplete/search_provider_unittest.cc", "../browser/autocomplete/shortcuts_provider_extension_unittest.cc", + "../browser/availability/availability_prober_unittest.cc", "../browser/background_fetch/background_fetch_delegate_impl_unittest.cc", "../browser/background_fetch/background_fetch_permission_context_unittest.cc", "../browser/background_sync/background_sync_controller_impl_unittest.cc", @@ -2813,7 +2814,6 @@ "../browser/component_updater/optimization_hints_component_installer_unittest.cc", "../browser/component_updater/origin_trials_component_installer_unittest.cc", "../browser/component_updater/subresource_filter_component_installer_unittest.cc", - "../browser/component_updater/supervised_user_whitelist_installer_unittest.cc", "../browser/component_updater/sw_reporter_installer_win_unittest.cc", "../browser/content_index/content_index_provider_unittest.cc", "../browser/content_settings/content_settings_default_provider_unittest.cc", @@ -3066,7 +3066,6 @@ "../browser/previews/previews_lite_page_predictor_unittest.cc", "../browser/previews/previews_lite_page_url_loader_interceptor_unittest.cc", "../browser/previews/previews_offline_helper_unittest.cc", - "../browser/previews/previews_prober_unittest.cc", "../browser/previews/previews_service_unittest.cc", "../browser/previews/previews_top_host_provider_unittest.cc", "../browser/previews/previews_ui_tab_helper_unittest.cc", @@ -3832,7 +3831,7 @@ if (!is_android) { sources += [ - "../browser/apps/app_service/app_service_proxy_impl_unittest.cc", + "../browser/apps/app_service/app_service_proxy_unittest.cc", "../browser/apps/intent_helper/apps_navigation_throttle_unittest.cc", "../browser/apps/intent_helper/page_transition_util_unittest.cc", "../browser/devtools/devtools_file_system_indexer_unittest.cc", @@ -4432,7 +4431,6 @@ } if (!is_chromeos && is_linux) { sources += [ - "../browser/password_manager/native_backend_kwallet_x_unittest.cc", "../browser/shell_integration_linux_unittest.cc", "../browser/ui/input_method/input_method_engine_unittest.cc", ] @@ -4567,6 +4565,11 @@ "//components/safe_browsing/renderer:websocket_sb_handshake_throttle_unittest", "//components/safe_browsing/triggers:ad_redirect_trigger", ] + + # TODO(drubery): Once b/138388200 has been addressed, enable this on Windows. + if (!is_win) { + sources += [ "../browser/safe_browsing/download_protection/multipart_uploader_unittest.cc" ] + } } else if (safe_browsing_mode == 2) { sources += [ "../browser/safe_browsing/telemetry/android/android_telemetry_service_unittest.cc" ] deps += [] @@ -4670,21 +4673,6 @@ } else { sources -= [ "../browser/password_manager/password_store_x_unittest.cc" ] } - if (use_gnome_keyring && current_cpu == "x64") { - # Only add this test for 64 bit builds because otherwise we need the 32 - # bit library on 64 bit systems when running this test. - sources += - [ "../browser/password_manager/native_backend_gnome_x_unittest.cc" ] - configs += [ - "//components/os_crypt:gnome_keyring", - "//components/os_crypt:gnome_keyring_direct", - ] - } - if (is_linux && !is_chromeos && !use_ozone) { - sources += - [ "../browser/password_manager/native_backend_libsecret_unittest.cc" ] - deps += [ "//third_party/libsecret" ] - } if (is_linux && use_aura) { deps += [ "//ui/aura:test_support" ] if (use_dbus) { @@ -4941,6 +4929,7 @@ } if (enable_supervised_users) { sources += [ + "../browser/component_updater/supervised_user_whitelist_installer_unittest.cc", "../browser/content_settings/content_settings_supervised_provider_unittest.cc", "../browser/supervised_user/child_accounts/child_account_service_unittest.cc", "../browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc", @@ -4980,6 +4969,7 @@ "../browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc", "../browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc", "../browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc", + "../browser/ui/app_list/search/logging/search_ranking_event_logger_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/app_launch_event_logger_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/app_launch_predictor_unittest.cc", "../browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider_unittest.cc",
diff --git a/chrome/test/android/DEPS b/chrome/test/android/DEPS index c470c190..56d481ae 100644 --- a/chrome/test/android/DEPS +++ b/chrome/test/android/DEPS
@@ -2,5 +2,4 @@ # This test code needs to depend on sync related classes and test tools. "+components/sync/android/java/src/org/chromium/components/sync/signin", "+components/sync/test/android/javatests/src/org/chromium/components/sync/test/util", - "+components/signin/core/browser/android/java/src/org/chromium/components/signin", ]
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/ArticleCardController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/ArticleCardController.java index 56534220..1fa0419 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/ArticleCardController.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/ArticleCardController.java
@@ -105,14 +105,14 @@ return null; } else { if (headline == null) - throw UiLocationException.newInstance( - "Headline not found", headlineLocator, articleCard); + throw new UiLocationException( + "Headline not found.", headlineLocator, articleCard); else if (publisher == null) - throw UiLocationException.newInstance( - "Publisher not found", publisherLocator, articleCard); + throw new UiLocationException( + "Publisher not found.", publisherLocator, articleCard); else - throw UiLocationException.newInstance( - "Age not found", ageLocator, articleCard); + throw new UiLocationException( + "Age not found.", ageLocator, articleCard); } } });
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/SuggestionTileController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/SuggestionTileController.java index f7df404..2eaa52c 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/SuggestionTileController.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/ntp/SuggestionTileController.java
@@ -86,8 +86,8 @@ // called again if we throw an exception. This // gives a chance for the title UI of the tile to // load. - throw UiLocationException.newInstance( - "Title is null", LOCATOR_TILE_TITLES, root); + throw new UiLocationException( + "Title not found.", LOCATOR_TILE_TITLES, root); } else { // This is the last attempt. It is possible that // no complete tiles are found on the screen, just
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/tabswitcher/TabSwitcherController.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/tabswitcher/TabSwitcherController.java index a257204..c3ec853 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/tabswitcher/TabSwitcherController.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/controllers/tabswitcher/TabSwitcherController.java
@@ -55,8 +55,9 @@ if (matcher.matches()) { return Integer.valueOf(matcher.group(1)); } else { - throw UiLocationException.newInstance( - "Could not match " + text + " to " + PATTERN_NUMBER_OF_OPEN_TABS); + throw new UiLocationException( + "Could not get number of open tabs in Tab Switcher button.", + LOCATOR_TAB_SWITCHER_BUTTON); } } public NewTabPageController clickNewTab() {
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiApplicationTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiApplicationTestRule.java index 983603d..079a789 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiApplicationTestRule.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/rules/ChromeUiApplicationTestRule.java
@@ -40,7 +40,7 @@ return instance; } } - throw UiLocationException.newInstance("Could not detect current Page"); + throw new UiLocationException("Could not detect current Page."); } /** Launch the chrome application */ @@ -71,8 +71,8 @@ if (controller instanceof NewTabPageController) { return (NewTabPageController) controller; } else { - throw UiLocationException.newInstance( - "Could not navigate to new tab page from " + controller.getClass().getName()); + throw new UiLocationException("Could not navigate to new tab page from " + + controller.getClass().getName() + "."); } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiAutomatorUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiAutomatorUtils.java index 3f784f7..0e3944b 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiAutomatorUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiAutomatorUtils.java
@@ -342,15 +342,14 @@ int iterationsLeft = MAX_SWIPES; while (!mLocatorHelper.isOnScreen(locator) && iterationsLeft-- > 0) { if (mLocatorHelper.isOnScreen(stopLocator)) - throw UiLocationException.newInstance( - "Did not find locator while swiping to " + stopLocator, locator, null); + throw new UiLocationException( + "Did not find locator while swiping to " + stopLocator + ".", locator); swipeVertically(fractionOfScreen); Utils.sleep(UiLocatorHelper.UI_CHECK_INTERVAL_MS); } if (!mLocatorHelper.isOnScreen(locator)) { - throw UiLocationException.newInstance( - "Did not find locator after swiping for " + MAX_SWIPES + " times", locator, - null); + throw new UiLocationException( + "Did not find locator after swiping for " + MAX_SWIPES + " times.", locator); } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocationException.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocationException.java index a26c213..02676227 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocationException.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocationException.java
@@ -8,53 +8,40 @@ /** * Exception class that represents an unexpected failure when trying to find - * a UI element. + * a UI node. */ public class UiLocationException extends IllegalStateException { - private final UiObject2 mUiObject2; - private final IUi2Locator mIUi2Locator; - - public UiObject2 getUiObject2() { - return mUiObject2; - } - - public IUi2Locator getIUi2Locator() { - return mIUi2Locator; - } - - private UiLocationException( - String message, Throwable cause, UiObject2 mUiObject2, IUi2Locator mIUi2Locator) { - super(message, cause); - this.mUiObject2 = mUiObject2; - this.mIUi2Locator = mIUi2Locator; - } - /** - * Creates a UiLocationException exception. + * Creates a UiLocationException exception when the locator used is not + * known. * * @param msg The error message. - * @return UiLocationException with msg. */ - public static UiLocationException newInstance(String msg) { - return newInstance(msg, null, null); + public UiLocationException(String msg) { + super(msg); } /** - * Creates a UiLocationException exception. + * Creates a UiLocationException exception when the locator failed to find + * any nodes in the root node. * * @param msg The error message. * @param locator The locator that failed to find any nodes. * @param root The root that the locator searched under, or null if all the nodes were * searched. - * @return UiLocationException with msg, locator, and root. */ - public static UiLocationException newInstance(String msg, IUi2Locator locator, UiObject2 root) { - if (root == null) { - return new UiLocationException( - msg + " Locator: " + locator + " on device", null, root, locator); - } else { - return new UiLocationException( - msg + " Locator: " + locator + " in " + root.toString(), null, root, locator); - } + public UiLocationException(String msg, IUi2Locator locator, UiObject2 root) { + this(msg + " (Locator=" + locator + " in root=" + root + ")"); + } + + /** + * Creates a UiLocationException exception when the locator failed to find + * any nodes on the device. + * + * @param msg The error message. + * @param locator The locator that failed to find any nodes. + */ + public UiLocationException(String msg, IUi2Locator locator) { + this(msg + " (Locator=" + locator + " on device)"); } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocatorHelper.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocatorHelper.java index 658221f..40f2f16 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocatorHelper.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/pagecontroller/utils/UiLocatorHelper.java
@@ -42,7 +42,7 @@ if (object2.isCheckable()) { return object2.isChecked(); } else { - throw UiLocationException.newInstance("Item is not checkable", null, object2); + throw new UiLocationException("Item in " + object2 + " is not checkable."); } }; @@ -288,9 +288,9 @@ } Utils.sleep(UI_CHECK_INTERVAL_MS); } while (true); - throw UiLocationException.newInstance("Could not find any objects after " + elapsedTime - + " ms and " + attempts + " attempts", - locator, null); + throw new UiLocationException("Could not find any objects after " + elapsedTime + " ms and " + + attempts + " attempts.", + locator); } /**
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityUtils.java index bdf4aff..b3a5e4d 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ActivityUtils.java
@@ -5,8 +5,6 @@ package org.chromium.chrome.test.util; import android.app.Activity; -import android.app.DialogFragment; -import android.app.Fragment; import android.app.Instrumentation; import android.app.Instrumentation.ActivityMonitor; import android.content.Context; @@ -40,33 +38,6 @@ private static final long CONDITION_POLL_INTERVAL_MS = 100; /** - * Waits for a particular fragment to be present on a given activity. - */ - private static class FragmentPresentCriteria extends Criteria { - - private final Activity mActivity; - private final String mFragmentTag; - - public FragmentPresentCriteria(Activity activity, String fragmentTag) { - super(String.format("Could not locate the fragment with tag '%s'", fragmentTag)); - mActivity = activity; - mFragmentTag = fragmentTag; - } - - @Override - public boolean isSatisfied() { - Fragment fragment = mActivity.getFragmentManager().findFragmentByTag(mFragmentTag); - if (fragment == null) return false; - if (fragment instanceof DialogFragment) { - DialogFragment dialogFragment = (DialogFragment) fragment; - return dialogFragment.getDialog() != null - && dialogFragment.getDialog().isShowing(); - } - return fragment.getView() != null; - } - } - - /** * Captures an activity of a particular type by launching an intent explicitly targeting the * activity. * @@ -179,24 +150,6 @@ * @param activity The activity that owns the fragment. * @param fragmentTag The tag of the fragment to be loaded. */ - @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) - public static <T> T waitForFragment(Activity activity, String fragmentTag) { - CriteriaHelper.pollInstrumentationThread(new FragmentPresentCriteria(activity, fragmentTag), - ACTIVITY_START_TIMEOUT_MS, CONDITION_POLL_INTERVAL_MS); - return (T) activity.getFragmentManager().findFragmentByTag(fragmentTag); - } - - /** - * TODO(crbug.com/967022): This method is a duplicate of {@link #waitForFragment(Activity, - * String)}, but with Support Library classes replacing deprecated Framework classes. When - * Preference Support Library migration is complete remove {@link #waitForFragment(Activity, - * String)} and {@link FragmentPresentCriteria} in favor of this method. - * - * Waits for a fragment to be registered by the specified activity. - * - * @param activity The activity that owns the fragment. - * @param fragmentTag The tag of the fragment to be loaded. - */ @SuppressWarnings("unchecked") public static <T extends android.support.v4.app.Fragment> T waitForFragmentCompat( AppCompatActivity activity, String fragmentTag) { @@ -226,35 +179,6 @@ * quickly and we can miss the time that a fragment is visible. This method allows you to get a * reference to any fragment that was attached to the activity at any point. * - * @param <T> A subclass of android.app.Fragment - * @param activity An instance or subclass of Preferences - * @param fragmentClass The class object for T - * @return A reference to the requested fragment or null. - */ - @SuppressWarnings("unchecked") - public static <T extends Fragment> T waitForFragmentToAttach( - final Preferences activity, final Class<T> fragmentClass) { - CriteriaHelper.pollInstrumentationThread( - new Criteria("Could not find fragment " + fragmentClass) { - @Override - public boolean isSatisfied() { - return fragmentClass.isInstance(activity.getMainFragment()); - } - }, ACTIVITY_START_TIMEOUT_MS, CONDITION_POLL_INTERVAL_MS); - return (T) activity.getMainFragment(); - } - - /** - * TODO(crbug.com/967022): This method is a duplicate of {@link - * #waitForFragmentToAttach(Preferences, Class)}, but with Support Library classes replacing - * deprecated Framework classes. When Preference Support Library migration is complete remove - * {@link #waitForFragmentToAttach(Preferences, Class)} in favor of this method. - * - * Waits until the specified fragment has been attached to the specified activity. Note that - * we don't guarantee that the fragment is visible. Some UI operations can happen too - * quickly and we can miss the time that a fragment is visible. This method allows you to get a - * reference to any fragment that was attached to the activity at any point. - * * @param <T> A subclass of {@link android.support.v4.app.Fragment}. * @param activity An instance or subclass of {@link Preferences}. * @param fragmentClass The class object for {@link T}.
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeSigninUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeSigninUtils.java index f432de2..26abd7b 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeSigninUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ChromeSigninUtils.java
@@ -17,7 +17,6 @@ import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.ChromeSigninController; -import org.chromium.components.signin.CoreAccountInfo; import org.chromium.components.signin.test.util.AccountHolder; import org.chromium.components.signin.test.util.FakeAccountManagerDelegate; @@ -86,11 +85,9 @@ * Removes all fake accounts from the OS. */ public void removeAllFakeAccountsFromOs() throws Exception { - for (CoreAccountInfo accountInfo : mFakeAccountManagerDelegate.getAccountsSyncNoThrow()) { + for (Account acct : mFakeAccountManagerDelegate.getAccountsSyncNoThrow()) { mFakeAccountManagerDelegate.removeAccountHolderBlocking( - AccountHolder.builder(accountInfo.getAccount()) - .accountId(accountInfo.getId()) - .build()); + AccountHolder.builder(acct).build()); } } @@ -101,8 +98,8 @@ * @return {@code true} if fake account is on OS, false otherwise. */ public boolean isExistingFakeAccountOnOs(String username) { - for (CoreAccountInfo accountInfo : mFakeAccountManagerDelegate.getAccountsSyncNoThrow()) { - if (username.equals(accountInfo.getName())) { + for (Account acct : mFakeAccountManagerDelegate.getAccountsSyncNoThrow()) { + if (username.equals(acct.name)) { return true; } }
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java index c493222d..b7a2052 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestUtil.java
@@ -14,7 +14,6 @@ import org.chromium.components.signin.AccountIdProvider; import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.ChromeSigninController; -import org.chromium.components.signin.CoreAccountInfo; import org.chromium.components.signin.OAuth2TokenService; import org.chromium.components.signin.test.util.AccountHolder; import org.chromium.components.signin.test.util.FakeAccountManagerDelegate; @@ -104,12 +103,13 @@ } private static void seedAccounts() { - List<CoreAccountInfo> accountInfos = sAccountManager.getAccountsSyncNoThrow(); - String[] accountNames = new String[accountInfos.size()]; - String[] accountIds = new String[accountInfos.size()]; - for (int i = 0; i < accountInfos.size(); i++) { - accountNames[i] = accountInfos.get(i).getName(); - accountIds[i] = accountInfos.get(i).getId().getGaiaIdAsString(); + AccountIdProvider accountIdProvider = AccountIdProvider.getInstance(); + Account[] accounts = sAccountManager.getAccountsSyncNoThrow(); + String[] accountNames = new String[accounts.length]; + String[] accountIds = new String[accounts.length]; + for (int i = 0; i < accounts.length; i++) { + accountNames[i] = accounts[i].name; + accountIds[i] = accountIdProvider.getAccountId(accounts[i].name); } IdentityServicesProvider.getAccountTrackerService().syncForceRefreshForTest( accountIds, accountNames);
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc index 0386c5a..2cfff5c 100644 --- a/chrome/test/base/in_process_browser_test.cc +++ b/chrome/test/base/in_process_browser_test.cc
@@ -57,6 +57,7 @@ #include "chrome/test/base/chrome_test_suite.h" #include "chrome/test/base/test_launcher_utils.h" #include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/ui_test_utils.h" #include "components/google/core/common/google_util.h" #include "components/os_crypt/os_crypt_mocker.h" #include "content/public/browser/devtools_agent_host.h" @@ -319,10 +320,8 @@ } void InProcessBrowserTest::CloseBrowserSynchronously(Browser* browser) { - content::WindowedNotificationObserver observer( - chrome::NOTIFICATION_BROWSER_CLOSED, content::Source<Browser>(browser)); CloseBrowserAsynchronously(browser); - observer.Wait(); + ui_test_utils::WaitForBrowserToClose(browser); } void InProcessBrowserTest::CloseBrowserAsynchronously(Browser* browser) {
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h index 423ba03..5d6159af 100644 --- a/chrome/test/base/test_browser_window.h +++ b/chrome/test/base/test_browser_window.h
@@ -127,8 +127,8 @@ void ShowBookmarkBubble(const GURL& url, bool already_bookmarked) override {} #if !defined(OS_ANDROID) void ShowIntentPickerBubble(std::vector<apps::IntentPickerAppInfo> app_info, - bool enable_stay_in_chrome, - bool show_persistence_options, + bool show_stay_in_chrome, + bool show_remember_selection, IntentPickerResponse callback) override {} #endif // !define(OS_ANDROID) autofill::SaveCardBubbleView* ShowSaveCreditCardBubble(
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc index 6e020e9..1022469 100644 --- a/chrome/test/base/testing_browser_process.cc +++ b/chrome/test/base/testing_browser_process.cc
@@ -370,10 +370,12 @@ return nullptr; } +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) component_updater::SupervisedUserWhitelistInstaller* TestingBrowserProcess::supervised_user_whitelist_installer() { return nullptr; } +#endif MediaFileSystemRegistry* TestingBrowserProcess::media_file_system_registry() { #if defined(OS_ANDROID)
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h index 7cfbf01c..a2df097 100644 --- a/chrome/test/base/testing_browser_process.h +++ b/chrome/test/base/testing_browser_process.h
@@ -121,8 +121,10 @@ #endif component_updater::ComponentUpdateService* component_updater() override; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) component_updater::SupervisedUserWhitelistInstaller* supervised_user_whitelist_installer() override; +#endif MediaFileSystemRegistry* media_file_system_registry() override; WebRtcLogUploader* webrtc_log_uploader() override;
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index 34beb1d..08fc569 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc
@@ -437,8 +437,10 @@ user_prefs::UserPrefs::Set(this, prefs_.get()); else if (IsOffTheRecord()) CreateIncognitoPrefService(); +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) else if (!supervised_user_id_.empty()) CreatePrefServiceForSupervisedUser(); +#endif else CreateTestingPrefService(); @@ -821,6 +823,7 @@ RegisterUserProfilePrefs(testing_prefs_->registry()); } +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) void TestingProfile::CreatePrefServiceForSupervisedUser() { DCHECK(!prefs_.get()); DCHECK(!supervised_user_id_.empty()); @@ -839,6 +842,7 @@ RegisterUserProfilePrefs(registry.get()); user_prefs::UserPrefs::Set(this, prefs_.get()); } +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) void TestingProfile::CreateIncognitoPrefService() { DCHECK(original_profile_);
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h index 8a9c81e0..6dd27277 100644 --- a/chrome/test/base/testing_profile.h +++ b/chrome/test/base/testing_profile.h
@@ -16,6 +16,7 @@ #include "base/optional.h" #include "build/build_config.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/common/buildflags.h" #include "components/domain_reliability/clear_mode.h" #include "components/keyed_service/content/browser_context_keyed_service_factory.h" #include "components/keyed_service/core/simple_factory_key.h" @@ -419,9 +420,11 @@ // Creates a TestingPrefService and associates it with the TestingProfile. void CreateTestingPrefService(); +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) // Creates a pref service that uses SupervisedUserPrefStore and associates // it with the TestingProfile. void CreatePrefServiceForSupervisedUser(); +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) // Initializes |prefs_| for an incognito profile, derived from // |original_profile_|.
diff --git a/chrome/test/data/BUILD.gn b/chrome/test/data/BUILD.gn index f976695..befb2de 100644 --- a/chrome/test/data/BUILD.gn +++ b/chrome/test/data/BUILD.gn
@@ -29,7 +29,4 @@ sources = [ "webui/web_ui_test.mojom", ] - - # TODO(https://crbug.com/968369): Change to use new names. - use_old_js_lite_bindings_names = true }
diff --git a/chrome/test/data/android/render_tests/BookmarkReorderTest.bookmark_manager_folder_selected.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeDisabled-bookmark_manager_folder_selected.Nexus_5-19.png.sha1 similarity index 100% rename from chrome/test/data/android/render_tests/BookmarkReorderTest.bookmark_manager_folder_selected.Nexus_5-19.png.sha1 rename to chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeDisabled-bookmark_manager_folder_selected.Nexus_5-19.png.sha1
diff --git a/chrome/test/data/android/render_tests/BookmarkReorderTest.bookmark_manager_one_folder.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeDisabled-bookmark_manager_one_folder.Nexus_5-19.png.sha1 similarity index 100% rename from chrome/test/data/android/render_tests/BookmarkReorderTest.bookmark_manager_one_folder.Nexus_5-19.png.sha1 rename to chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeDisabled-bookmark_manager_one_folder.Nexus_5-19.png.sha1
diff --git a/chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeEnabled-bookmark_manager_folder_selected.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeEnabled-bookmark_manager_folder_selected.Nexus_5-19.png.sha1 new file mode 100644 index 0000000..2608ec14 --- /dev/null +++ b/chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeEnabled-bookmark_manager_folder_selected.Nexus_5-19.png.sha1
@@ -0,0 +1 @@ +82717411fb282589ba37ac01f0e5d81a3c12babc
diff --git a/chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeEnabled-bookmark_manager_one_folder.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeEnabled-bookmark_manager_one_folder.Nexus_5-19.png.sha1 new file mode 100644 index 0000000..c5c2a7e1 --- /dev/null +++ b/chrome/test/data/android/render_tests/BookmarkReorderTest.NightModeEnabled-bookmark_manager_one_folder.Nexus_5-19.png.sha1
@@ -0,0 +1 @@ +b2b67ed9e0c888c4076d7fdf5de394743def87f7
diff --git a/chrome/test/data/android/render_tests/RevampedContextMenuRenderTest.NightModeDisabled-revamped_context_menu_with_image_link.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/RevampedContextMenuRenderTest.NightModeDisabled-revamped_context_menu_with_image_link.Nexus_5-19.png.sha1 index c3c9603f..6e078d2e 100644 --- a/chrome/test/data/android/render_tests/RevampedContextMenuRenderTest.NightModeDisabled-revamped_context_menu_with_image_link.Nexus_5-19.png.sha1 +++ b/chrome/test/data/android/render_tests/RevampedContextMenuRenderTest.NightModeDisabled-revamped_context_menu_with_image_link.Nexus_5-19.png.sha1
@@ -1 +1 @@ -329f6dd0d04005e2f71bdafb3bb322574746c7a2 \ No newline at end of file +cfaf40f75d21ecfba91edcf14a796a950270cb69 \ No newline at end of file
diff --git a/chrome/test/data/android/render_tests/RevampedContextMenuRenderTest.NightModeEnabled-revamped_context_menu_with_image_link.Nexus_5-19.png.sha1 b/chrome/test/data/android/render_tests/RevampedContextMenuRenderTest.NightModeEnabled-revamped_context_menu_with_image_link.Nexus_5-19.png.sha1 index d33a04f2..69defdb 100644 --- a/chrome/test/data/android/render_tests/RevampedContextMenuRenderTest.NightModeEnabled-revamped_context_menu_with_image_link.Nexus_5-19.png.sha1 +++ b/chrome/test/data/android/render_tests/RevampedContextMenuRenderTest.NightModeEnabled-revamped_context_menu_with_image_link.Nexus_5-19.png.sha1
@@ -1 +1 @@ -e1e15f28009525bc57b03b5860b80e69061cb753 \ No newline at end of file +b3b76225f96fb6ed97b73198f0dc1c77804dab38 \ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/certificate_provider/request_pin/operated.js b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/operated.js index c9365be..c3e0264 100644 --- a/chrome/test/data/extensions/api_test/certificate_provider/request_pin/operated.js +++ b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/operated.js
@@ -64,6 +64,9 @@ case 'RequestWithZeroAttempts': requestPin({signRequestId: SIGN_REQUEST_ID, attemptsLeft: 0}); break; + case 'RequestWithNegativeAttempts': + requestPin({signRequestId: SIGN_REQUEST_ID, attemptsLeft: -1}); + break; case 'Stop': stopPinRequest({signRequestId: SIGN_REQUEST_ID}); break;
diff --git a/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js b/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js index b954084a..f4d763a 100644 --- a/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js +++ b/chrome/test/data/webui/settings/chromeos/cups_printer_landing_page_tests.js
@@ -207,7 +207,7 @@ page = document.createElement('settings-cups-printers'); // Enable feature flag to show the new saved printers list. // TODO(jimmyxgong): Remove this line when the feature flag is removed. - page.enableUpdatedUI_ = true; + page.enableUpdatedUi_ = true; document.body.appendChild(page); assertTrue(!!page); @@ -386,7 +386,7 @@ page = document.createElement('settings-cups-printers'); // Enable feature flag to show the new saved printers list. // TODO(jimmyxgong): Remove this line when the feature flag is removed. - page.enableUpdatedUI_ = true; + page.enableUpdatedUi_ = true; document.body.appendChild(page); assertTrue(!!page);
diff --git a/chrome/test/data/webui/settings/chromeos/multidevice_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/multidevice_subpage_tests.js index fb689a2d..a774a6c 100644 --- a/chrome/test/data/webui/settings/chromeos/multidevice_subpage_tests.js +++ b/chrome/test/data/webui/settings/chromeos/multidevice_subpage_tests.js
@@ -168,7 +168,7 @@ }); test( - 'AndroidMessages set up button is disabled when prohibited by policy', + 'AndroidMessages toggle is disabled when prohibited by policy', function() { // Verify that setup button is disabled when prohibited by policy. multideviceSubpage.pageContentData = @@ -181,9 +181,7 @@ let setUpButton = multideviceSubpage.$$('#messagesItem > [slot=feature-controller]'); - assertTrue(!!setUpButton); - assertTrue(setUpButton.tagName.includes('BUTTON')); - assertTrue(setUpButton.disabled); + assertFalse(!!setUpButton); // Verify that setup button is not disabled when feature is enabled. setAndroidSmsPairingComplete(false);
diff --git a/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js b/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js index 2ad9f784..9cb97ac7 100644 --- a/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js +++ b/chrome/test/data/webui/settings/chromeos/os_reset_page_test.js
@@ -23,8 +23,8 @@ lifetimeBrowserProxy = new settings.TestLifetimeBrowserProxy(); settings.LifetimeBrowserProxyImpl.instance_ = lifetimeBrowserProxy; - resetPageBrowserProxy = new reset_page.TestResetBrowserProxy(); - settings.ResetOsProxyImpl.instance_ = resetPageBrowserProxy; + resetPageBrowserProxy = new reset_page.TestOsResetBrowserProxy(); + settings.OsResetBrowserProxyImpl.instance_ = resetPageBrowserProxy; PolymerTest.clearBody(); resetPage = document.createElement('os-settings-reset-page');
diff --git a/chrome/test/data/webui/settings/chromeos/os_search_page_test.js b/chrome/test/data/webui/settings/chromeos/os_search_page_test.js new file mode 100644 index 0000000..f2fa3a1d --- /dev/null +++ b/chrome/test/data/webui/settings/chromeos/os_search_page_test.js
@@ -0,0 +1,122 @@ +// 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. + +cr.define('os_settings_search_page', function() { + function generateSearchEngineInfo() { + const searchEngines0 = + settings_search.createSampleSearchEngine(true, false, false); + searchEngines0.default = true; + const searchEngines1 = + settings_search.createSampleSearchEngine(true, false, false); + searchEngines1.default = false; + const searchEngines2 = + settings_search.createSampleSearchEngine(true, false, false); + searchEngines2.default = false; + + return { + defaults: [searchEngines0, searchEngines1, searchEngines2], + others: [], + extensions: [], + }; + } + + suite('OSSearchPageTests', function() { + /** @type {?SettingsSearchPageElement} */ + let page = null; + + let browserProxy = null; + + setup(function() { + browserProxy = new settings_search.TestSearchEnginesBrowserProxy(); + browserProxy.setSearchEnginesInfo(generateSearchEngineInfo()); + settings.SearchEnginesBrowserProxyImpl.instance_ = browserProxy; + PolymerTest.clearBody(); + page = document.createElement('os-settings-search-page'); + page.prefs = { + default_search_provider_data: { + template_url_data: {}, + }, + }; + document.body.appendChild(page); + }); + + teardown(function() { + page.remove(); + }); + + // Tests that the page is querying and displaying search engine info on + // startup. + test('Initialization', async () => { + const selectElement = page.$$('select'); + assertTrue(!!selectElement); + assertTrue(!!page.$$('#help-icon')); + + await browserProxy.whenCalled('getSearchEnginesList'); + Polymer.dom.flush(); + assertEquals(0, selectElement.selectedIndex); + + // Simulate a user initiated change of the default search engine. + selectElement.selectedIndex = 1; + selectElement.dispatchEvent(new CustomEvent('change')); + await browserProxy.whenCalled('setDefaultSearchEngine'); + assertEquals(1, selectElement.selectedIndex); + + // Simulate a change that happened in browser settings. + const searchEnginesInfo = generateSearchEngineInfo(); + searchEnginesInfo.defaults[0].default = false; + searchEnginesInfo.defaults[1].default = false; + searchEnginesInfo.defaults[2].default = true; + + browserProxy.resetResolver('setDefaultSearchEngine'); + cr.webUIListenerCallback('search-engines-changed', searchEnginesInfo); + Polymer.dom.flush(); + assertEquals(2, selectElement.selectedIndex); + + browserProxy.whenCalled('setDefaultSearchEngine').then(function() { + // Since the change happened in a different tab, there should be + // no new call to |setDefaultSearchEngine|. + assertNotReached('Should not call setDefaultSearchEngine again'); + }); + }); + + test('ControlledByExtension', async () => { + await browserProxy.whenCalled('getSearchEnginesList'); + const selectElement = page.$$('select'); + assertFalse(selectElement.disabled); + assertFalse(!!page.$$('extension-controlled-indicator')); + + page.set('prefs.default_search_provider_data.template_url_data', { + controlledBy: chrome.settingsPrivate.ControlledBy.EXTENSION, + controlledByName: 'fake extension name', + enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, + extensionId: 'fake extension id', + extensionCanBeDisabled: true, + value: {}, + }); + Polymer.dom.flush(); + + assertTrue(selectElement.disabled); + assertTrue(!!page.$$('extension-controlled-indicator')); + assertFalse(!!page.$$('cr-policy-pref-indicator')); + }); + + test('ControlledByPolicy', async () => { + await browserProxy.whenCalled('getSearchEnginesList'); + const selectElement = page.$$('select'); + assertFalse(selectElement.disabled); + assertFalse(!!page.$$('extension-controlled-indicator')); + + page.set('prefs.default_search_provider_data.template_url_data', { + controlledBy: chrome.settingsPrivate.ControlledBy.USER_POLICY, + enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, + value: {}, + }); + Polymer.dom.flush(); + + assertTrue(selectElement.disabled); + assertFalse(!!page.$$('extension-controlled-indicator')); + assertTrue(!!page.$$('cr-policy-pref-indicator')); + }); + }); +});
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js index 5859cb4..523fe6c0 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -821,8 +821,8 @@ return super.extraLibraries.concat([ BROWSER_SETTINGS_PATH + '../test_browser_proxy.js', BROWSER_SETTINGS_PATH + 'test_lifetime_browser_proxy.js', - BROWSER_SETTINGS_PATH + 'test_reset_browser_proxy.js', BROWSER_SETTINGS_PATH + 'test_util.js', + 'test_os_reset_browser_proxy.js', 'os_reset_page_test.js', ]); } @@ -832,6 +832,29 @@ mocha.run(); }); +// Test fixture for the "Search and assistant" page. +// eslint-disable-next-line no-var +var OSSettingsSearchPageTest = class extends OSSettingsBrowserTest { + /** @override */ + get browsePreload() { + return super.browsePreload + 'chromeos/os_search_page/os_search_page.html'; + } + + /** @override */ + get extraLibraries() { + return super.extraLibraries.concat([ + BROWSER_SETTINGS_PATH + '../test_browser_proxy.js', + BROWSER_SETTINGS_PATH + 'test_search_engines_browser_proxy.js', + 'os_search_page_test.js', + ]); + } +}; + +// Settings tests are flaky on debug. See https://crbug.com/968608. +TEST_F('OSSettingsSearchPageTest', 'MAYBE_AllJsTests', () => { + mocha.run(); +}); + // Test fixture for the Smb Shares page. // eslint-disable-next-line no-var var OSSettingsSmbPageTest = class extends OSSettingsBrowserTest {
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js index 589a33d..1ac227c 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_ui_browsertest.js
@@ -28,7 +28,15 @@ } }; -TEST_F('OSSettingsUIBrowserTest', 'All', () => { +// Timeouts in debug because the page can be slow to load. +// https://crbug.com/987512 +GEN('#if !defined(NDEBUG)'); +GEN('#define MAYBE_AllJsTests DISABLED_AllJsTests'); +GEN('#else'); +GEN('#define MAYBE_AllJsTests AllJsTests'); +GEN('#endif'); + +TEST_F('OSSettingsUIBrowserTest', 'MAYBE_AllJsTests', () => { suite('os-settings-ui', () => { let ui;
diff --git a/chrome/test/data/webui/settings/chromeos/test_os_reset_browser_proxy.js b/chrome/test/data/webui/settings/chromeos/test_os_reset_browser_proxy.js new file mode 100644 index 0000000..ef74482d --- /dev/null +++ b/chrome/test/data/webui/settings/chromeos/test_os_reset_browser_proxy.js
@@ -0,0 +1,23 @@ +// 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. + +cr.define('reset_page', function() { + /** @implements {settings.OsResetBrowserProxy} */ + class TestOsResetBrowserProxy extends TestBrowserProxy { + constructor() { + super([ + 'onPowerwashDialogShow', + ]); + } + + /** @override */ + onPowerwashDialogShow() { + this.methodCalled('onPowerwashDialogShow'); + } + } + + return { + TestOsResetBrowserProxy: TestOsResetBrowserProxy, + }; +});
diff --git a/chrome/test/data/webui/settings/settings_ui_browsertest.js b/chrome/test/data/webui/settings/settings_ui_browsertest.js index 15d38fbf..ac0a2d8 100644 --- a/chrome/test/data/webui/settings/settings_ui_browsertest.js +++ b/chrome/test/data/webui/settings/settings_ui_browsertest.js
@@ -26,13 +26,8 @@ // and several times that in a Debug build. See https://crbug.com/558434 // and http://crbug.com/711256. -GEN('#if !defined(NDEBUG) || defined(OS_MACOSX)'); -GEN('#define MAYBE_All DISABLED_All'); -GEN('#else'); -GEN('#define MAYBE_All All'); -GEN('#endif'); - -TEST_F('SettingsUIBrowserTest', 'MAYBE_All', function() { +// Disabling everywhere, see flaky failures at crbug.com/986985. +TEST_F('SettingsUIBrowserTest', 'DISABLED_All', function() { suite('settings-ui', function() { let toolbar; let ui;
diff --git a/chrome/test/data/webui/test_api.js b/chrome/test/data/webui/test_api.js index 4eb227b7..2e4327c 100644 --- a/chrome/test/data/webui/test_api.js +++ b/chrome/test/data/webui/test_api.js
@@ -704,9 +704,9 @@ Mojo.bindInterface( webUiTest.mojom.TestRunner.name, mojo.makeRequest(testRunner).handle); - } else if (webUiTest.mojom.TestRunnerProxy) { + } else if (webUiTest.mojom.TestRunnerRemote) { // For mojo-lite WebUI tests. - testRunner = webUiTest.mojom.TestRunner.getProxy(); + testRunner = webUiTest.mojom.TestRunner.getRemote(); } else { assertNotReached( 'Mojo bindings found, but no valid test interface loaded');
diff --git a/chrome/updater/win/net/network_unittest.cc b/chrome/updater/win/net/network_unittest.cc index 66d2e8a5..8500a39 100644 --- a/chrome/updater/win/net/network_unittest.cc +++ b/chrome/updater/win/net/network_unittest.cc
@@ -3,15 +3,17 @@ // found in the LICENSE file. #include "chrome/updater/win/net/network.h" + #include "base/memory/ref_counted.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" namespace updater { TEST(UpdaterTestNetwork, NetworkFetcherWinHTTPFactory) { - base::MessageLoopForUI message_loop; + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); auto fetcher = base::MakeRefCounted<NetworkFetcherFactory>()->Create(); EXPECT_NE(nullptr, fetcher.get()); }
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn index 1ad1ebb4..b043dd2e 100644 --- a/chromecast/browser/BUILD.gn +++ b/chromecast/browser/BUILD.gn
@@ -373,10 +373,10 @@ if (enable_cast_wayland_server) { sources += [ + "exo/cast_wm_helper.cc", + "exo/cast_wm_helper.h", "exo/wayland_server_controller.cc", "exo/wayland_server_controller.h", - "exo/wm_helper_cast_shell.cc", - "exo/wm_helper_cast_shell.h", "webview/webview_controller.cc", "webview/webview_controller.h", "webview/webview_grpc_service.cc",
diff --git a/chromecast/browser/accessibility/touch_exploration_controller.cc b/chromecast/browser/accessibility/touch_exploration_controller.cc index a83ed3b..c8ef3f0 100644 --- a/chromecast/browser/accessibility/touch_exploration_controller.cc +++ b/chromecast/browser/accessibility/touch_exploration_controller.cc
@@ -7,6 +7,8 @@ #include "chromecast/browser/accessibility/touch_exploration_controller.h" +#include <algorithm> +#include <string> #include <utility> #include "base/bind.h" @@ -52,8 +54,7 @@ prev_state_(NO_FINGERS_DOWN), DVLOG_on_(true) {} -TouchExplorationController::~TouchExplorationController() { -} +TouchExplorationController::~TouchExplorationController() {} void TouchExplorationController::SetTouchAccessibilityAnchorPoint( const gfx::Point& anchor_point_dip) { @@ -66,9 +67,9 @@ exclude_bounds_ = bounds; } -ui::EventRewriteStatus TouchExplorationController::RewriteEvent( +ui::EventDispatchDetails TouchExplorationController::RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { if (!event.IsTouchEvent()) { if (event.IsKeyEvent()) { const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event); @@ -77,7 +78,7 @@ << ", Flags: " << key_event.flags() << ", Is char: " << key_event.is_char(); } - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } const ui::TouchEvent& touch_event = static_cast<const ui::TouchEvent&>(event); @@ -97,10 +98,10 @@ bool in_exclude_area = exclude_bounds_.Contains(location); if (in_exclude_area) { if (state_ == NO_FINGERS_DOWN) - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); if (touch_event.type() == ui::ET_TOUCH_MOVED || touch_event.type() == ui::ET_TOUCH_PRESSED) { - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // Otherwise, continue handling events. Basically, we want to let // CANCELLED or RELEASE events through so this can get back to @@ -147,12 +148,11 @@ new_event->set_location(location); new_event->set_root_location(root_location); new_event->set_flags(touch_event.flags()); - *rewritten_event = std::move(new_event); - return ui::EVENT_REWRITE_REWRITTEN; + return SendEventFinally(continuation, new_event.get()); } // Otherwise just pass it through. - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } current_touch_ids_.erase(it); @@ -163,12 +163,12 @@ // Can happen if touch exploration is enabled while fingers were down. if (it == current_touch_ids_.end()) - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); touch_locations_[*it] = gfx::PointF(location); } else { NOTREACHED() << "Unexpected event type received: " << event.GetName(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } DVLOG_EVENT(touch_event); @@ -185,7 +185,7 @@ DVLOG(1) << "Reset to no fingers in Rewrite event because the touch " "release or cancel was on the edge of the screen."; } - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } } @@ -208,102 +208,83 @@ ProcessGestureEvents(); } - ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE; // The rest of the processing depends on what state we're in. switch (state_) { case NO_FINGERS_DOWN: - status = InNoFingersDown(touch_event_dip, rewritten_event); - break; + return InNoFingersDown(touch_event_dip, continuation); case SINGLE_TAP_PRESSED: - status = InSingleTapPressed(touch_event_dip, rewritten_event); - break; + return InSingleTapPressed(touch_event_dip, continuation); case SINGLE_TAP_RELEASED: case TOUCH_EXPLORE_RELEASED: - status = - InSingleTapOrTouchExploreReleased(touch_event_dip, rewritten_event); - break; + return InSingleTapOrTouchExploreReleased(touch_event_dip, continuation); case DOUBLE_TAP_PENDING: - status = InDoubleTapPending(touch_event_dip, rewritten_event); - break; + return InDoubleTapPending(touch_event_dip, continuation); case TOUCH_RELEASE_PENDING: - status = InTouchReleasePending(touch_event_dip, rewritten_event); - break; + return InTouchReleasePending(touch_event_dip, continuation); case TOUCH_EXPLORATION: - status = InTouchExploration(touch_event_dip, rewritten_event); - break; + return InTouchExploration(touch_event_dip, continuation); case GESTURE_IN_PROGRESS: - status = InGestureInProgress(touch_event_dip, rewritten_event); - break; + return InGestureInProgress(touch_event_dip, continuation); case TOUCH_EXPLORE_SECOND_PRESS: - status = InTouchExploreSecondPress(touch_event_dip, rewritten_event); - break; + return InTouchExploreSecondPress(touch_event_dip, continuation); case ONE_FINGER_PASSTHROUGH: - status = InOneFingerPassthrough(touch_event_dip, rewritten_event); - break; + return InOneFingerPassthrough(touch_event_dip, continuation); case WAIT_FOR_NO_FINGERS: - status = InWaitForNoFingers(touch_event_dip, rewritten_event); - break; + return InWaitForNoFingers(touch_event_dip, continuation); case TWO_FINGER_TAP: - status = InTwoFingerTap(touch_event_dip, rewritten_event); - break; + return InTwoFingerTap(touch_event_dip, continuation); } - if (status == ui::EVENT_REWRITE_REWRITTEN) { - DCHECK(rewritten_event->get()); - SetTouchAccessibilityFlag(rewritten_event->get()); - } - return status; -} - -ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) { NOTREACHED(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } -ui::EventRewriteStatus TouchExplorationController::InNoFingersDown( +ui::EventDispatchDetails TouchExplorationController::InNoFingersDown( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { const ui::EventType type = event.type(); if (type != ui::ET_TOUCH_PRESSED) { NOTREACHED() << "Unexpected event type received: " << event.GetName(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } initial_press_ = std::make_unique<ui::TouchEvent>(event); + initial_press_continuation_ = continuation; most_recent_press_timestamp_ = initial_press_->time_stamp(); initial_presses_[event.pointer_details().id] = event.location(); last_unused_finger_event_ = std::make_unique<ui::TouchEvent>(event); + last_unused_finger_continuation_ = continuation; StartTapTimer(); SET_STATE(SINGLE_TAP_PRESSED); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } -ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed( +ui::EventDispatchDetails TouchExplorationController::InSingleTapPressed( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { const ui::EventType type = event.type(); if (type == ui::ET_TOUCH_PRESSED) { initial_presses_[event.pointer_details().id] = event.location(); SET_STATE(TWO_FINGER_TAP); - return ui::EVENT_REWRITE_DISCARD; - } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { + return DiscardEvent(continuation); + } + if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { if (current_touch_ids_.size() == 0 && event.pointer_details().id == initial_press_->pointer_details().id) { - MaybeSendSimulatedTapInLiftActivationBounds(event); + MaybeSendSimulatedTapInLiftActivationBounds(event, continuation); SET_STATE(SINGLE_TAP_RELEASED); } else if (current_touch_ids_.size() == 0) { SET_STATE(NO_FINGERS_DOWN); } - return ui::EVENT_REWRITE_DISCARD; - } else if (type == ui::ET_TOUCH_MOVED) { + return DiscardEvent(continuation); + } + if (type == ui::ET_TOUCH_MOVED) { float distance = (event.location() - initial_press_->location()).Length(); // If the user does not move far enough from the original position, then the // resulting movement should not be considered to be a deliberate gesture or // touch exploration. if (distance <= gesture_detector_config_.touch_slop) - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); float delta_time = (event.time_stamp() - most_recent_press_timestamp_).InSecondsF(); @@ -319,27 +300,27 @@ // gesture detection. Otherwise, jump to the touch exploration mode early. if (velocity > gesture_detector_config_.minimum_swipe_velocity) { SET_STATE(GESTURE_IN_PROGRESS); - return InGestureInProgress(event, rewritten_event); + return InGestureInProgress(event, continuation); } anchor_point_state_ = ANCHOR_POINT_FROM_TOUCH_EXPLORATION; EnterTouchToMouseMode(); SET_STATE(TOUCH_EXPLORATION); - return InTouchExploration(event, rewritten_event); + return InTouchExploration(event, continuation); } NOTREACHED(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } -ui::EventRewriteStatus +ui::EventDispatchDetails TouchExplorationController::InSingleTapOrTouchExploreReleased( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { const ui::EventType type = event.type(); // If there is more than one finger down, then discard to wait until no // fingers are down. if (current_touch_ids_.size() > 1) { SET_STATE(WAIT_FOR_NO_FINGERS); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } if (type == ui::ET_TOUCH_PRESSED) { // If there is no anchor point for synthesized events because the @@ -347,7 +328,7 @@ // send a click, so discard. if (anchor_point_state_ == ANCHOR_POINT_NONE) { tap_timer_.Stop(); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // This is the second tap in a double-tap (or double tap-hold). // We set the tap timer. If it fires before the user lifts their finger, @@ -362,29 +343,33 @@ // This will update as the finger moves before a possible passthrough, and // will determine the offset. last_unused_finger_event_.reset(new ui::TouchEvent(event)); - return ui::EVENT_REWRITE_DISCARD; - } else if (type == ui::ET_TOUCH_RELEASED && - anchor_point_state_ == ANCHOR_POINT_NONE) { + last_unused_finger_continuation_ = continuation; + return DiscardEvent(continuation); + } + if (type == ui::ET_TOUCH_RELEASED && + anchor_point_state_ == ANCHOR_POINT_NONE) { // If the previous press was discarded, we need to also handle its // release. if (current_touch_ids_.size() == 0) { SET_STATE(NO_FINGERS_DOWN); } - return ui::EVENT_REWRITE_DISCARD; - } else if (type == ui::ET_TOUCH_MOVED) { - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); + } + if (type == ui::ET_TOUCH_MOVED) { + return DiscardEvent(continuation); } NOTREACHED(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } -ui::EventRewriteStatus TouchExplorationController::InDoubleTapPending( +ui::EventDispatchDetails TouchExplorationController::InDoubleTapPending( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { const ui::EventType type = event.type(); if (type == ui::ET_TOUCH_PRESSED) { - return ui::EVENT_REWRITE_DISCARD; - } else if (type == ui::ET_TOUCH_MOVED) { + return DiscardEvent(continuation); + } + if (type == ui::ET_TOUCH_MOVED) { // If the user moves far enough from the initial touch location (outside // the "slop" region, jump to passthrough mode early. float delta = (event.location() - initial_press_->location()).Length(); @@ -392,74 +377,80 @@ tap_timer_.Stop(); OnTapTimerFired(); } - return ui::EVENT_REWRITE_DISCARD; - } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { + return DiscardEvent(continuation); + } + if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { if (current_touch_ids_.size() != 0) - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); - SendSimulatedClickOrTap(); + SendSimulatedClickOrTap(continuation); SET_STATE(NO_FINGERS_DOWN); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } NOTREACHED(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } -ui::EventRewriteStatus TouchExplorationController::InTouchReleasePending( +ui::EventDispatchDetails TouchExplorationController::InTouchReleasePending( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { const ui::EventType type = event.type(); if (type == ui::ET_TOUCH_PRESSED || type == ui::ET_TOUCH_MOVED) { - return ui::EVENT_REWRITE_DISCARD; - } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { + return DiscardEvent(continuation); + } + if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { if (current_touch_ids_.size() != 0) - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); - SendSimulatedClickOrTap(); + SendSimulatedClickOrTap(continuation); SET_STATE(NO_FINGERS_DOWN); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } NOTREACHED(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } -ui::EventRewriteStatus TouchExplorationController::InTouchExploration( +ui::EventDispatchDetails TouchExplorationController::InTouchExploration( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { const ui::EventType type = event.type(); if (type == ui::ET_TOUCH_PRESSED) { // Enter split-tap mode. initial_press_ = std::make_unique<ui::TouchEvent>(event); tap_timer_.Stop(); + initial_press_continuation_ = continuation; SET_STATE(TOUCH_EXPLORE_SECOND_PRESS); - return ui::EVENT_REWRITE_DISCARD; - } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { + return DiscardEvent(continuation); + } + if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { initial_press_ = std::make_unique<ui::TouchEvent>(event); + initial_press_continuation_ = continuation; StartTapTimer(); most_recent_press_timestamp_ = event.time_stamp(); - MaybeSendSimulatedTapInLiftActivationBounds(event); + MaybeSendSimulatedTapInLiftActivationBounds(event, continuation); SET_STATE(TOUCH_EXPLORE_RELEASED); } else if (type != ui::ET_TOUCH_MOVED) { NOTREACHED(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } // Rewrite as a mouse-move event. // |event| locations are in DIP; see |RewriteEvent|. We need to dispatch // |screen coords. gfx::PointF location_f(ConvertDIPToScreenInPixels(event.location_f())); - *rewritten_event = CreateMouseMoveEvent(location_f, event.flags()); + std::unique_ptr<ui::Event> new_event = + CreateMouseMoveEvent(location_f, event.flags()); + SetTouchAccessibilityFlag(new_event.get()); last_touch_exploration_ = std::make_unique<ui::TouchEvent>(event); if (anchor_point_state_ != ANCHOR_POINT_EXPLICITLY_SET) anchor_point_dip_ = last_touch_exploration_->location_f(); - - return ui::EVENT_REWRITE_REWRITTEN; + return SendEventFinally(continuation, new_event.get()); } -ui::EventRewriteStatus TouchExplorationController::InGestureInProgress( +ui::EventDispatchDetails TouchExplorationController::InGestureInProgress( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { // The events were sent to the gesture provider in RewriteEvent already. // If no gesture is registered before the tap timer times out, the state // will change to "wait for no fingers down" or "touch exploration" depending @@ -467,57 +458,56 @@ if (current_touch_ids_.size() == 0) { SET_STATE(NO_FINGERS_DOWN); } - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } -ui::EventRewriteStatus TouchExplorationController::InOneFingerPassthrough( +ui::EventDispatchDetails TouchExplorationController::InOneFingerPassthrough( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { if (event.pointer_details().id != initial_press_->pointer_details().id) { if (current_touch_ids_.size() == 0) { SET_STATE(NO_FINGERS_DOWN); } - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // |event| locations are in DIP; see |RewriteEvent|. We need to dispatch // screen coordinates. gfx::PointF location_f( ConvertDIPToScreenInPixels(event.location_f() - passthrough_offset_)); - std::unique_ptr<ui::TouchEvent> new_event(new ui::TouchEvent( - event.type(), gfx::Point(), event.time_stamp(), event.pointer_details())); - new_event->set_location_f(location_f); - new_event->set_root_location_f(location_f); - new_event->set_flags(event.flags()); - *rewritten_event = std::move(new_event); + ui::TouchEvent new_event(event.type(), gfx::Point(), event.time_stamp(), + event.pointer_details(), event.flags()); + new_event.set_location_f(location_f); + new_event.set_root_location_f(location_f); + SetTouchAccessibilityFlag(&new_event); if (current_touch_ids_.size() == 0) { SET_STATE(NO_FINGERS_DOWN); } - return ui::EVENT_REWRITE_REWRITTEN; + return SendEventFinally(continuation, &new_event); } -ui::EventRewriteStatus TouchExplorationController::InTouchExploreSecondPress( +ui::EventDispatchDetails TouchExplorationController::InTouchExploreSecondPress( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { ui::EventType type = event.type(); if (type == ui::ET_TOUCH_PRESSED) { // A third finger being pressed means that a split tap can no longer go // through. The user enters the wait state, Since there has already been // a press dispatched when split tap began, the touch needs to be // cancelled. - std::unique_ptr<ui::TouchEvent> new_event(new ui::TouchEvent( - ui::ET_TOUCH_CANCELLED, gfx::Point(), event.time_stamp(), - initial_press_->pointer_details())); + ui::TouchEvent new_event(ui::ET_TOUCH_CANCELLED, gfx::Point(), + event.time_stamp(), + initial_press_->pointer_details(), event.flags()); // TODO(dmazzoni): fix for multiple displays. http://crbug.com/616793 // |event| locations are in DIP; see |RewriteEvent|. We need to dispatch // screen coordinates. gfx::PointF location_f(ConvertDIPToScreenInPixels(anchor_point_dip_)); - new_event->set_location_f(location_f); - new_event->set_root_location_f(location_f); - new_event->set_flags(event.flags()); - *rewritten_event = std::move(new_event); + new_event.set_location_f(location_f); + new_event.set_root_location_f(location_f); + SetTouchAccessibilityFlag(&new_event); SET_STATE(WAIT_FOR_NO_FINGERS); - return ui::EVENT_REWRITE_REWRITTEN; - } else if (type == ui::ET_TOUCH_MOVED) { + return SendEventFinally(continuation, &new_event); + } + if (type == ui::ET_TOUCH_MOVED) { // If the fingers have moved too far from their original locations, // the user can no longer split tap. ui::TouchEvent* original_touch; @@ -530,7 +520,7 @@ } else { NOTREACHED(); SET_STATE(WAIT_FOR_NO_FINGERS); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // Check the distance between the current finger location and the original // location. The slop for this is a bit more generous since keeping two @@ -540,41 +530,44 @@ GetSplitTapTouchSlop()) { SET_STATE(WAIT_FOR_NO_FINGERS); } - return ui::EVENT_REWRITE_DISCARD; - } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { + return DiscardEvent(continuation); + } + if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { // If the touch exploration finger is lifted, there is no option to return // to touch explore anymore. The remaining finger acts as a pending // tap or long tap for the last touch explore location. if (event.pointer_details().id == last_touch_exploration_->pointer_details().id) { SET_STATE(TOUCH_RELEASE_PENDING); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // Continue to release the touch only if the touch explore finger is the // only finger remaining. - if (current_touch_ids_.size() != 1) - return ui::EVENT_REWRITE_DISCARD; + if (current_touch_ids_.size() != 1) { + return DiscardEvent(continuation); + } - SendSimulatedClickOrTap(); + SendSimulatedClickOrTap(continuation); SET_STATE(TOUCH_EXPLORATION); EnterTouchToMouseMode(); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } NOTREACHED(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } -ui::EventRewriteStatus TouchExplorationController::InWaitForNoFingers( +ui::EventDispatchDetails TouchExplorationController::InWaitForNoFingers( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { if (current_touch_ids_.size() == 0) SET_STATE(NO_FINGERS_DOWN); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } -void TouchExplorationController::SendSimulatedClickOrTap() { +void TouchExplorationController::SendSimulatedClickOrTap( + const Continuation continuation) { // If we got an anchor point from ChromeVox, send a double-tap gesture // and let ChromeVox handle the click. const gfx::Point location; @@ -583,17 +576,18 @@ delegate_->HandleAccessibilityGesture(ax::mojom::Gesture::kClick); return; } - SendSimulatedTap(); + SendSimulatedTap(continuation); } -void TouchExplorationController::SendSimulatedTap() { +void TouchExplorationController::SendSimulatedTap( + const Continuation continuation) { std::unique_ptr<ui::TouchEvent> touch_press; touch_press.reset(new ui::TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(), Now(), initial_press_->pointer_details())); touch_press->set_location_f(anchor_point_dip_); touch_press->set_root_location_f(anchor_point_dip_); - DispatchEvent(touch_press.get()); + DispatchEvent(touch_press.get(), continuation); std::unique_ptr<ui::TouchEvent> touch_release; touch_release.reset(new ui::TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(), @@ -601,29 +595,30 @@ initial_press_->pointer_details())); touch_release->set_location_f(anchor_point_dip_); touch_release->set_root_location_f(anchor_point_dip_); - DispatchEvent(touch_release.get()); + DispatchEvent(touch_release.get(), continuation); } void TouchExplorationController::MaybeSendSimulatedTapInLiftActivationBounds( - const ui::TouchEvent& event) { + const ui::TouchEvent& event, + const Continuation continuation) { gfx::Point location = event.location(); gfx::Point anchor_location(anchor_point_dip_.x(), anchor_point_dip_.y()); if (lift_activation_bounds_.Contains(anchor_location.x(), anchor_location.y()) && lift_activation_bounds_.Contains(location)) { accessibility_sound_player_->PlayTouchTypeEarcon(); - SendSimulatedTap(); + SendSimulatedTap(continuation); } } -ui::EventRewriteStatus TouchExplorationController::InTwoFingerTap( +ui::EventDispatchDetails TouchExplorationController::InTwoFingerTap( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { ui::EventType type = event.type(); if (type == ui::ET_TOUCH_PRESSED) { // This is now a three finger gesture. SET_STATE(GESTURE_IN_PROGRESS); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } if (type == ui::ET_TOUCH_MOVED) { @@ -635,18 +630,19 @@ if (distance > gesture_detector_config_.touch_slop) { SET_STATE(GESTURE_IN_PROGRESS); } - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } - if (current_touch_ids_.size() != 0) - return ui::EVENT_REWRITE_DISCARD; + if (current_touch_ids_.size() != 0) { + return DiscardEvent(continuation); + } if (type == ui::ET_TOUCH_RELEASED) { delegate_->HandleAccessibilityGesture(ax::mojom::Gesture::kTap2); SET_STATE(NO_FINGERS_DOWN); - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } base::TimeTicks TouchExplorationController::Now() { @@ -679,7 +675,7 @@ last_unused_finger_event_->pointer_details())); passthrough_press->set_location_f(anchor_point_dip_); passthrough_press->set_root_location_f(anchor_point_dip_); - DispatchEvent(passthrough_press.get()); + DispatchEvent(passthrough_press.get(), last_unused_finger_continuation_); return; } case SINGLE_TAP_PRESSED: @@ -703,13 +699,15 @@ EnterTouchToMouseMode(); std::unique_ptr<ui::Event> mouse_move = CreateMouseMoveEvent( initial_press_->location_f(), initial_press_->flags()); - DispatchEvent(mouse_move.get()); + DispatchEvent(mouse_move.get(), initial_press_continuation_); last_touch_exploration_ = std::make_unique<ui::TouchEvent>(*initial_press_); anchor_point_dip_ = last_touch_exploration_->location_f(); anchor_point_state_ = ANCHOR_POINT_FROM_TOUCH_EXPLORATION; } -void TouchExplorationController::DispatchEvent(ui::Event* event) { +void TouchExplorationController::DispatchEvent( + ui::Event* event, + const Continuation continuation) { SetTouchAccessibilityFlag(event); if (event->IsLocatedEvent()) { ui::LocatedEvent* located_event = event->AsLocatedEvent(); @@ -718,8 +716,9 @@ located_event->set_location_f(screen_point); located_event->set_root_location_f(screen_point); } - ignore_result( - root_window_->GetHost()->dispatcher()->OnEventFromSource(event)); + if (SendEventFinally(continuation, event).dispatcher_destroyed) { + VLOG(0) << "Undispatched event due to destroyed dispatcher."; + } } // This is an override for a function that is only called for timer-based events @@ -874,11 +873,12 @@ void TouchExplorationController::DispatchKeyWithFlags( const ui::KeyboardCode key, - int flags) { + int flags, + const Continuation continuation) { ui::KeyEvent key_down(ui::ET_KEY_PRESSED, key, flags); ui::KeyEvent key_up(ui::ET_KEY_RELEASED, key, flags); - DispatchEvent(&key_down); - DispatchEvent(&key_up); + DispatchEvent(&key_down, continuation); + DispatchEvent(&key_up, continuation); if (DVLOG_on_) { DVLOG(1) << "\nKey down: key code : " << key_down.key_code() << ", flags: " << key_down.flags() @@ -889,9 +889,10 @@ base::OnceClosure TouchExplorationController::BindKeyEventWithFlags( const ui::KeyboardCode key, - int flags) { + int flags, + const Continuation continuation) { return base::BindOnce(&TouchExplorationController::DispatchKeyWithFlags, - base::Unretained(this), key, flags); + base::Unretained(this), key, flags, continuation); } std::unique_ptr<ui::MouseEvent>
diff --git a/chromecast/browser/accessibility/touch_exploration_controller.h b/chromecast/browser/accessibility/touch_exploration_controller.h index 2882e958..2ef33f6 100644 --- a/chromecast/browser/accessibility/touch_exploration_controller.h +++ b/chromecast/browser/accessibility/touch_exploration_controller.h
@@ -8,6 +8,10 @@ #ifndef CHROMECAST_BROWSER_ACCESSIBILITY_TOUCH_EXPLORATION_CONTROLLER_H_ #define CHROMECAST_BROWSER_ACCESSIBILITY_TOUCH_EXPLORATION_CONTROLLER_H_ +#include <map> +#include <memory> +#include <vector> + #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/timer/timer.h" @@ -181,50 +185,40 @@ void SetExcludeBounds(const gfx::Rect& bounds); // Overridden from ui::EventRewriter - ui::EventRewriteStatus RewriteEvent( + ui::EventDispatchDetails RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) override; - ui::EventRewriteStatus NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) override; + const Continuation continuation) override; private: friend class TouchExplorationControllerTestApi; // Event handlers based on the current state - see State, below. - ui::EventRewriteStatus InNoFingersDown( + ui::EventDispatchDetails InNoFingersDown(const ui::TouchEvent& event, + const Continuation continuation); + ui::EventDispatchDetails InSingleTapPressed(const ui::TouchEvent& event, + const Continuation continuation); + ui::EventDispatchDetails InSingleTapOrTouchExploreReleased( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InSingleTapPressed( + const Continuation continuation); + ui::EventDispatchDetails InDoubleTapPending(const ui::TouchEvent& event, + const Continuation continuation); + ui::EventDispatchDetails InTouchReleasePending( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InSingleTapOrTouchExploreReleased( + const Continuation continuation); + ui::EventDispatchDetails InTouchExploration(const ui::TouchEvent& event, + const Continuation continuation); + ui::EventDispatchDetails InOneFingerPassthrough( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InDoubleTapPending( + const Continuation continuation); + ui::EventDispatchDetails InGestureInProgress(const ui::TouchEvent& event, + const Continuation continuation); + ui::EventDispatchDetails InTouchExploreSecondPress( const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InTouchReleasePending( - const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InTouchExploration( - const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InOneFingerPassthrough( - const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InGestureInProgress( - const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InTouchExploreSecondPress( - const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InWaitForNoFingers( - const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); - ui::EventRewriteStatus InTwoFingerTap( - const ui::TouchEvent& event, - std::unique_ptr<ui::Event>* rewritten_event); + const Continuation continuation); + ui::EventDispatchDetails InWaitForNoFingers(const ui::TouchEvent& event, + const Continuation continuation); + ui::EventDispatchDetails InTwoFingerTap(const ui::TouchEvent& event, + const Continuation continuation); // Returns the current time of the tick clock. base::TimeTicks Now(); @@ -237,7 +231,7 @@ void OnTapTimerFired(); // Dispatch a new event outside of the event rewriting flow. - void DispatchEvent(ui::Event* event); + void DispatchEvent(ui::Event* event, const Continuation continuation); // Overridden from GestureProviderAuraClient. // @@ -254,11 +248,14 @@ void OnSwipeEvent(ui::GestureEvent* swipe_gesture); // Dispatches a single key with the given flags. - void DispatchKeyWithFlags(const ui::KeyboardCode key, int flags); + void DispatchKeyWithFlags(const ui::KeyboardCode key, + int flags, + const Continuation continuation); // Binds DispatchKeyWithFlags to a specific key and flags. base::OnceClosure BindKeyEventWithFlags(const ui::KeyboardCode key, - int flags); + int flags, + const Continuation continuation); std::unique_ptr<ui::MouseEvent> CreateMouseMoveEvent( const gfx::PointF& location, @@ -270,20 +267,22 @@ // Sends a simulated click, if an anchor point was set explicitly. Otherwise, // sends a simulated tap at anchor point. - void SendSimulatedClickOrTap(); + void SendSimulatedClickOrTap(const Continuation continuation); // Sends a simulated tap at anchor point. - void SendSimulatedTap(); + void SendSimulatedTap(const Continuation continuation); // Sends a simulated tap, if the anchor point falls within lift activation // bounds. - void MaybeSendSimulatedTapInLiftActivationBounds(const ui::TouchEvent& event); + void MaybeSendSimulatedTapInLiftActivationBounds( + const ui::TouchEvent& event, + const Continuation continuation); // Some constants used in touch_exploration_controller: // Within this many dips of the screen edge, the release event generated will // reset the state to NoFingersDown. - // TODO: Unify with identical value in CastSystemGestureEventHandler. + // TODO(kpschoedel): Unify with identical value in SideSwipeDetector. const float kLeavingScreenEdge = 35; // Touch within this distance from a corner can invoke corner passthrough. @@ -427,6 +426,7 @@ // A copy of the event from the initial touch press. std::unique_ptr<ui::TouchEvent> initial_press_; + Continuation initial_press_continuation_; // The timestamp of the most recent press event for the main touch id. // The difference between this and |initial_press_->time_stamp| is that @@ -445,6 +445,7 @@ // sending events through, but might in the future (e.g. before a finger // enters double-tap-hold passthrough, we need to update its location.) std::unique_ptr<ui::TouchEvent> last_unused_finger_event_; + Continuation last_unused_finger_continuation_; // The anchor point used as the location of a synthesized tap when the // user double-taps anywhere on the screen, and similarly the initial
diff --git a/chromecast/browser/accessibility/touch_exploration_manager.cc b/chromecast/browser/accessibility/touch_exploration_manager.cc index b1d34cb..a9e80f99 100644 --- a/chromecast/browser/accessibility/touch_exploration_manager.cc +++ b/chromecast/browser/accessibility/touch_exploration_manager.cc
@@ -7,6 +7,9 @@ #include "chromecast/browser/accessibility/touch_exploration_manager.h" +#include <utility> +#include <vector> + #include "chromecast/browser/cast_browser_context.h" #include "chromecast/browser/cast_browser_process.h" #include "chromecast/common/extensions_api/accessibility_private.h" @@ -47,23 +50,12 @@ UpdateTouchExplorationState(); } -ui::EventRewriteStatus TouchExplorationManager::RewriteEvent( +ui::EventDispatchDetails TouchExplorationManager::RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) { - if (touch_exploration_controller_) { - return touch_exploration_controller_->RewriteEvent(event, rewritten_event); - } - return ui::EVENT_REWRITE_CONTINUE; -} - -ui::EventRewriteStatus TouchExplorationManager::NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) { - if (touch_exploration_controller_) { - return touch_exploration_controller_->NextDispatchEvent(last_event, - new_event); - } - return ui::EVENT_REWRITE_CONTINUE; + const Continuation continuation) { + return touch_exploration_controller_ + ? touch_exploration_controller_->RewriteEvent(event, continuation) + : SendEvent(continuation, &event); } void TouchExplorationManager::HandleAccessibilityGesture( @@ -120,8 +112,7 @@ } if (pass_through_surface) { const display::Display display = - display::Screen::GetScreen()->GetDisplayNearestWindow( - root_window_); + display::Screen::GetScreen()->GetDisplayNearestWindow(root_window_); const gfx::Rect work_area = display.work_area(); touch_exploration_controller_->SetExcludeBounds(work_area); // Clear the focus highlight.
diff --git a/chromecast/browser/accessibility/touch_exploration_manager.h b/chromecast/browser/accessibility/touch_exploration_manager.h index 7217e712..54d25c2b 100644 --- a/chromecast/browser/accessibility/touch_exploration_manager.h +++ b/chromecast/browser/accessibility/touch_exploration_manager.h
@@ -8,6 +8,8 @@ #ifndef CHROMECAST_BROWSER_ACCESSIBILITY_TOUCH_EXPLORATION_MANAGER_H_ #define CHROMECAST_BROWSER_ACCESSIBILITY_TOUCH_EXPLORATION_MANAGER_H_ +#include <memory> + #include "chromecast/browser/accessibility/accessibility_sound_player.h" #include "chromecast/browser/accessibility/touch_exploration_controller.h" #include "chromecast/graphics/accessibility/accessibility_focus_ring_controller.h" @@ -41,12 +43,9 @@ void Enable(bool enabled); // ui::EventRewriter overrides: - ui::EventRewriteStatus RewriteEvent( + ui::EventDispatchDetails RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) override; - ui::EventRewriteStatus NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) override; + const Continuation continuation) override; // TouchExplorationControllerDelegate overrides: void HandleAccessibilityGesture(ax::mojom::Gesture gesture) override;
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc index f213cf3..2d9c5e5 100644 --- a/chromecast/browser/cast_browser_main_parts.cc +++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -119,7 +119,6 @@ #if BUILDFLAG(ENABLE_CAST_WAYLAND_SERVER) #include "chromecast/browser/exo/wayland_server_controller.h" -#include "chromecast/browser/exo/wm_helper_cast_shell.h" #endif #if !defined(OS_ANDROID) && !defined(OS_FUCHSIA) @@ -577,7 +576,8 @@ extensions_browser_client_ = std::make_unique<extensions::CastExtensionsBrowserClient>( - cast_browser_process_->browser_context(), user_pref_service_.get()); + cast_browser_process_->browser_context(), user_pref_service_.get(), + cast_content_browser_client_->cast_network_contexts()); extensions::ExtensionsBrowserClient::Set(extensions_browser_client_.get()); extensions::EnsureBrowserContextKeyedServiceFactoriesBuilt();
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index 1863115..dc18542 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -212,7 +212,8 @@ CastContentBrowserClient::CastContentBrowserClient( CastFeatureListCreator* cast_feature_list_creator) : cast_browser_main_parts_(nullptr), - cast_network_contexts_(std::make_unique<CastNetworkContexts>()), + cast_network_contexts_( + std::make_unique<CastNetworkContexts>(GetCorsExemptHeadersList())), url_request_context_factory_(new URLRequestContextFactory()), cast_feature_list_creator_(cast_feature_list_creator) { cast_feature_list_creator_->SetExtraEnableFeatures({
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h index b429f74..9824e1b 100644 --- a/chromecast/browser/cast_content_browser_client.h +++ b/chromecast/browser/cast_content_browser_client.h
@@ -76,6 +76,11 @@ static std::unique_ptr<CastContentBrowserClient> Create( CastFeatureListCreator* cast_feature_list_creator); + // Returns a list of headers that will be exempt from CORS preflight checks. + // This is needed since currently servers don't have the correct response to + // preflight checks. + static std::vector<std::string> GetCorsExemptHeadersList(); + ~CastContentBrowserClient() override; // Creates and returns the CastService instance for the current process.
diff --git a/chromecast/browser/cast_content_browser_client_simple.cc b/chromecast/browser/cast_content_browser_client_simple.cc index 89d5f43..b3dfcba 100644 --- a/chromecast/browser/cast_content_browser_client_simple.cc +++ b/chromecast/browser/cast_content_browser_client_simple.cc
@@ -18,5 +18,10 @@ new CastContentBrowserClient(cast_feature_list_creator)); } +// static +std::vector<std::string> CastContentBrowserClient::GetCorsExemptHeadersList() { + return std::vector<std::string>(); +} + } // namespace shell } // namespace chromecast
diff --git a/chromecast/browser/cast_media_blocker.h b/chromecast/browser/cast_media_blocker.h index 861ae31..0e4476d7 100644 --- a/chromecast/browser/cast_media_blocker.h +++ b/chromecast/browser/cast_media_blocker.h
@@ -60,6 +60,8 @@ const base::flat_map<media_session::mojom::MediaSessionImageType, std::vector<media_session::MediaImage>>& images) override {} + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} private: friend shell::CastMediaBlockerTest;
diff --git a/chromecast/browser/cast_network_contexts.cc b/chromecast/browser/cast_network_contexts.cc index 9475983..f9e9f7f 100644 --- a/chromecast/browser/cast_network_contexts.cc +++ b/chromecast/browser/cast_network_contexts.cc
@@ -82,8 +82,10 @@ DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryForSystem); }; -CastNetworkContexts::CastNetworkContexts() - : system_shared_url_loader_factory_( +CastNetworkContexts::CastNetworkContexts( + std::vector<std::string> cors_exempt_headers_list) + : cors_exempt_headers_list_(std::move(cors_exempt_headers_list)), + system_shared_url_loader_factory_( base::MakeRefCounted<URLLoaderFactoryForSystem>(this)) {} CastNetworkContexts::~CastNetworkContexts() { @@ -208,6 +210,8 @@ AddProxyToNetworkContextParams(network_context_params.get()); + network_context_params->cors_exempt_header_list = cors_exempt_headers_list_; + return network_context_params; }
diff --git a/chromecast/browser/cast_network_contexts.h b/chromecast/browser/cast_network_contexts.h index 1c86cfab..2f356f1 100644 --- a/chromecast/browser/cast_network_contexts.h +++ b/chromecast/browser/cast_network_contexts.h
@@ -6,6 +6,8 @@ #define CHROMECAST_BROWSER_CAST_NETWORK_CONTEXTS_H_ #include <memory> +#include <string> +#include <vector> #include "base/memory/scoped_refptr.h" #include "content/public/browser/browser_thread.h" @@ -44,7 +46,8 @@ class CastNetworkContexts : public net::ProxyConfigService::Observer, public network::mojom::ProxyConfigPollerClient { public: - CastNetworkContexts(); + explicit CastNetworkContexts( + std::vector<std::string> cors_exempt_headers_list); ~CastNetworkContexts() override; // Returns the System NetworkContext. Does any initialization of the @@ -103,6 +106,8 @@ // network::mojom::ProxyConfigPollerClient implementation: void OnLazyProxyConfigPoll() override; + const std::vector<std::string> cors_exempt_headers_list_; + // The system NetworkContext. network::mojom::NetworkContextPtr system_network_context_;
diff --git a/chromecast/browser/exo/wm_helper_cast_shell.cc b/chromecast/browser/exo/cast_wm_helper.cc similarity index 64% rename from chromecast/browser/exo/wm_helper_cast_shell.cc rename to chromecast/browser/exo/cast_wm_helper.cc index 61c54d4..4d022dc2 100644 --- a/chromecast/browser/exo/wm_helper_cast_shell.cc +++ b/chromecast/browser/exo/cast_wm_helper.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromecast/browser/exo/wm_helper_cast_shell.h" +#include "chromecast/browser/exo/cast_wm_helper.h" #include "base/memory/singleton.h" #include "chromecast/browser/cast_browser_process.h" @@ -46,7 +46,7 @@ } // namespace -WMHelperCastShell::WMHelperCastShell( +CastWMHelper::CastWMHelper( chromecast::CastWindowManagerAura* cast_window_manager_aura, chromecast::CastScreen* cast_screen) : cast_window_manager_aura_(cast_window_manager_aura), @@ -55,66 +55,66 @@ cast_screen_->AddObserver(&display_observer_); } -WMHelperCastShell::~WMHelperCastShell() { +CastWMHelper::~CastWMHelper() { cast_screen_->RemoveObserver(&display_observer_); } -void WMHelperCastShell::AddActivationObserver( +void CastWMHelper::AddActivationObserver( wm::ActivationChangeObserver* observer) { NOTIMPLEMENTED(); } -void WMHelperCastShell::RemoveActivationObserver( +void CastWMHelper::RemoveActivationObserver( wm::ActivationChangeObserver* observer) { NOTIMPLEMENTED(); } -void WMHelperCastShell::AddFocusObserver( +void CastWMHelper::AddFocusObserver( aura::client::FocusChangeObserver* observer) { NOTIMPLEMENTED(); } -void WMHelperCastShell::RemoveFocusObserver( +void CastWMHelper::RemoveFocusObserver( aura::client::FocusChangeObserver* observer) { NOTIMPLEMENTED(); } -void WMHelperCastShell::AddDragDropObserver(DragDropObserver* observer) { +void CastWMHelper::AddDragDropObserver(DragDropObserver* observer) { NOTIMPLEMENTED(); } -void WMHelperCastShell::RemoveDragDropObserver(DragDropObserver* observer) { +void CastWMHelper::RemoveDragDropObserver(DragDropObserver* observer) { NOTIMPLEMENTED(); } -void WMHelperCastShell::SetDragDropDelegate(aura::Window* window) { +void CastWMHelper::SetDragDropDelegate(aura::Window* window) { aura::client::SetDragDropDelegate(window, this); } -void WMHelperCastShell::ResetDragDropDelegate(aura::Window* window) { +void CastWMHelper::ResetDragDropDelegate(aura::Window* window) { aura::client::SetDragDropDelegate(window, nullptr); } -VSyncTimingManager& WMHelperCastShell::GetVSyncTimingManager() { +VSyncTimingManager& CastWMHelper::GetVSyncTimingManager() { return vsync_timing_manager_; } -void WMHelperCastShell::OnDragEntered(const ui::DropTargetEvent& event) {} +void CastWMHelper::OnDragEntered(const ui::DropTargetEvent& event) {} -int WMHelperCastShell::OnDragUpdated(const ui::DropTargetEvent& event) { +int CastWMHelper::OnDragUpdated(const ui::DropTargetEvent& event) { NOTIMPLEMENTED(); return 0; } -void WMHelperCastShell::OnDragExited() {} +void CastWMHelper::OnDragExited() {} -int WMHelperCastShell::OnPerformDrop(const ui::DropTargetEvent& event, - std::unique_ptr<ui::OSExchangeData> data) { +int CastWMHelper::OnPerformDrop(const ui::DropTargetEvent& event, + std::unique_ptr<ui::OSExchangeData> data) { NOTIMPLEMENTED(); return ui::DragDropTypes::DRAG_MOVE; } -void WMHelperCastShell::AddVSyncParameterObserver( +void CastWMHelper::AddVSyncParameterObserver( viz::mojom::VSyncParameterObserverPtr observer) { cast_window_manager_aura_->GetRootWindow() ->layer() @@ -122,103 +122,103 @@ ->AddVSyncParameterObserver(std::move(observer)); } -const display::ManagedDisplayInfo& WMHelperCastShell::GetDisplayInfo( +const display::ManagedDisplayInfo& CastWMHelper::GetDisplayInfo( int64_t display_id) const { return display_observer_.GetDisplayInfo(display_id); } -const std::vector<uint8_t>& WMHelperCastShell::GetDisplayIdentificationData( +const std::vector<uint8_t>& CastWMHelper::GetDisplayIdentificationData( int64_t display_id) const { NOTIMPLEMENTED(); static std::vector<uint8_t> no_data; return no_data; } -bool WMHelperCastShell::GetActiveModeForDisplayId( +bool CastWMHelper::GetActiveModeForDisplayId( int64_t display_id, display::ManagedDisplayMode* mode) const { return display_observer_.GetActiveModeForDisplayId(display_id, mode); } -aura::Window* WMHelperCastShell::GetPrimaryDisplayContainer(int container_id) { +aura::Window* CastWMHelper::GetPrimaryDisplayContainer(int container_id) { return cast_window_manager_aura_->GetRootWindow(); } -aura::Window* WMHelperCastShell::GetActiveWindow() const { +aura::Window* CastWMHelper::GetActiveWindow() const { NOTIMPLEMENTED(); return nullptr; } -aura::Window* WMHelperCastShell::GetFocusedWindow() const { +aura::Window* CastWMHelper::GetFocusedWindow() const { NOTIMPLEMENTED(); return nullptr; } -aura::Window* WMHelperCastShell::GetRootWindowForNewWindows() const { +aura::Window* CastWMHelper::GetRootWindowForNewWindows() const { return cast_window_manager_aura_->GetRootWindow(); } -aura::client::CursorClient* WMHelperCastShell::GetCursorClient() { +aura::client::CursorClient* CastWMHelper::GetCursorClient() { NOTIMPLEMENTED(); return nullptr; } -void WMHelperCastShell::AddPreTargetHandler(ui::EventHandler* handler) { +void CastWMHelper::AddPreTargetHandler(ui::EventHandler* handler) { cast_window_manager_aura_->GetRootWindow()->AddPreTargetHandler(handler); } -void WMHelperCastShell::PrependPreTargetHandler(ui::EventHandler* handler) { +void CastWMHelper::PrependPreTargetHandler(ui::EventHandler* handler) { NOTIMPLEMENTED(); } -void WMHelperCastShell::RemovePreTargetHandler(ui::EventHandler* handler) { +void CastWMHelper::RemovePreTargetHandler(ui::EventHandler* handler) { cast_window_manager_aura_->GetRootWindow()->RemovePreTargetHandler(handler); } -void WMHelperCastShell::AddPostTargetHandler(ui::EventHandler* handler) { +void CastWMHelper::AddPostTargetHandler(ui::EventHandler* handler) { cast_window_manager_aura_->GetRootWindow()->AddPostTargetHandler(handler); } -void WMHelperCastShell::RemovePostTargetHandler(ui::EventHandler* handler) { +void CastWMHelper::RemovePostTargetHandler(ui::EventHandler* handler) { cast_window_manager_aura_->GetRootWindow()->RemovePostTargetHandler(handler); } -bool WMHelperCastShell::InTabletMode() const { +bool CastWMHelper::InTabletMode() const { NOTIMPLEMENTED(); return false; } -double WMHelperCastShell::GetDefaultDeviceScaleFactor() const { +double CastWMHelper::GetDefaultDeviceScaleFactor() const { NOTIMPLEMENTED(); return 1.0; } -void WMHelperCastShell::SetImeBlocked(aura::Window* window, bool ime_blocked) { +void CastWMHelper::SetImeBlocked(aura::Window* window, bool ime_blocked) { NOTIMPLEMENTED(); } -bool WMHelperCastShell::IsImeBlocked(aura::Window* window) const { +bool CastWMHelper::IsImeBlocked(aura::Window* window) const { NOTIMPLEMENTED(); return false; } -WMHelper::LifetimeManager* WMHelperCastShell::GetLifetimeManager() { +WMHelper::LifetimeManager* CastWMHelper::GetLifetimeManager() { return &lifetime_manager_; } -aura::client::CaptureClient* WMHelperCastShell::GetCaptureClient() { +aura::client::CaptureClient* CastWMHelper::GetCaptureClient() { return cast_window_manager_aura_->capture_client(); } -WMHelperCastShell::CastDisplayObserver::CastDisplayObserver() {} +CastWMHelper::CastDisplayObserver::CastDisplayObserver() {} -WMHelperCastShell::CastDisplayObserver::~CastDisplayObserver() {} +CastWMHelper::CastDisplayObserver::~CastDisplayObserver() {} -void WMHelperCastShell::CastDisplayObserver::OnWillProcessDisplayChanges() {} +void CastWMHelper::CastDisplayObserver::OnWillProcessDisplayChanges() {} -void WMHelperCastShell::CastDisplayObserver::OnDidProcessDisplayChanges() {} +void CastWMHelper::CastDisplayObserver::OnDidProcessDisplayChanges() {} -void WMHelperCastShell::CastDisplayObserver::OnDisplayAdded( +void CastWMHelper::CastDisplayObserver::OnDisplayAdded( const display::Display& new_display) { display::ManagedDisplayInfo md(new_display.id(), "CastDisplayInfo", true); md.SetRotation(new_display.rotation(), @@ -229,12 +229,12 @@ display_info_.emplace(new_display.id(), md); } -void WMHelperCastShell::CastDisplayObserver::OnDisplayRemoved( +void CastWMHelper::CastDisplayObserver::OnDisplayRemoved( const display::Display& old_display) { display_info_.erase(old_display.id()); } -void WMHelperCastShell::CastDisplayObserver::OnDisplayMetricsChanged( +void CastWMHelper::CastDisplayObserver::OnDisplayMetricsChanged( const display::Display& display, uint32_t changed_metrics) { if (display_info_.find(display.id()) == display_info_.end()) @@ -246,15 +246,14 @@ } const display::ManagedDisplayInfo& -WMHelperCastShell::CastDisplayObserver::GetDisplayInfo( - int64_t display_id) const { +CastWMHelper::CastDisplayObserver::GetDisplayInfo(int64_t display_id) const { auto iter = display_info_.find(display_id); DCHECK(iter != display_info_.end()) << "Failed to find display " << display_id; return iter->second; } -bool WMHelperCastShell::CastDisplayObserver::GetActiveModeForDisplayId( +bool CastWMHelper::CastDisplayObserver::GetActiveModeForDisplayId( int64_t display_id, display::ManagedDisplayMode* mode) const { auto iter = display_info_.find(display_id);
diff --git a/chromecast/browser/exo/wm_helper_cast_shell.h b/chromecast/browser/exo/cast_wm_helper.h similarity index 90% rename from chromecast/browser/exo/wm_helper_cast_shell.h rename to chromecast/browser/exo/cast_wm_helper.h index 206bac3..d79df9b 100644 --- a/chromecast/browser/exo/wm_helper_cast_shell.h +++ b/chromecast/browser/exo/cast_wm_helper.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROMECAST_BROWSER_EXO_WM_HELPER_CAST_SHELL_H_ -#define CHROMECAST_BROWSER_EXO_WM_HELPER_CAST_SHELL_H_ +#ifndef CHROMECAST_BROWSER_EXO_CAST_WM_HELPER_H_ +#define CHROMECAST_BROWSER_EXO_CAST_WM_HELPER_H_ #include <cstdint> #include <map> @@ -54,11 +54,11 @@ // A CastShell-specific helper class for accessing WindowManager related // features. -class WMHelperCastShell : public WMHelper, public VSyncTimingManager::Delegate { +class CastWMHelper : public WMHelper, public VSyncTimingManager::Delegate { public: - WMHelperCastShell(chromecast::CastWindowManagerAura* cast_window_manager_aura, - chromecast::CastScreen* cast_screen); - ~WMHelperCastShell() override; + CastWMHelper(chromecast::CastWindowManagerAura* cast_window_manager_aura, + chromecast::CastScreen* cast_screen); + ~CastWMHelper() override; // Overridden from WMHelper void AddActivationObserver(wm::ActivationChangeObserver* observer) override; @@ -139,9 +139,9 @@ LifetimeManager lifetime_manager_; VSyncTimingManager vsync_timing_manager_; - DISALLOW_COPY_AND_ASSIGN(WMHelperCastShell); + DISALLOW_COPY_AND_ASSIGN(CastWMHelper); }; } // namespace exo -#endif // CHROMECAST_BROWSER_EXO_WM_HELPER_CAST_SHELL_H_ +#endif // CHROMECAST_BROWSER_EXO_CAST_WM_HELPER_H_
diff --git a/chromecast/browser/exo/wayland_server_controller.cc b/chromecast/browser/exo/wayland_server_controller.cc index 85081c56..422207e4 100644 --- a/chromecast/browser/exo/wayland_server_controller.cc +++ b/chromecast/browser/exo/wayland_server_controller.cc
@@ -4,7 +4,7 @@ #include "chromecast/browser/exo/wayland_server_controller.h" -#include "chromecast/browser/exo/wm_helper_cast_shell.h" +#include "chromecast/browser/exo/cast_wm_helper.h" #include "chromecast/graphics/cast_screen.h" #include "components/exo/display.h" #include "components/exo/wayland/server.h" @@ -15,7 +15,7 @@ WaylandServerController::WaylandServerController( CastWindowManagerAura* window_manager) { - wm_helper_ = std::make_unique<exo::WMHelperCastShell>( + wm_helper_ = std::make_unique<exo::CastWMHelper>( window_manager, static_cast<CastScreen*>(CastScreen::GetScreen())); exo::WMHelper::SetInstance(wm_helper_.get()); display_ = std::make_unique<exo::Display>();
diff --git a/chromecast/browser/extensions/cast_extensions_browser_client.cc b/chromecast/browser/extensions/cast_extensions_browser_client.cc index 9b2e9ef..a2fec43 100644 --- a/chromecast/browser/extensions/cast_extensions_browser_client.cc +++ b/chromecast/browser/extensions/cast_extensions_browser_client.cc
@@ -10,6 +10,7 @@ #include "base/memory/ptr_util.h" #include "base/task/post_task.h" #include "build/build_config.h" +#include "chromecast/browser/cast_network_contexts.h" #include "chromecast/browser/extensions/cast_extension_host_delegate.h" #include "chromecast/browser/extensions/cast_extension_system_factory.h" #include "chromecast/browser/extensions/cast_extension_web_contents_observer.h" @@ -40,10 +41,13 @@ CastExtensionsBrowserClient::CastExtensionsBrowserClient( BrowserContext* context, - PrefService* pref_service) + PrefService* pref_service, + chromecast::shell::CastNetworkContexts* cast_network_contexts) : browser_context_(context), + cast_network_contexts_(cast_network_contexts), pref_service_(pref_service), api_client_(new CastExtensionsAPIClient) { + DCHECK(cast_network_contexts_); // Set to UNKNOWN to enable all APIs. // TODO(achaulk): figure out what channel to use here. SetCurrentChannel(version_info::Channel::UNKNOWN); @@ -54,6 +58,11 @@ CastExtensionsBrowserClient::~CastExtensionsBrowserClient() {} +network::mojom::NetworkContext* +CastExtensionsBrowserClient::GetSystemNetworkContext() { + return cast_network_contexts_->GetSystemContext(); +} + bool CastExtensionsBrowserClient::IsShuttingDown() { return false; }
diff --git a/chromecast/browser/extensions/cast_extensions_browser_client.h b/chromecast/browser/extensions/cast_extensions_browser_client.h index d51a63a4..2beaca0 100644 --- a/chromecast/browser/extensions/cast_extensions_browser_client.h +++ b/chromecast/browser/extensions/cast_extensions_browser_client.h
@@ -15,6 +15,12 @@ class PrefService; +namespace chromecast { +namespace shell { +class CastNetworkContexts; +} // namespace shell +} // namespace chromecast + namespace extensions { class ExtensionsAPIClient; @@ -25,11 +31,14 @@ public: // |context| is the single BrowserContext used for IsValidContext() below. // |pref_service| is used for GetPrefServiceForContext() below. - CastExtensionsBrowserClient(content::BrowserContext* context, - PrefService* pref_service); + CastExtensionsBrowserClient( + content::BrowserContext* context, + PrefService* pref_service, + chromecast::shell::CastNetworkContexts* cast_network_contexts); ~CastExtensionsBrowserClient() override; // ExtensionsBrowserClient overrides: + network::mojom::NetworkContext* GetSystemNetworkContext() override; bool IsShuttingDown() override; bool AreExtensionsDisabled(const base::CommandLine& command_line, content::BrowserContext* context) override; @@ -112,6 +121,8 @@ // The single BrowserContext for cast_shell. Not owned. content::BrowserContext* browser_context_; + chromecast::shell::CastNetworkContexts* cast_network_contexts_; + // The PrefService for |browser_context_|. Not owned. PrefService* pref_service_;
diff --git a/chromecast/graphics/accessibility/fullscreen_magnification_controller.cc b/chromecast/graphics/accessibility/fullscreen_magnification_controller.cc index eefa1fe8..ff77568 100644 --- a/chromecast/graphics/accessibility/fullscreen_magnification_controller.cc +++ b/chromecast/graphics/accessibility/fullscreen_magnification_controller.cc
@@ -4,6 +4,8 @@ #include "chromecast/graphics/accessibility/fullscreen_magnification_controller.h" +#include <vector> + #include "base/numerics/ranges.h" #include "chromecast/graphics/gestures/cast_gesture_handler.h" #include "third_party/skia/include/core/SkPaint.h" @@ -152,14 +154,14 @@ } // Overridden from ui::EventRewriter -ui::EventRewriteStatus FullscreenMagnificationController::RewriteEvent( +ui::EventDispatchDetails FullscreenMagnificationController::RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { if (!IsEnabled()) { - return ui::EventRewriteStatus::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } if (!event.IsTouchEvent()) - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); const ui::TouchEvent* touch_event = event.AsTouchEvent(); @@ -193,7 +195,7 @@ touch_event_dip.unique_event_id(), false /* event_consumed */, false /* is_source_touch_event_set_non_blocking */); } else { - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // The user can change the zoom level with two fingers pinch and pan around @@ -208,21 +210,19 @@ consume_touch_event_ = true; if (!press_event_map_.empty()) { - auto it = press_event_map_.begin(); - - std::unique_ptr<ui::TouchEvent> rewritten_touch_event = - std::make_unique<ui::TouchEvent>(ui::ET_TOUCH_CANCELLED, gfx::Point(), - touch_event_dip.time_stamp(), - it->second->pointer_details()); - rewritten_touch_event->set_location_f(it->second->location_f()); - rewritten_touch_event->set_root_location_f(it->second->root_location_f()); - rewritten_touch_event->set_flags(it->second->flags()); - *rewritten_event = std::move(rewritten_touch_event); - - // The other event is cancelled in NextDispatchEvent. - press_event_map_.erase(it); - - return ui::EVENT_REWRITE_DISPATCH_ANOTHER; + DCHECK_EQ(2u, press_event_map_.size()); + ui::EventDispatchDetails details; + for (const auto& it : press_event_map_) { + ui::TouchEvent rewritten_touch_event( + ui::ET_TOUCH_CANCELLED, it.second->location_f(), + it.second->root_location_f(), touch_event_dip.time_stamp(), + it.second->pointer_details(), it.second->flags()); + details = SendEvent(continuation, &rewritten_touch_event); + if (details.dispatcher_destroyed) + break; + } + press_event_map_.clear(); + return details; } } @@ -239,31 +239,9 @@ } if (discard) - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); - return ui::EVENT_REWRITE_CONTINUE; -} - -ui::EventRewriteStatus FullscreenMagnificationController::NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) { - DCHECK_EQ(1u, press_event_map_.size()); - - auto it = press_event_map_.begin(); - - std::unique_ptr<ui::TouchEvent> event = std::make_unique<ui::TouchEvent>( - ui::ET_TOUCH_CANCELLED, gfx::Point(), last_event.time_stamp(), - it->second->pointer_details()); - event->set_location_f(it->second->location_f()); - event->set_root_location_f(it->second->root_location_f()); - event->set_flags(it->second->flags()); - *new_event = std::move(event); - - press_event_map_.erase(it); - - DCHECK_EQ(0u, press_event_map_.size()); - - return ui::EVENT_REWRITE_REWRITTEN; + return SendEvent(continuation, &event); } bool FullscreenMagnificationController::RedrawDIP(
diff --git a/chromecast/graphics/accessibility/fullscreen_magnification_controller.h b/chromecast/graphics/accessibility/fullscreen_magnification_controller.h index 0d00316c..e439bc8 100644 --- a/chromecast/graphics/accessibility/fullscreen_magnification_controller.h +++ b/chromecast/graphics/accessibility/fullscreen_magnification_controller.h
@@ -5,6 +5,9 @@ #ifndef CHROMECAST_GRAPHICS_ACCESSIBILITY_FULLSCREEN_MAGNIFICATION_CONTROLLER_H_ #define CHROMECAST_GRAPHICS_ACCESSIBILITY_FULLSCREEN_MAGNIFICATION_CONTROLLER_H_ +#include <map> +#include <memory> + #include "chromecast/graphics/accessibility/magnification_controller.h" #include "ui/compositor/layer_delegate.h" #include "ui/events/event_handler.h" @@ -57,12 +60,9 @@ bool RedrawDIP(const gfx::PointF& position_in_dip, float scale); // Overridden from ui::EventRewriter - ui::EventRewriteStatus RewriteEvent( + ui::EventDispatchDetails RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) override; - ui::EventRewriteStatus NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) override; + const Continuation continuation) override; // Adds the layer for the highlight-ring which provides a visual indicator // that magnification is enabled.
diff --git a/chromecast/graphics/cast_touch_event_gate.cc b/chromecast/graphics/cast_touch_event_gate.cc index 73c9db0..abeeb2ba 100644 --- a/chromecast/graphics/cast_touch_event_gate.cc +++ b/chromecast/graphics/cast_touch_event_gate.cc
@@ -42,22 +42,16 @@ } } -ui::EventRewriteStatus CastTouchEventGate::RewriteEvent( +ui::EventDispatchDetails CastTouchEventGate::RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { if (!enabled_ || !event.IsTouchEvent()) - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); for (auto* observer : observers_) { observer->OnTouchActivity(); } - return ui::EVENT_REWRITE_DISCARD; -} - -ui::EventRewriteStatus CastTouchEventGate::NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) { - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } } // namespace chromecast
diff --git a/chromecast/graphics/cast_touch_event_gate.h b/chromecast/graphics/cast_touch_event_gate.h index b59d535..968b12f 100644 --- a/chromecast/graphics/cast_touch_event_gate.h +++ b/chromecast/graphics/cast_touch_event_gate.h
@@ -32,13 +32,9 @@ void RemoveObserver(CastTouchActivityObserver* observer); // ui::EventRewriter implementation. - ui::EventRewriteStatus RewriteEvent( + ui::EventDispatchDetails RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) override; - - ui::EventRewriteStatus NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) override; + const Continuation continuation) override; private: bool enabled_ = false;
diff --git a/chromecast/graphics/gestures/multiple_tap_detector.cc b/chromecast/graphics/gestures/multiple_tap_detector.cc index 2ba628e..2456a51 100644 --- a/chromecast/graphics/gestures/multiple_tap_detector.cc +++ b/chromecast/graphics/gestures/multiple_tap_detector.cc
@@ -4,6 +4,8 @@ #include "chromecast/graphics/gestures/multiple_tap_detector.h" +#include <memory> + #include "base/auto_reset.h" #include "base/logging.h" #include "ui/aura/window.h" @@ -15,24 +17,6 @@ namespace chromecast { -namespace { - -std::unique_ptr<ui::TouchEvent> MakeCancelEvent( - const base::TimeTicks& time_stamp, - const ui::TouchEvent& stashed_press) { - std::unique_ptr<ui::TouchEvent> rewritten_touch_event = - std::make_unique<ui::TouchEvent>(ui::ET_TOUCH_CANCELLED, gfx::Point(), - time_stamp, - stashed_press.pointer_details()); - rewritten_touch_event->set_location_f(stashed_press.location_f()); - rewritten_touch_event->set_root_location_f(stashed_press.root_location_f()); - rewritten_touch_event->set_flags(stashed_press.flags()); - - return rewritten_touch_event; -} - -} // namespace - MultipleTapDetector::MultipleTapDetector(aura::Window* root_window, MultipleTapDetectorDelegate* delegate) : root_window_(root_window), @@ -47,11 +31,11 @@ root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); } -ui::EventRewriteStatus MultipleTapDetector::RewriteEvent( +ui::EventDispatchDetails MultipleTapDetector::RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) { + const Continuation continuation) { if (!enabled_ || !delegate_ || !event.IsTouchEvent()) { - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } const ui::TouchEvent& touch_event = static_cast<const ui::TouchEvent&>(event); @@ -59,11 +43,11 @@ // If a press happened again before the minimum inter-tap interval, cancel // the detection. if (tap_state_ == MultiTapState::INTERVAL_WAIT && - (event.time_stamp() - stashed_events_.back().time_stamp()) < + (event.time_stamp() - stashed_events_.back().event.time_stamp()) < gesture_detector_config_.double_tap_min_time) { stashed_events_.clear(); TapDetectorStateReset(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } // If the user moved too far from the last tap position, it's not a multi @@ -73,7 +57,7 @@ if (distance > gesture_detector_config_.double_tap_slop) { TapDetectorStateReset(); stashed_events_.clear(); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } } @@ -90,14 +74,14 @@ // If we've already gotten one tap, discard this event, only the original // tap needs to get through. if (tap_count_) { - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // Copy the event so we can issue a cancel for it later if this turns out to // be a multi-tap. - stashed_events_.push_back(touch_event); + stashed_events_.emplace_back(touch_event, continuation); - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } // Finger was released while we were waiting for one, count it as a tap. @@ -113,35 +97,25 @@ TapDetectorStateReset(); delegate_->OnTripleTap(touch_event.location()); - // Start issuing cancel events for old presses. - DCHECK(!stashed_events_.empty()); - *rewritten_event = - MakeCancelEvent(touch_event.time_stamp(), stashed_events_.front()); - stashed_events_.pop_front(); - - if (!stashed_events_.empty()) - return ui::EVENT_REWRITE_DISPATCH_ANOTHER; - else - return ui::EVENT_REWRITE_REWRITTEN; + // Issue cancel events for old presses. + ui::EventDispatchDetails details; + for (const auto& it : stashed_events_) { + ui::TouchEvent cancel_event( + ui::ET_TOUCH_CANCELLED, it.event.location_f(), + it.event.root_location_f(), it.event.time_stamp(), + it.event.pointer_details(), it.event.flags()); + details = SendEvent(it.continuation, &cancel_event); + if (details.dispatcher_destroyed) + break; + } + stashed_events_.clear(); + return details; } else if (tap_count_ > 1) { - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } } - return ui::EVENT_REWRITE_CONTINUE; -} - -ui::EventRewriteStatus MultipleTapDetector::NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) { - *new_event = - MakeCancelEvent(last_event.time_stamp(), stashed_events_.front()); - stashed_events_.pop_front(); - - if (!stashed_events_.empty()) - return ui::EVENT_REWRITE_DISPATCH_ANOTHER; - else - return ui::EVENT_REWRITE_DISCARD; + return SendEvent(continuation, &event); } void MultipleTapDetector::OnTapIntervalTimerFired() { @@ -149,14 +123,14 @@ // So call out the double-tap. if (tap_count_ == 2) { delegate_->OnDoubleTap(last_tap_location_); - - // Unfortunately we cannot NextDispatchEvent to issue a cancel on the second - // tap, so we have to manually DispatchEvent to the EventSource. - // Subsequent EventRewriters in the chain will not see the event. if (!stashed_events_.empty()) { - std::unique_ptr<ui::TouchEvent> cancel_event = - MakeCancelEvent(base::TimeTicks::Now(), stashed_events_.front()); - DispatchEvent(cancel_event.get()); + Stash& stash = stashed_events_.front(); + ui::TouchEvent cancel_event( + ui::ET_TOUCH_CANCELLED, stash.event.location_f(), + stash.event.root_location_f(), base::TimeTicks::Now(), + stash.event.pointer_details(), stash.event.flags()); + DCHECK( + !SendEvent(stash.continuation, &cancel_event).dispatcher_destroyed); } } TapDetectorStateReset(); @@ -174,13 +148,9 @@ triple_tap_timer_.Stop(); } -void MultipleTapDetector::DispatchEvent(ui::TouchEvent* event) { - // Turn off triple-tap before re-dispatching to avoid infinite recursion into - // this detector. - base::AutoReset<bool> toggle_enable(&enabled_, false); - DCHECK(!root_window_->GetHost() - ->dispatcher() - ->OnEventFromSource(event) - .dispatcher_destroyed); -} +MultipleTapDetector::Stash::Stash(const ui::TouchEvent& e, const Continuation c) + : event(e), continuation(c) {} + +MultipleTapDetector::Stash::~Stash() {} + } // namespace chromecast
diff --git a/chromecast/graphics/gestures/multiple_tap_detector.h b/chromecast/graphics/gestures/multiple_tap_detector.h index 0810971f..59879f3d 100644 --- a/chromecast/graphics/gestures/multiple_tap_detector.h +++ b/chromecast/graphics/gestures/multiple_tap_detector.h
@@ -53,12 +53,9 @@ bool enabled() const { return enabled_; } // Overridden from ui::EventRewriter - ui::EventRewriteStatus RewriteEvent( + ui::EventDispatchDetails RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) override; - ui::EventRewriteStatus NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) override; + const Continuation continuation) override; private: friend class MultipleTapDetectorTest; @@ -84,7 +81,14 @@ int tap_count_; gfx::Point last_tap_location_; base::OneShotTimer triple_tap_timer_; - std::deque<ui::TouchEvent> stashed_events_; + class Stash { + public: + Stash(const ui::TouchEvent& e, const Continuation c); + ~Stash(); + const ui::TouchEvent event; + const Continuation continuation; + }; + std::deque<Stash> stashed_events_; DISALLOW_COPY_AND_ASSIGN(MultipleTapDetector); };
diff --git a/chromecast/graphics/gestures/side_swipe_detector.cc b/chromecast/graphics/gestures/side_swipe_detector.cc index 9ea0233..7bfde99 100644 --- a/chromecast/graphics/gestures/side_swipe_detector.cc +++ b/chromecast/graphics/gestures/side_swipe_detector.cc
@@ -99,11 +99,11 @@ stashed_events_.push_back(event); } -ui::EventRewriteStatus SideSwipeDetector::RewriteEvent( +ui::EventDispatchDetails SideSwipeDetector::RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* new_event) { + const Continuation continuation) { if (!event.IsTouchEvent()) { - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } const ui::TouchEvent* touch_event = event.AsTouchEvent(); @@ -127,12 +127,12 @@ // Check to see if we have any potential consumers of events on this side. // If not, we can continue on without consuming it. if (!gesture_handler_->CanHandleSwipe(side_swipe_origin)) { - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } // Detect the beginning of a system gesture swipe. if (touch_event->type() != ui::ET_TOUCH_PRESSED) { - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } current_swipe_ = side_swipe_origin; @@ -154,17 +154,17 @@ root_window_->CleanupGestureState(); // And then stop the original event from propagating. - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // If no swipe in progress, just move on. if (current_swipe_ == CastSideSwipeOrigin::NONE) { - return ui::EVENT_REWRITE_CONTINUE; + return SendEvent(continuation, &event); } // If the finger involved is not the one we're looking for, discard it. if (touch_event->pointer_details().id != current_pointer_id_) { - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // A swipe is in progress, or has completed, so stop propagation of underlying @@ -183,19 +183,22 @@ current_pointer_id_ = ui::PointerDetails::kUnknownPointerId; // If the finger is still inside the touch margin at release, this is not - // really a side swipe. Start streaming out events we stashed for later - // retrieval. + // really a side swipe. Stream out events we stashed for later retrieval. if (side_swipe_origin != CastSideSwipeOrigin::NONE && !stashed_events_.empty()) { - *new_event = ui::Event::Clone(stashed_events_.front()); - stashed_events_.pop_front(); - return ui::EVENT_REWRITE_DISPATCH_ANOTHER; + ui::EventDispatchDetails details; + for (const auto& it : stashed_events_) { + details = SendEvent(continuation, &it); + if (details.dispatcher_destroyed) + break; + } + stashed_events_.clear(); + return details; } // Otherwise, clear them. stashed_events_.clear(); - - return ui::EVENT_REWRITE_DISCARD; + return DiscardEvent(continuation); } // The system gesture is ongoing... @@ -205,20 +208,7 @@ << current_swipe_time_.Elapsed().InMilliseconds() << "ms @ " << touch_location.ToString(); - return ui::EVENT_REWRITE_DISCARD; -} - -ui::EventRewriteStatus SideSwipeDetector::NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) { - if (stashed_events_.empty()) { - return ui::EVENT_REWRITE_DISCARD; - } - - *new_event = ui::Event::Clone(stashed_events_.front()); - stashed_events_.pop_front(); - - return ui::EVENT_REWRITE_DISPATCH_ANOTHER; + return DiscardEvent(continuation); } } // namespace chromecast
diff --git a/chromecast/graphics/gestures/side_swipe_detector.h b/chromecast/graphics/gestures/side_swipe_detector.h index 095ad04..0222f2ce 100644 --- a/chromecast/graphics/gestures/side_swipe_detector.h +++ b/chromecast/graphics/gestures/side_swipe_detector.h
@@ -5,6 +5,8 @@ #ifndef CHROMECAST_GRAPHICS_GESTURES_SIDE_SWIPE_DETECTOR_H_ #define CHROMECAST_GRAPHICS_GESTURES_SIDE_SWIPE_DETECTOR_H_ +#include <deque> + #include "base/timer/elapsed_timer.h" #include "chromecast/graphics/gestures/cast_gesture_handler.h" #include "ui/events/event_rewriter.h" @@ -32,12 +34,9 @@ const gfx::Rect& screen_bounds) const; // Overridden from ui::EventRewriter - ui::EventRewriteStatus RewriteEvent( + ui::EventDispatchDetails RewriteEvent( const ui::Event& event, - std::unique_ptr<ui::Event>* rewritten_event) override; - ui::EventRewriteStatus NextDispatchEvent( - const ui::Event& last_event, - std::unique_ptr<ui::Event>* new_event) override; + const Continuation continuation) override; private: void StashEvent(const ui::TouchEvent& event);
diff --git a/chromecast/media/cdm/OWNERS b/chromecast/media/cdm/OWNERS new file mode 100644 index 0000000..f6a6baf --- /dev/null +++ b/chromecast/media/cdm/OWNERS
@@ -0,0 +1 @@ +# COMPONENT: Internals>Media>Encrypted
diff --git a/chromeos/assistant/OWNERS b/chromeos/assistant/OWNERS index c47d135..a03f56b 100644 --- a/chromeos/assistant/OWNERS +++ b/chromeos/assistant/OWNERS
@@ -2,4 +2,4 @@ wutao@chromium.org xiaohuic@chromium.org -# COMPONENTS: UI>Shell>Assistant +# COMPONENT: UI>Shell>Assistant
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index a7c62a8..9abf076 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -135,10 +135,10 @@ <!-- Managed guest session warnings --> <message name="IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING" desc="Text shown in the public account user pod in case of risky configuration, informing the user that this session is managed and admin can monitor all activity."> - The administrator of this device has access to all activity, including passwords and communications. + <ph name="ENROLLMENT_DOMAIN">$1<ex>example.com</ex></ph> manages this device and has access to all user activity, including webpages visited, passwords, and email. </message> <message name="IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_SOFT_WARNING" desc="Text shown in the public account user pod in case of non-risky configuration, informing the user that this session is managed and admin can monitor all activity."> - The device administrator may be able to monitor your activity. + <ph name="ENROLLMENT_DOMAIN">$1<ex>example.com</ex></ph> manages this device and may be able to monitor your activity. </message> <!-- Status tray enterprise management. -->
diff --git a/chromeos/chromeos_strings_grd/IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING.png.sha1 b/chromeos/chromeos_strings_grd/IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING.png.sha1 index 0612919..0ebd593 100644 --- a/chromeos/chromeos_strings_grd/IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING.png.sha1 +++ b/chromeos/chromeos_strings_grd/IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_FULL_WARNING.png.sha1
@@ -1 +1 @@ -35ff7a23ed3df6ccbc9b2267ebaaf8ed8bada467 \ No newline at end of file +00708b9d291e109d1f196d698b038262d4fe1022 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_SOFT_WARNING.png.sha1 b/chromeos/chromeos_strings_grd/IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_SOFT_WARNING.png.sha1 index 6208ff3d..aef24bb 100644 --- a/chromeos/chromeos_strings_grd/IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_SOFT_WARNING.png.sha1 +++ b/chromeos/chromeos_strings_grd/IDS_ASH_LOGIN_MANAGED_SESSION_MONITORING_SOFT_WARNING.png.sha1
@@ -1 +1 @@ -980ed20bd0ed1748276b5ea307a0e3e841745dcc \ No newline at end of file +818ef020fef4427b569cfadef4ec11546d81e1ce \ No newline at end of file
diff --git a/chromeos/components/BUILD.gn b/chromeos/components/BUILD.gn index 13050e2..d143615 100644 --- a/chromeos/components/BUILD.gn +++ b/chromeos/components/BUILD.gn
@@ -23,6 +23,7 @@ "//chromeos/components/nearby:unit_tests", "//chromeos/components/power:unit_tests", "//chromeos/components/proximity_auth:unit_tests", + "//chromeos/components/sync_wifi:unit_tests", "//chromeos/components/tether:unit_tests", "//mojo/core/embedder", ]
diff --git a/chromeos/components/proximity_auth/BUILD.gn b/chromeos/components/proximity_auth/BUILD.gn index c8971a7e..01f7efd 100644 --- a/chromeos/components/proximity_auth/BUILD.gn +++ b/chromeos/components/proximity_auth/BUILD.gn
@@ -121,6 +121,8 @@ "//chromeos/components/multidevice:test_support", "//chromeos/components/multidevice/logging", "//chromeos/constants", + "//chromeos/dbus/power", + "//chromeos/dbus/power:power_manager_proto", "//chromeos/services/multidevice_setup/public/cpp:prefs", "//chromeos/services/multidevice_setup/public/cpp:test_support", "//chromeos/services/secure_channel:test_support",
diff --git a/chromeos/components/proximity_auth/unlock_manager_impl.cc b/chromeos/components/proximity_auth/unlock_manager_impl.cc index 84a09a3..610ed3b 100644 --- a/chromeos/components/proximity_auth/unlock_manager_impl.cc +++ b/chromeos/components/proximity_auth/unlock_manager_impl.cc
@@ -12,6 +12,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/time/default_clock.h" #include "base/time/time.h" +#include "base/timer/timer.h" #include "chromeos/components/multidevice/logging/logging.h" #include "chromeos/components/multidevice/remote_device_ref.h" #include "chromeos/components/proximity_auth/messenger.h" @@ -24,13 +25,22 @@ namespace proximity_auth { namespace { -// The maximum amount of time, in seconds, that the unlock manager can stay in -// the 'waking up' state after resuming from sleep. +// The maximum amount of time that the unlock manager can stay in the 'waking +// up' state after resuming from sleep. constexpr base::TimeDelta kWakingUpDuration = base::TimeDelta::FromSeconds(15); -// The limit, in seconds, on the elapsed time for an auth attempt. If an auth -// attempt exceeds this limit, it will time out and be rejected. This is -// provided as a failsafe, in case something goes wrong. +// The maximum amount of time that we wait for the BluetoothAdapter to be +// fully initialized after resuming from sleep. +// TODO(crbug.com/986896): This is necessary because the BluetoothAdapter +// returns incorrect presence and power values directly after resume, and does +// not return correct values until about 1-2 seconds later. Remove this once +// the bug is fixed. +constexpr base::TimeDelta kBluetoothAdapterResumeMaxDuration = + base::TimeDelta::FromSeconds(3); + +// The limit on the elapsed time for an auth attempt. If an auth attempt exceeds +// this limit, it will time out and be rejected. This is provided as a failsafe, +// in case something goes wrong. constexpr base::TimeDelta kAuthAttemptTimeout = base::TimeDelta::FromSeconds(5); constexpr base::TimeDelta kMinGetUnlockableRemoteStatusDuration = @@ -107,14 +117,9 @@ ProximityAuthSystem::ScreenlockType screenlock_type, ProximityAuthClient* proximity_auth_client) : screenlock_type_(screenlock_type), - life_cycle_(nullptr), proximity_auth_client_(proximity_auth_client), - is_attempting_auth_(false), - is_performing_initial_scan_(false), - screenlock_state_(ScreenlockState::INACTIVE), - initial_scan_timeout_weak_ptr_factory_(this), - reject_auth_attempt_weak_ptr_factory_(this), - weak_ptr_factory_(this) { + bluetooth_suspension_recovery_timer_( + std::make_unique<base::OneShotTimer>()) { chromeos::PowerManagerClient::Get()->AddObserver(this); if (device::BluetoothAdapterFactory::IsBluetoothSupported()) { @@ -314,15 +319,44 @@ UpdateLockScreen(); } +void UnlockManagerImpl::SuspendImminent( + power_manager::SuspendImminent::Reason reason) { + // TODO(crbug.com/986896): For a short time window after resuming from + // suspension, BluetoothAdapter returns incorrect presence and power values. + // Cache the correct values now, in case we need to check those values during + // that time window when the device resumes. + was_bluetooth_present_and_powered_before_last_suspend_ = + IsBluetoothPresentAndPowered(); + bluetooth_suspension_recovery_timer_->Stop(); +} + void UnlockManagerImpl::SuspendDone(const base::TimeDelta& sleep_duration) { + bluetooth_suspension_recovery_timer_->Start( + FROM_HERE, kBluetoothAdapterResumeMaxDuration, + base::Bind(&UnlockManagerImpl::UpdateLockScreen, + weak_ptr_factory_.GetWeakPtr())); + SetIsPerformingInitialScan(true /* is_performing_initial_scan */); } bool UnlockManagerImpl::IsBluetoothPresentAndPowered() const { + // TODO(crbug.com/986896): If the BluetoothAdapter is still "resuming after + // suspension" at this time, it's prone to this bug, meaning we cannot trust + // its returned presence and power values. If this is the case, depend on + // the cached |was_bluetooth_present_and_powered_before_last_suspend_| to + // signal if Bluetooth is enabled; otherwise, directly check request values + // from BluetoothAdapter. Remove this check once the bug is fixed. + if (IsBluetoothAdapterRecoveringFromSuspend()) + return was_bluetooth_present_and_powered_before_last_suspend_; + return bluetooth_adapter_ && bluetooth_adapter_->IsPresent() && bluetooth_adapter_->IsPowered(); } +bool UnlockManagerImpl::IsBluetoothAdapterRecoveringFromSuspend() const { + return bluetooth_suspension_recovery_timer_->IsRunning(); +} + void UnlockManagerImpl::AttemptToStartRemoteDeviceLifecycle() { if (IsBluetoothPresentAndPowered() && life_cycle_ && life_cycle_->GetState() == RemoteDeviceLifeCycle::State::STOPPED) { @@ -660,4 +694,9 @@ attempt_get_remote_status_start_time_ = base::Time(); } +void UnlockManagerImpl::SetBluetoothSuspensionRecoveryTimerForTesting( + std::unique_ptr<base::OneShotTimer> timer) { + bluetooth_suspension_recovery_timer_ = std::move(timer); +} + } // namespace proximity_auth
diff --git a/chromeos/components/proximity_auth/unlock_manager_impl.h b/chromeos/components/proximity_auth/unlock_manager_impl.h index 6259d1f..fc52823 100644 --- a/chromeos/components/proximity_auth/unlock_manager_impl.h +++ b/chromeos/components/proximity_auth/unlock_manager_impl.h
@@ -23,6 +23,10 @@ #include "chromeos/services/secure_channel/public/mojom/secure_channel.mojom.h" #include "device/bluetooth/bluetooth_adapter.h" +namespace base { +class OneShotTimer; +} // namespace base + namespace proximity_auth { class Messenger; @@ -57,6 +61,8 @@ RemoteDeviceLifeCycle* life_cycle); private: + friend class ProximityAuthUnlockManagerImplTest; + // The possible lock screen states for the remote device. enum class RemoteScreenlockState { UNKNOWN, @@ -90,6 +96,7 @@ bool powered) override; // chromeos::PowerManagerClient::Observer: + void SuspendImminent(power_manager::SuspendImminent::Reason reason) override; void SuspendDone(const base::TimeDelta& sleep_duration) override; // RemoteDeviceLifeCycle::Observer: @@ -99,6 +106,17 @@ // Returns true if the BluetoothAdapter is present and powered. bool IsBluetoothPresentAndPowered() const; + // TODO(crbug.com/986896): Waiting a certain time, after resume, before + // trusting the presence and power values returned by BluetoothAdapter is + // necessary because the BluetoothAdapter returns incorrect values directly + // after resume, and does not return correct values until about 1-2 seconds + // later. Remove this function once the bug is resolved. + // + // This function returns true if the BluetoothAdapter is still resuming from + // suspension, indicating that its returned presence and power values cannot + // yet be trusted. + bool IsBluetoothAdapterRecoveringFromSuspend() const; + // If the RemoteDeviceLifeCycle is available, ensure it is started (but only // if Bluetooth is available). void AttemptToStartRemoteDeviceLifecycle(); @@ -159,27 +177,43 @@ // Clears the timers for beginning a scan and fetching remote status. void ResetPerformanceMetricsTimestamps(); + void SetBluetoothSuspensionRecoveryTimerForTesting( + std::unique_ptr<base::OneShotTimer> timer); + // Whether |this| manager is being used for sign-in or session unlock. const ProximityAuthSystem::ScreenlockType screenlock_type_; - // Whether the user is present at the remote device. Unset if no remote status - // update has yet been received. - std::unique_ptr<RemoteScreenlockState> remote_screenlock_state_; + // Used to call into the embedder. Expected to outlive |this| instance. + ProximityAuthClient* proximity_auth_client_; - // Controls the proximity auth flow logic for a remote device. Not owned, and - // expcted to outlive |this| instance. - RemoteDeviceLifeCycle* life_cycle_; + // Starts running after resuming from suspension, and fires once enough time + // has elapsed such that the BluetoothAdapter's presence and power values can + // be trusted again. To be removed once https://crbug.com/986896 is fixed. + std::unique_ptr<base::OneShotTimer> bluetooth_suspension_recovery_timer_; + + // The Bluetooth adapter. Null if there is no adapter present on the local + // device. + scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_; // Tracks whether the remote device is currently in close enough proximity to // the local device to allow unlocking. std::unique_ptr<ProximityMonitor> proximity_monitor_; - // Used to call into the embedder. Expected to outlive |this| instance. - ProximityAuthClient* proximity_auth_client_; + // Whether the user is present at the remote device. Unset if no remote status + // update has yet been received. + std::unique_ptr<RemoteScreenlockState> remote_screenlock_state_; + + // The sign-in secret received from the remote device by decrypting the + // sign-in challenge. + std::unique_ptr<std::string> sign_in_secret_; + + // Controls the proximity auth flow logic for a remote device. Not owned, and + // expcted to outlive |this| instance. + RemoteDeviceLifeCycle* life_cycle_ = nullptr; // True if the manager is currently processing a user-initiated authentication // attempt, which is initiated when the user pod is clicked. - bool is_attempting_auth_; + bool is_attempting_auth_ = false; // If true, either the lock screen was just shown (after resuming from // suspend, or directly locking the screen), or the focused user pod was @@ -188,18 +222,17 @@ // point the user visually sees an indication that the phone cannot be found). // Though this field becomes false after this timeout, Smart Lock continues // to scan for the phone until the user unlocks the screen. - bool is_performing_initial_scan_; + bool is_performing_initial_scan_ = false; - // The Bluetooth adapter. Null if there is no adapter present on the local - // device. - scoped_refptr<device::BluetoothAdapter> bluetooth_adapter_; - - // The sign-in secret received from the remote device by decrypting the - // sign-in challenge. - std::unique_ptr<std::string> sign_in_secret_; + // TODO(crbug.com/986896): For a short time window after resuming from + // suspension, BluetoothAdapter returns incorrect presence and power values. + // This field acts as a cache in case we need to check those values during + // that time window when the device resumes. Remove this field once the bug + // is fixed. + bool was_bluetooth_present_and_powered_before_last_suspend_ = false; // The state of the current screen lock UI. - ScreenlockState screenlock_state_; + ScreenlockState screenlock_state_ = ScreenlockState::INACTIVE; // The timestamp of when UnlockManager begins to try to establish a secure // connection to the requested remote device of the provided @@ -214,15 +247,16 @@ // Used to track if the "initial scan" has timed out. See // |is_performing_initial_scan_| for more. base::WeakPtrFactory<UnlockManagerImpl> - initial_scan_timeout_weak_ptr_factory_; + initial_scan_timeout_weak_ptr_factory_{this}; // Used to reject auth attempts after a timeout. An in-progress auth attempt // blocks the sign-in screen UI, so it's important to prevent the auth attempt // from blocking the UI in case a step in the code path hangs. - base::WeakPtrFactory<UnlockManagerImpl> reject_auth_attempt_weak_ptr_factory_; + base::WeakPtrFactory<UnlockManagerImpl> reject_auth_attempt_weak_ptr_factory_{ + this}; // Used to vend all other weak pointers. - base::WeakPtrFactory<UnlockManagerImpl> weak_ptr_factory_; + base::WeakPtrFactory<UnlockManagerImpl> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(UnlockManagerImpl); };
diff --git a/chromeos/components/proximity_auth/unlock_manager_impl_unittest.cc b/chromeos/components/proximity_auth/unlock_manager_impl_unittest.cc index dd0891dc..c06f7e1 100644 --- a/chromeos/components/proximity_auth/unlock_manager_impl_unittest.cc +++ b/chromeos/components/proximity_auth/unlock_manager_impl_unittest.cc
@@ -12,6 +12,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/test_simple_task_runner.h" #include "base/threading/thread_task_runner_handle.h" +#include "base/timer/mock_timer.h" #include "build/build_config.h" #include "chromeos/components/multidevice/logging/logging.h" #include "chromeos/components/multidevice/remote_device_test_util.h" @@ -23,6 +24,9 @@ #include "chromeos/components/proximity_auth/remote_device_life_cycle.h" #include "chromeos/components/proximity_auth/remote_status_update.h" #include "chromeos/constants/chromeos_features.h" +#include "chromeos/dbus/power/fake_power_manager_client.h" +#include "chromeos/dbus/power/power_manager_client.h" +#include "chromeos/dbus/power_manager/suspend.pb.h" #include "chromeos/services/secure_channel/public/cpp/client/fake_client_channel.h" #include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/test/mock_bluetooth_adapter.h" @@ -160,16 +164,16 @@ ~ProximityAuthUnlockManagerImplTest() override = default; void SetUp() override { + chromeos::PowerManagerClient::InitializeFake(); + ON_CALL(*bluetooth_adapter_, IsPresent()).WillByDefault(Return(true)); ON_CALL(*bluetooth_adapter_, IsPowered()).WillByDefault(Return(true)); + ON_CALL(messenger_, SupportsSignIn()).WillByDefault(Return(true)); ON_CALL(messenger_, GetChannel()) .WillByDefault(Return(fake_client_channel_.get())); - life_cycle_.set_messenger(&messenger_); life_cycle_.set_channel(fake_client_channel_.get()); - - chromeos::PowerManagerClient::InitializeFake(); } void TearDown() override { @@ -189,6 +193,11 @@ ProximityAuthSystem::ScreenlockType screenlock_type) { unlock_manager_.reset( new TestUnlockManager(screenlock_type, &proximity_auth_client_)); + + auto mock_timer = std::make_unique<base::MockOneShotTimer>(); + mock_bluetooth_suspension_recovery_timer_ = mock_timer.get(); + unlock_manager_->SetBluetoothSuspensionRecoveryTimerForTesting( + std::move(mock_timer)); } void SimulateUserPresentState() { @@ -222,6 +231,7 @@ NiceMock<MockProximityAuthClient> proximity_auth_client_; NiceMock<MockMessenger> messenger_; std::unique_ptr<TestUnlockManager> unlock_manager_; + base::MockOneShotTimer* mock_bluetooth_suspension_recovery_timer_ = nullptr; private: base::test::ScopedFeatureList scoped_feature_list_; @@ -528,6 +538,119 @@ EXPECT_TRUE(life_cycle_.started()); } +TEST_F( + ProximityAuthUnlockManagerImplTest, + CacheBluetoothAdapterStateAfterSuspendAndResume_AttemptConnectionWhileBluetoothAdapterIsStillRecovering) { + CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); + + ASSERT_FALSE(mock_bluetooth_suspension_recovery_timer_->IsRunning()); + + chromeos::FakePowerManagerClient::Get()->SendSuspendImminent( + power_manager::SuspendImminent_Reason_LID_CLOSED); + + // Simulate https://crbug.com/986896 by returning false for presence and power + // directly after resuming, but do not fire + // |mock_bluetooth_suspension_recovery_timer_|, simulating that not enough + // time has passed for the BluetoothAdapter to recover. It's expected under + // these conditions that: + // * ProximityAuthClient::UpdateScreenlockState() never be called with + // ScreenlockState::NO_BLUETOOTH. + // * ProximityAuthClient::UpdateScreenlockState() only be called once with + // ScreenlockState::BLUETOOTH_CONNECTING, because it should only be called + // on when the ScreenlockState value changes. + EXPECT_CALL(proximity_auth_client_, + UpdateScreenlockState(ScreenlockState::NO_BLUETOOTH)) + .Times(0); + EXPECT_CALL(proximity_auth_client_, + UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING)); + + ON_CALL(*bluetooth_adapter_, IsPresent()).WillByDefault(Return(false)); + ON_CALL(*bluetooth_adapter_, IsPowered()).WillByDefault(Return(false)); + + chromeos::FakePowerManagerClient::Get()->SendSuspendDone(); + EXPECT_TRUE(mock_bluetooth_suspension_recovery_timer_->IsRunning()); + + // Simulate how ProximityAuthSystem, the owner of UnlockManager, reacts to + // resume: providing a new RemoteDeviceLifeCycle. This shouldn't trigger a new + // call to ProximityAuthClient::UpdateScreenlockState(). + unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); + EXPECT_TRUE(life_cycle_.started()); + + EXPECT_TRUE(mock_bluetooth_suspension_recovery_timer_->IsRunning()); +} + +TEST_F( + ProximityAuthUnlockManagerImplTest, + CacheBluetoothAdapterStateAfterSuspendAndResume_AttemptConnectionOnceBluetoothAdapterHasHadTimeToRecover) { + CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); + + ASSERT_FALSE(mock_bluetooth_suspension_recovery_timer_->IsRunning()); + + chromeos::FakePowerManagerClient::Get()->SendSuspendImminent( + power_manager::SuspendImminent_Reason_LID_CLOSED); + + // Simulate https://crbug.com/986896 by returning false for presence and power + // directly after resuming, and then fire + // |mock_bluetooth_suspension_recovery_timer_|, simulating that enough time + // has passed for the BluetoothAdapter to recover - this means that Bluetooth + // is truly off after resume and the user should be visually informed as such. + // It's expected under these conditions that: + // * ProximityAuthClient::UpdateScreenlockState() only be called once with + // ScreenlockState::NO_BLUETOOTH, but after the timer fires (this is + // impossible to explicitly do in code with mocks, unfortunately). + // * ProximityAuthClient::UpdateScreenlockState() only be called once with + // ScreenlockState::BLUETOOTH_CONNECTING, directly after SuspendDone. + EXPECT_CALL(proximity_auth_client_, + UpdateScreenlockState(ScreenlockState::NO_BLUETOOTH)); + EXPECT_CALL(proximity_auth_client_, + UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING)); + + ON_CALL(*bluetooth_adapter_, IsPresent()).WillByDefault(Return(false)); + ON_CALL(*bluetooth_adapter_, IsPowered()).WillByDefault(Return(false)); + + chromeos::FakePowerManagerClient::Get()->SendSuspendDone(); + EXPECT_TRUE(mock_bluetooth_suspension_recovery_timer_->IsRunning()); + + // Simulate how ProximityAuthSystem, the owner of UnlockManager, reacts to + // resume: providing a new RemoteDeviceLifeCycle. This shouldn't trigger a new + // call to ProximityAuthClient::UpdateScreenlockState(). + unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); + EXPECT_TRUE(life_cycle_.started()); + + ON_CALL(*bluetooth_adapter_, IsPresent()).WillByDefault(Return(false)); + ON_CALL(*bluetooth_adapter_, IsPowered()).WillByDefault(Return(false)); + + EXPECT_TRUE(mock_bluetooth_suspension_recovery_timer_->IsRunning()); + + // This leads to ProximityAuthClient::UpdateScreenlockState() being called + // with ScreenlockState::NO_BLUETOOTH. + mock_bluetooth_suspension_recovery_timer_->Fire(); +} + +TEST_F(ProximityAuthUnlockManagerImplTest, + BluetoothOffMessagePresentedImmediatelyIfBluetoothWasOffBeforeSuspend) { + CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); + + ON_CALL(*bluetooth_adapter_, IsPresent()).WillByDefault(Return(false)); + ON_CALL(*bluetooth_adapter_, IsPowered()).WillByDefault(Return(false)); + + chromeos::FakePowerManagerClient::Get()->SendSuspendImminent( + power_manager::SuspendImminent_Reason_LID_CLOSED); + + EXPECT_CALL(proximity_auth_client_, + UpdateScreenlockState(ScreenlockState::NO_BLUETOOTH)); + EXPECT_CALL(proximity_auth_client_, + UpdateScreenlockState(ScreenlockState::BLUETOOTH_CONNECTING)) + .Times(0); + + chromeos::FakePowerManagerClient::Get()->SendSuspendDone(); + + // Simulate how ProximityAuthSystem, the owner of UnlockManager, reacts to + // resume: providing a new RemoteDeviceLifeCycle. + unlock_manager_->SetRemoteDeviceLifeCycle(&life_cycle_); + EXPECT_FALSE(life_cycle_.started()); +} + TEST_F(ProximityAuthUnlockManagerImplTest, StartsProximityMonitor) { CreateUnlockManager(ProximityAuthSystem::SESSION_LOCK); SimulateUserPresentState();
diff --git a/chromeos/components/sync_wifi/BUILD.gn b/chromeos/components/sync_wifi/BUILD.gn new file mode 100644 index 0000000..b5acece --- /dev/null +++ b/chromeos/components/sync_wifi/BUILD.gn
@@ -0,0 +1,28 @@ +# 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. + +static_library("sync_wifi") { + sources = [ + "synced_network_updater.h", + "wifi_configuration_bridge.cc", + "wifi_configuration_bridge.h", + ] + deps = [ + "//base", + "//components/sync", + ] +} + +source_set("unit_tests") { + testonly = true + sources = [ + "wifi_configuration_bridge_unittest.cc", + ] + deps = [ + ":sync_wifi", + "//base/test:test_support", + "//components/sync:test_support", + "//testing/gtest", + ] +}
diff --git a/chromeos/components/sync_wifi/DEPS b/chromeos/components/sync_wifi/DEPS new file mode 100644 index 0000000..5fb592e --- /dev/null +++ b/chromeos/components/sync_wifi/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+components/sync", +]
diff --git a/chromeos/components/sync_wifi/OWNERS b/chromeos/components/sync_wifi/OWNERS new file mode 100644 index 0000000..a663579 --- /dev/null +++ b/chromeos/components/sync_wifi/OWNERS
@@ -0,0 +1,4 @@ +jonmann@chromium.org +khorimoto@chromium.org + +# COMPONENT: OS>Systems>Network>WiFi
diff --git a/chromeos/components/sync_wifi/README.md b/chromeos/components/sync_wifi/README.md new file mode 100644 index 0000000..e0cc93f --- /dev/null +++ b/chromeos/components/sync_wifi/README.md
@@ -0,0 +1,20 @@ +Wifi Configuration Sync + +sync_wifi is a component which provides the necessary APIs to sync Wi-Fi +credentials across devices. This component will receive changes from the +Chrome sync server as well as monitor local changes to the network list +and keep the two network lists in sync with each other. Local changes will +be monitored using chromeos::NetworkStateHandler and updated using +chromeos::NetworkConfigurationHandler. Changes from the server will be +received through the syncer::ModelTypeSyncBridge interface. + +Only password protected networks which were added by the specific user will be +synced to their account. Public networks, enterprise networks, and networks +which have static ip configurations will not be synced. + +The network configurations with credentials will be stored in the users +cryptohome using a syncer::ModelTypeStore and held in memory during the +user session. All network details will be encrypted before getting sent +to the Chrome sync server. + +This feature is tracked at http://crbug.com/954648 \ No newline at end of file
diff --git a/chromeos/components/sync_wifi/synced_network_updater.h b/chromeos/components/sync_wifi/synced_network_updater.h new file mode 100644 index 0000000..8e5eedc --- /dev/null +++ b/chromeos/components/sync_wifi/synced_network_updater.h
@@ -0,0 +1,36 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_COMPONENTS_SYNC_WIFI_SYNCED_NETWORK_UPDATER_H_ +#define CHROMEOS_COMPONENTS_SYNC_WIFI_SYNCED_NETWORK_UPDATER_H_ + +#include <string> + +#include "base/macros.h" + +namespace sync_pb { +class WifiConfigurationSpecificsData; +} + +namespace sync_wifi { + +// Applies updates to synced networks to the local networking stack. +class SyncedNetworkUpdater { + public: + virtual ~SyncedNetworkUpdater() = default; + + virtual void AddOrUpdateNetwork( + const sync_pb::WifiConfigurationSpecificsData& specifics) = 0; + virtual void RemoveNetwork(const std::string& ssid) = 0; + + protected: + SyncedNetworkUpdater() = default; + + private: + DISALLOW_COPY_AND_ASSIGN(SyncedNetworkUpdater); +}; + +} // namespace sync_wifi + +#endif // CHROMEOS_COMPONENTS_SYNC_WIFI_SYNCED_NETWORK_UPDATER_H_
diff --git a/chromeos/components/sync_wifi/wifi_configuration_bridge.cc b/chromeos/components/sync_wifi/wifi_configuration_bridge.cc new file mode 100644 index 0000000..95bfc13 --- /dev/null +++ b/chromeos/components/sync_wifi/wifi_configuration_bridge.cc
@@ -0,0 +1,198 @@ +// 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. + +#include "chromeos/components/sync_wifi/wifi_configuration_bridge.h" + +#include <algorithm> + +#include "base/bind.h" +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" +#include "base/optional.h" +#include "base/time/clock.h" +#include "base/time/time.h" +#include "chromeos/components/sync_wifi/synced_network_updater.h" +#include "components/sync/model/entity_change.h" +#include "components/sync/model/metadata_batch.h" +#include "components/sync/model/metadata_change_list.h" +#include "components/sync/model/model_type_change_processor.h" +#include "components/sync/model/mutable_data_batch.h" +#include "components/sync/protocol/model_type_state.pb.h" + +namespace sync_wifi { + +namespace { + +std::unique_ptr<syncer::EntityData> GenerateWifiEntityData( + const sync_pb::WifiConfigurationSpecificsData& data) { + auto entity_data = std::make_unique<syncer::EntityData>(); + entity_data->specifics.mutable_wifi_configuration() + ->mutable_client_only_encrypted_data() + ->CopyFrom(data); + entity_data->name = data.ssid(); + return entity_data; +} +} // namespace + +WifiConfigurationBridge::WifiConfigurationBridge( + SyncedNetworkUpdater* synced_network_updater, + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, + syncer::OnceModelTypeStoreFactory create_store_callback) + : ModelTypeSyncBridge(std::move(change_processor)), + synced_network_updater_(synced_network_updater) { + std::move(create_store_callback) + .Run(syncer::WIFI_CONFIGURATIONS, + base::BindOnce(&WifiConfigurationBridge::OnStoreCreated, + weak_ptr_factory_.GetWeakPtr())); +} + +WifiConfigurationBridge::~WifiConfigurationBridge() {} + +std::unique_ptr<syncer::MetadataChangeList> +WifiConfigurationBridge::CreateMetadataChangeList() { + return syncer::ModelTypeStore::WriteBatch::CreateMetadataChangeList(); +} + +base::Optional<syncer::ModelError> WifiConfigurationBridge::MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) { + DCHECK(entries_.empty()); + return ApplySyncChanges(std::move(metadata_change_list), + std::move(entity_data)); +} + +base::Optional<syncer::ModelError> WifiConfigurationBridge::ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_changes) { + std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch = + store_->CreateWriteBatch(); + + for (std::unique_ptr<syncer::EntityChange>& change : entity_changes) { + if (change->type() == syncer::EntityChange::ACTION_DELETE) { + auto it = entries_.find(change->storage_key()); + if (it != entries_.end()) { + entries_.erase(it); + batch->DeleteData(change->storage_key()); + synced_network_updater_->RemoveNetwork(change->storage_key()); + } + continue; + } + + auto& specifics = change->data() + .specifics.wifi_configuration() + .client_only_encrypted_data(); + synced_network_updater_->AddOrUpdateNetwork(specifics); + + batch->WriteData(change->storage_key(), specifics.SerializeAsString()); + entries_[change->storage_key()] = std::move(specifics); + } + + batch->TakeMetadataChangesFrom(std::move(metadata_change_list)); + Commit(std::move(batch)); + + return base::nullopt; +} + +void WifiConfigurationBridge::GetData(StorageKeyList storage_keys, + DataCallback callback) { + auto batch = std::make_unique<syncer::MutableDataBatch>(); + + for (const std::string& id : storage_keys) { + auto it = entries_.find(id); + if (it == entries_.end()) { + continue; + } + batch->Put(id, GenerateWifiEntityData(it->second)); + } + std::move(callback).Run(std::move(batch)); +} + +void WifiConfigurationBridge::GetAllDataForDebugging(DataCallback callback) { + auto batch = std::make_unique<syncer::MutableDataBatch>(); + for (const auto& entry : entries_) { + batch->Put(entry.first, GenerateWifiEntityData(entry.second)); + } + std::move(callback).Run(std::move(batch)); +} + +std::string WifiConfigurationBridge::GetClientTag( + const syncer::EntityData& entity_data) { + return GetStorageKey(entity_data); +} + +std::string WifiConfigurationBridge::GetStorageKey( + const syncer::EntityData& entity_data) { + return entity_data.specifics.wifi_configuration() + .client_only_encrypted_data() + .ssid(); +} + +void WifiConfigurationBridge::OnStoreCreated( + const base::Optional<syncer::ModelError>& error, + std::unique_ptr<syncer::ModelTypeStore> store) { + if (error) { + change_processor()->ReportError(*error); + return; + } + + store_ = std::move(store); + store_->ReadAllData(base::BindOnce(&WifiConfigurationBridge::OnReadAllData, + weak_ptr_factory_.GetWeakPtr())); +} + +void WifiConfigurationBridge::OnReadAllData( + const base::Optional<syncer::ModelError>& error, + std::unique_ptr<syncer::ModelTypeStore::RecordList> records) { + if (error) { + change_processor()->ReportError(*error); + return; + } + + for (syncer::ModelTypeStore::Record& record : *records) { + sync_pb::WifiConfigurationSpecificsData data; + if (record.id.empty() || !data.ParseFromString(record.value)) { + DVLOG(1) << "Unable to parse proto for entry with key: " << record.id; + continue; + } + entries_[record.id] = std::move(data); + } + + store_->ReadAllMetadata( + base::BindOnce(&WifiConfigurationBridge::OnReadAllMetadata, + weak_ptr_factory_.GetWeakPtr())); +} + +void WifiConfigurationBridge::OnReadAllMetadata( + const base::Optional<syncer::ModelError>& error, + std::unique_ptr<syncer::MetadataBatch> metadata_batch) { + if (error) { + change_processor()->ReportError(*error); + return; + } + change_processor()->ModelReadyToSync(std::move(metadata_batch)); +} + +void WifiConfigurationBridge::OnCommit( + const base::Optional<syncer::ModelError>& error) { + if (error) + change_processor()->ReportError(*error); +} + +void WifiConfigurationBridge::Commit( + std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch) { + store_->CommitWriteBatch(std::move(batch), + base::BindOnce(&WifiConfigurationBridge::OnCommit, + weak_ptr_factory_.GetWeakPtr())); +} + +std::vector<std::string> WifiConfigurationBridge::GetAllSsidsForTesting() { + std::vector<std::string> ssids; + for (const auto& entry : entries_) + ssids.push_back(entry.second.ssid()); + + return ssids; +} + +} // namespace sync_wifi
diff --git a/chromeos/components/sync_wifi/wifi_configuration_bridge.h b/chromeos/components/sync_wifi/wifi_configuration_bridge.h new file mode 100644 index 0000000..f7fe8d95 --- /dev/null +++ b/chromeos/components/sync_wifi/wifi_configuration_bridge.h
@@ -0,0 +1,88 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_COMPONENTS_SYNC_WIFI_WIFI_CONFIGURATION_BRIDGE_H_ +#define CHROMEOS_COMPONENTS_SYNC_WIFI_WIFI_CONFIGURATION_BRIDGE_H_ + +#include <map> +#include <memory> +#include <string> +#include <utility> +#include <vector> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/time/time.h" +#include "chromeos/components/sync_wifi/synced_network_updater.h" +#include "components/sync/base/model_type.h" +#include "components/sync/model/model_type_store.h" +#include "components/sync/model/model_type_sync_bridge.h" + +namespace syncer { +class ModelTypeChangeProcessor; +} // namespace syncer + +namespace sync_wifi { + +// Receives updates to network configurations from the Chrome sync back end and +// from the system network stack and keeps both lists in sync. +class WifiConfigurationBridge : public syncer::ModelTypeSyncBridge { + public: + WifiConfigurationBridge( + SyncedNetworkUpdater* synced_network_updater, + std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor, + syncer::OnceModelTypeStoreFactory create_store_callback); + ~WifiConfigurationBridge() override; + + // syncer::ModelTypeSyncBridge: + std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList() + override; + base::Optional<syncer::ModelError> MergeSyncData( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_data) override; + base::Optional<syncer::ModelError> ApplySyncChanges( + std::unique_ptr<syncer::MetadataChangeList> metadata_change_list, + syncer::EntityChangeList entity_changes) override; + void GetData(StorageKeyList storage_keys, DataCallback callback) override; + void GetAllDataForDebugging(DataCallback callback) override; + std::string GetClientTag(const syncer::EntityData& entity_data) override; + std::string GetStorageKey(const syncer::EntityData& entity_data) override; + + // Comes from |entries_| the in-memory map. + std::vector<std::string> GetAllSsidsForTesting(); + + private: + void Commit(std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch); + + // Callbacks for ModelTypeStore. + void OnStoreCreated(const base::Optional<syncer::ModelError>& error, + std::unique_ptr<syncer::ModelTypeStore> store); + void OnReadAllData( + const base::Optional<syncer::ModelError>& error, + std::unique_ptr<syncer::ModelTypeStore::RecordList> records); + void OnReadAllMetadata(const base::Optional<syncer::ModelError>& error, + std::unique_ptr<syncer::MetadataBatch> metadata_batch); + void OnCommit(const base::Optional<syncer::ModelError>& error); + + // An in-memory list of the proto's that mirrors what is on the sync server. + // This gets updated when changes are received from the server and after local + // changes have been committed. On initialization of this class, it is + // populated with the contents of |store_|. + base::flat_map<std::string, sync_pb::WifiConfigurationSpecificsData> entries_; + + // The on disk store of WifiConfigurationSpecifics protos that mirrors what + // is on the sync server. This gets updated when changes are received from + // the server and after local changes have been committed to the server. + std::unique_ptr<syncer::ModelTypeStore> store_; + + SyncedNetworkUpdater* synced_network_updater_; + + base::WeakPtrFactory<WifiConfigurationBridge> weak_ptr_factory_{this}; + + DISALLOW_COPY_AND_ASSIGN(WifiConfigurationBridge); +}; + +} // namespace sync_wifi + +#endif // CHROMEOS_COMPONENTS_SYNC_WIFI_WIFI_CONFIGURATION_BRIDGE_H_
diff --git a/chromeos/components/sync_wifi/wifi_configuration_bridge_unittest.cc b/chromeos/components/sync_wifi/wifi_configuration_bridge_unittest.cc new file mode 100644 index 0000000..0853a3d --- /dev/null +++ b/chromeos/components/sync_wifi/wifi_configuration_bridge_unittest.cc
@@ -0,0 +1,269 @@ +// 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. + +#include "chromeos/components/sync_wifi/wifi_configuration_bridge.h" + +#include <map> +#include <set> +#include <utility> + +#include "base/bind.h" +#include "base/run_loop.h" +#include "base/test/scoped_task_environment.h" +#include "chromeos/components/sync_wifi/synced_network_updater.h" +#include "components/sync/model/entity_change.h" +#include "components/sync/model/metadata_batch.h" +#include "components/sync/model/mock_model_type_change_processor.h" +#include "components/sync/model/model_type_store_test_util.h" +#include "components/sync/model_impl/in_memory_metadata_change_list.h" +#include "components/sync/protocol/model_type_state.pb.h" +#include "components/sync/test/test_matchers.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace sync_wifi { + +namespace { + +using sync_pb::WifiConfigurationSpecificsData; +using testing::_; +using testing::AllOf; +using testing::ElementsAre; +using testing::IsEmpty; +using testing::Pair; +using testing::Return; +using testing::SizeIs; +using testing::UnorderedElementsAre; + +const char kSsidMeow[] = "meow"; +const char kSsidWoof[] = "woof"; + +WifiConfigurationSpecificsData CreateSpecifics(const std::string& ssid) { + WifiConfigurationSpecificsData specifics; + specifics.set_ssid(ssid); + specifics.set_security_type( + WifiConfigurationSpecificsData::SECURITY_TYPE_PSK); + specifics.set_passphrase("password"); + specifics.set_automatically_connect( + WifiConfigurationSpecificsData::AUTOMATICALLY_CONNECT_ENABLED); + specifics.set_is_preferred( + WifiConfigurationSpecificsData::IS_PREFERRED_ENABLED); + specifics.set_metered(WifiConfigurationSpecificsData::METERED_OPTION_AUTO); + sync_pb::WifiConfigurationSpecificsData_ProxyConfiguration proxy_config; + proxy_config.set_proxy_option(WifiConfigurationSpecificsData:: + ProxyConfiguration::PROXY_OPTION_DISABLED); + specifics.mutable_proxy_configuration()->CopyFrom(proxy_config); + return specifics; +} + +std::unique_ptr<syncer::EntityData> GenerateWifiEntityData( + const sync_pb::WifiConfigurationSpecificsData& data) { + auto entity_data = std::make_unique<syncer::EntityData>(); + entity_data->specifics.mutable_wifi_configuration() + ->mutable_client_only_encrypted_data() + ->CopyFrom(data); + entity_data->name = data.ssid(); + return entity_data; +} + +bool VectorContainsString(std::vector<std::string> v, std::string s) { + return std::find(v.begin(), v.end(), s) != v.end(); +} + +bool VectorContainsSsid( + const std::vector<sync_pb::WifiConfigurationSpecificsData>& v, + std::string s) { + for (sync_pb::WifiConfigurationSpecificsData specifics : v) { + if (specifics.ssid() == s) + return true; + } + return false; +} + +class TestSyncedNetworkUpdater : public SyncedNetworkUpdater { + public: + TestSyncedNetworkUpdater() = default; + ~TestSyncedNetworkUpdater() override = default; + + const std::vector<sync_pb::WifiConfigurationSpecificsData>& + add_or_update_calls() { + return add_update_calls_; + } + + const std::vector<std::string>& remove_calls() { return remove_calls_; } + + private: + void AddOrUpdateNetwork( + const sync_pb::WifiConfigurationSpecificsData& specifics) override { + add_update_calls_.push_back(specifics); + } + + void RemoveNetwork(const std::string& ssid) override { + remove_calls_.push_back(ssid); + } + + std::vector<sync_pb::WifiConfigurationSpecificsData> add_update_calls_; + std::vector<std::string> remove_calls_; +}; + +class WifiConfigurationBridgeTest : public testing::Test { + protected: + WifiConfigurationBridgeTest() + : store_(syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()) {} + + void SetUp() override { + ON_CALL(mock_processor_, IsTrackingMetadata()).WillByDefault(Return(true)); + synced_network_updater_ = std::make_unique<TestSyncedNetworkUpdater>(); + bridge_ = std::make_unique<WifiConfigurationBridge>( + synced_network_updater(), mock_processor_.CreateForwardingProcessor(), + syncer::ModelTypeStoreTestUtil::MoveStoreToFactory(std::move(store_))); + } + + void DisableBridge() { + ON_CALL(mock_processor_, IsTrackingMetadata()).WillByDefault(Return(false)); + } + + syncer::EntityChangeList CreateEntityAddList( + const std::vector<WifiConfigurationSpecificsData>& specifics_list) { + syncer::EntityChangeList changes; + for (const auto& data : specifics_list) { + auto entity_data = std::make_unique<syncer::EntityData>(); + sync_pb::WifiConfigurationSpecifics specifics; + + specifics.mutable_client_only_encrypted_data()->CopyFrom(data); + entity_data->specifics.mutable_wifi_configuration()->CopyFrom(specifics); + + entity_data->name = data.ssid(); + + changes.push_back( + syncer::EntityChange::CreateAdd(data.ssid(), std::move(entity_data))); + } + return changes; + } + + syncer::MockModelTypeChangeProcessor* processor() { return &mock_processor_; } + + WifiConfigurationBridge* bridge() { return bridge_.get(); } + + TestSyncedNetworkUpdater* synced_network_updater() { + return synced_network_updater_.get(); + } + + private: + base::test::ScopedTaskEnvironment task_environment_; + + std::unique_ptr<syncer::ModelTypeStore> store_; + + testing::NiceMock<syncer::MockModelTypeChangeProcessor> mock_processor_; + + std::unique_ptr<WifiConfigurationBridge> bridge_; + + std::unique_ptr<TestSyncedNetworkUpdater> synced_network_updater_; + + DISALLOW_COPY_AND_ASSIGN(WifiConfigurationBridgeTest); +}; + +TEST_F(WifiConfigurationBridgeTest, InitWithTwoNetworksFromServer) { + syncer::EntityChangeList remote_input; + + WifiConfigurationSpecificsData entry1 = CreateSpecifics(kSsidMeow); + WifiConfigurationSpecificsData entry2 = CreateSpecifics(kSsidWoof); + + remote_input.push_back(syncer::EntityChange::CreateAdd( + kSsidMeow, GenerateWifiEntityData(entry1))); + remote_input.push_back(syncer::EntityChange::CreateAdd( + kSsidWoof, GenerateWifiEntityData(entry2))); + + bridge()->MergeSyncData( + std::make_unique<syncer::InMemoryMetadataChangeList>(), + std::move(remote_input)); + + std::vector<std::string> ssids = bridge()->GetAllSsidsForTesting(); + EXPECT_EQ(2u, ssids.size()); + EXPECT_TRUE(VectorContainsString(ssids, kSsidMeow)); + EXPECT_TRUE(VectorContainsString(ssids, kSsidWoof)); + + const std::vector<sync_pb::WifiConfigurationSpecificsData>& networks = + synced_network_updater()->add_or_update_calls(); + EXPECT_EQ(2u, networks.size()); + EXPECT_TRUE(VectorContainsSsid(networks, kSsidMeow)); + EXPECT_TRUE(VectorContainsSsid(networks, kSsidWoof)); +} + +TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesAddTwoSpecifics) { + const WifiConfigurationSpecificsData specifics1 = CreateSpecifics(kSsidMeow); + const WifiConfigurationSpecificsData specifics2 = CreateSpecifics(kSsidWoof); + + base::Optional<syncer::ModelError> error = + bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(), + CreateEntityAddList({specifics1, specifics2})); + EXPECT_FALSE(error); + std::vector<std::string> ssids = bridge()->GetAllSsidsForTesting(); + EXPECT_EQ(2u, ssids.size()); + EXPECT_TRUE(VectorContainsString(ssids, kSsidMeow)); + EXPECT_TRUE(VectorContainsString(ssids, kSsidWoof)); + + const std::vector<sync_pb::WifiConfigurationSpecificsData>& networks = + synced_network_updater()->add_or_update_calls(); + EXPECT_EQ(2u, networks.size()); + EXPECT_TRUE(VectorContainsSsid(networks, kSsidMeow)); + EXPECT_TRUE(VectorContainsSsid(networks, kSsidWoof)); +} + +TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneAdd) { + WifiConfigurationSpecificsData entry = CreateSpecifics(kSsidMeow); + + syncer::EntityChangeList add_changes; + + add_changes.push_back(syncer::EntityChange::CreateAdd( + kSsidMeow, GenerateWifiEntityData(entry))); + + bridge()->ApplySyncChanges( + std::make_unique<syncer::InMemoryMetadataChangeList>(), + std::move(add_changes)); + std::vector<std::string> ssids = bridge()->GetAllSsidsForTesting(); + EXPECT_EQ(1u, ssids.size()); + EXPECT_TRUE(VectorContainsString(ssids, kSsidMeow)); + + const std::vector<sync_pb::WifiConfigurationSpecificsData>& networks = + synced_network_updater()->add_or_update_calls(); + EXPECT_EQ(1u, networks.size()); + EXPECT_TRUE(VectorContainsSsid(networks, kSsidMeow)); +} + +TEST_F(WifiConfigurationBridgeTest, ApplySyncChangesOneDeletion) { + WifiConfigurationSpecificsData entry = CreateSpecifics(kSsidMeow); + + syncer::EntityChangeList add_changes; + + add_changes.push_back(syncer::EntityChange::CreateAdd( + kSsidMeow, GenerateWifiEntityData(entry))); + + bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(), + std::move(add_changes)); + std::vector<std::string> ssids = bridge()->GetAllSsidsForTesting(); + EXPECT_EQ(1u, ssids.size()); + EXPECT_TRUE(VectorContainsString(ssids, kSsidMeow)); + + const std::vector<sync_pb::WifiConfigurationSpecificsData>& networks = + synced_network_updater()->add_or_update_calls(); + EXPECT_EQ(1u, networks.size()); + EXPECT_TRUE(VectorContainsSsid(networks, kSsidMeow)); + + syncer::EntityChangeList delete_changes; + delete_changes.push_back(syncer::EntityChange::CreateDelete(kSsidMeow)); + + bridge()->ApplySyncChanges(bridge()->CreateMetadataChangeList(), + std::move(delete_changes)); + EXPECT_TRUE(bridge()->GetAllSsidsForTesting().empty()); + + const std::vector<std::string>& removed_networks = + synced_network_updater()->remove_calls(); + EXPECT_EQ(1u, removed_networks.size()); + EXPECT_TRUE(VectorContainsString(removed_networks, kSsidMeow)); +} + +} // namespace + +} // namespace sync_wifi \ No newline at end of file
diff --git a/chromeos/dbus/kerberos/fake_kerberos_client.cc b/chromeos/dbus/kerberos/fake_kerberos_client.cc index 049197df..7ba95233 100644 --- a/chromeos/dbus/kerberos/fake_kerberos_client.cc +++ b/chromeos/dbus/kerberos/fake_kerberos_client.cc
@@ -5,7 +5,6 @@ #include "chromeos/dbus/kerberos/fake_kerberos_client.h" #include <utility> -#include <vector> #include "base/bind.h" #include "base/files/file_util.h" @@ -127,26 +126,33 @@ void FakeKerberosClient::ClearAccounts( const kerberos::ClearAccountsRequest& request, ClearAccountsCallback callback) { - switch (request.mode()) { - case kerberos::CLEAR_ALL: - accounts_.clear(); - break; + std::unordered_set<std::string> keep_list( + request.principal_names_to_ignore_size()); + for (int n = 0; n < request.principal_names_to_ignore_size(); ++n) + keep_list.insert(request.principal_names_to_ignore(n)); - case kerberos::CLEAR_ONLY_UNMANAGED_ACCOUNTS: - accounts_.erase(std::remove_if(accounts_.begin(), accounts_.end(), - [](const AccountData& account) { - return !account.is_managed; - }), - accounts_.end()); - break; + for (auto it = accounts_.begin(); it != accounts_.end(); /* empty */) { + if (base::Contains(keep_list, it->principal_name)) { + ++it; + continue; + } - case kerberos::CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS: - for (auto& account : accounts_) { - if (!account.is_managed) - account.password.clear(); - } - break; + switch (DetermineWhatToRemove(request.mode(), *it)) { + case WhatToRemove::kNothing: + ++it; + continue; + + case WhatToRemove::kPassword: + it->password.clear(); + ++it; + continue; + + case WhatToRemove::kAccount: + it = accounts_.erase(it); + continue; + } } + PostResponse(std::move(callback), kerberos::ERROR_NONE); } @@ -305,4 +311,25 @@ return !(*this == other); } +// static +FakeKerberosClient::WhatToRemove FakeKerberosClient::DetermineWhatToRemove( + kerberos::ClearMode mode, + const AccountData& data) { + switch (mode) { + case kerberos::CLEAR_ALL: + return WhatToRemove::kAccount; + + case kerberos::CLEAR_ONLY_MANAGED_ACCOUNTS: + return data.is_managed ? WhatToRemove::kAccount : WhatToRemove::kNothing; + + case kerberos::CLEAR_ONLY_UNMANAGED_ACCOUNTS: + return !data.is_managed ? WhatToRemove::kAccount : WhatToRemove::kNothing; + + case kerberos::CLEAR_ONLY_UNMANAGED_REMEMBERED_PASSWORDS: + return !data.is_managed ? WhatToRemove::kPassword + : WhatToRemove::kNothing; + } + return WhatToRemove::kNothing; +} + } // namespace chromeos
diff --git a/chromeos/dbus/kerberos/fake_kerberos_client.h b/chromeos/dbus/kerberos/fake_kerberos_client.h index 0616ff5..668dded 100644 --- a/chromeos/dbus/kerberos/fake_kerberos_client.h +++ b/chromeos/dbus/kerberos/fake_kerberos_client.h
@@ -7,6 +7,7 @@ #include <memory> #include <string> +#include <unordered_set> #include <vector> #include "chromeos/dbus/kerberos/kerberos_client.h" @@ -72,13 +73,18 @@ bool operator!=(const AccountData& other) const; }; + enum class WhatToRemove { kNothing, kPassword, kAccount }; + + // Determines what data to remove, depending on |mode| and |data|. + static WhatToRemove DetermineWhatToRemove(kerberos::ClearMode mode, + const AccountData& data); + // Returns the AccountData for |principal_name| if available or nullptr // otherwise. AccountData* GetAccountData(const std::string& principal_name); // Maps principal name (user@REALM.COM) to account data. - using AccountsMap = std::vector<AccountData>; - AccountsMap accounts_; + std::vector<AccountData> accounts_; KerberosFilesChangedCallback kerberos_files_changed_callback_; KerberosTicketExpiringCallback kerberos_ticket_expiring_callback_;
diff --git a/chromeos/network/network_configuration_handler_unittest.cc b/chromeos/network/network_configuration_handler_unittest.cc index 46e38c5..16675fa 100644 --- a/chromeos/network/network_configuration_handler_unittest.cc +++ b/chromeos/network/network_configuration_handler_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chromeos/network/network_configuration_handler.h" + #include <stddef.h> #include <map> @@ -12,17 +14,16 @@ #include "base/json/json_writer.h" #include "base/location.h" #include "base/macros.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/string_piece.h" +#include "base/test/scoped_task_environment.h" #include "base/values.h" #include "chromeos/dbus/shill/shill_clients.h" #include "chromeos/dbus/shill/shill_manager_client.h" #include "chromeos/dbus/shill/shill_profile_client.h" #include "chromeos/dbus/shill/shill_service_client.h" -#include "chromeos/network/network_configuration_handler.h" #include "chromeos/network/network_configuration_observer.h" #include "chromeos/network/network_profile_handler.h" #include "chromeos/network/network_state.h" @@ -309,7 +310,8 @@ std::unique_ptr<NetworkConfigurationHandler> network_configuration_handler_; std::unique_ptr<TestNetworkStateHandlerObserver> network_state_handler_observer_; - base::MessageLoopForUI message_loop_; + base::test::ScopedTaskEnvironment scoped_task_environment_{ + base::test::ScopedTaskEnvironment::MainThreadType::UI}; std::string success_callback_name_; std::string get_properties_path_; std::unique_ptr<base::DictionaryValue> get_properties_;
diff --git a/chromeos/network/network_state.cc b/chromeos/network/network_state.cc index 064f19cc..d0a1f94 100644 --- a/chromeos/network/network_state.cc +++ b/chromeos/network/network_state.cc
@@ -216,6 +216,12 @@ return false; onc_source_ = ui_data->onc_source(); return true; + } else if (key == shill::kProbeUrlProperty) { + std::string probe_url_string; + if (!GetStringValue(key, value, &probe_url_string)) + return false; + probe_url_ = GURL(probe_url_string); + return true; } return false; }
diff --git a/chromeos/network/network_state.h b/chromeos/network/network_state.h index 0b3e40ea..489489e 100644 --- a/chromeos/network/network_state.h +++ b/chromeos/network/network_state.h
@@ -7,6 +7,7 @@ #include <stdint.h> +#include <memory> #include <string> #include <vector> @@ -77,6 +78,7 @@ const std::string& device_path() const { return device_path_; } const std::string& guid() const { return guid_; } const std::string& profile_path() const { return profile_path_; } + const GURL& probe_url() const { return probe_url_; } ::onc::ONCSource onc_source() const { return onc_source_; } // Provides the error for the last attempt to connect/configure the network @@ -272,6 +274,7 @@ std::string connection_state_; std::string last_connection_state_; std::string profile_path_; + GURL probe_url_; std::vector<uint8_t> raw_ssid_; // Unknown encoding. Not necessarily UTF-8. int priority_ = 0; // kPriority, used for organizing known networks. ::onc::ONCSource onc_source_ = ::onc::ONC_SOURCE_UNKNOWN;
diff --git a/chromeos/profiles/OWNERS b/chromeos/profiles/OWNERS new file mode 100644 index 0000000..0d73e4e --- /dev/null +++ b/chromeos/profiles/OWNERS
@@ -0,0 +1 @@ +per-file orderfile.newest.txt=*
diff --git a/chromeos/profiles/orderfile.newest.txt b/chromeos/profiles/orderfile.newest.txt new file mode 100644 index 0000000..9e996d0 --- /dev/null +++ b/chromeos/profiles/orderfile.newest.txt
@@ -0,0 +1 @@ +chromeos-chrome-orderfile-77.0.3849.0_rc-r1.orderfile.xz
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.h b/chromeos/services/assistant/assistant_manager_service_impl.h index faf98acd..2e60ef2a 100644 --- a/chromeos/services/assistant/assistant_manager_service_impl.h +++ b/chromeos/services/assistant/assistant_manager_service_impl.h
@@ -206,6 +206,8 @@ override {} void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override {} + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} void UpdateInternalMediaPlayerStatus( media_session::mojom::MediaSessionAction action);
diff --git a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc index f0a3a1a..a1d9b78 100644 --- a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc +++ b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.cc
@@ -62,10 +62,11 @@ android_sms_app_helper_delegate_(android_sms_app_helper_delegate) { host_status_provider_->AddObserver(this); feature_state_manager_->AddObserver(this); - InstallPwaIfNeeded(); + UpdatePwaInstallationState(); } -bool AndroidSmsAppInstallingStatusObserver::IsPwaNeeded() { +bool AndroidSmsAppInstallingStatusObserver:: + DoesFeatureStateAllowInstallation() { mojom::FeatureState feature_state = feature_state_manager_->GetFeatureStates()[mojom::Feature::kMessages]; if (feature_state != mojom::FeatureState::kEnabledByUser && @@ -84,26 +85,35 @@ return true; } -void AndroidSmsAppInstallingStatusObserver::InstallPwaIfNeeded() { - // If PWA is not needed, clear default to persist cookie that was set - // during the last installation. - if (!IsPwaNeeded()) { +void AndroidSmsAppInstallingStatusObserver::UpdatePwaInstallationState() { + if (!DoesFeatureStateAllowInstallation()) { + // The feature is disabled, ensure that the integration cookie is removed. android_sms_app_helper_delegate_->TearDownAndroidSmsApp(); return; } + if (android_sms_app_helper_delegate_->HasAppBeenManuallyUninstalledByUser()) { + feature_state_manager_->SetFeatureEnabledState(mojom::Feature::kMessages, + false); + + // The feature is now disabled, clear the cookie and pref. + android_sms_app_helper_delegate_->TearDownAndroidSmsApp(); + + return; + } + // Otherwise, set the default to persist cookie and install the PWA. android_sms_app_helper_delegate_->SetUpAndroidSmsApp(); } void AndroidSmsAppInstallingStatusObserver::OnHostStatusChange( const HostStatusProvider::HostStatusWithDevice& host_status_with_device) { - InstallPwaIfNeeded(); + UpdatePwaInstallationState(); } void AndroidSmsAppInstallingStatusObserver::OnFeatureStatesChange( const FeatureStateManager::FeatureStatesMap& feature_states_map) { - InstallPwaIfNeeded(); + UpdatePwaInstallationState(); } } // namespace multidevice_setup
diff --git a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.h b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.h index ff0500afc..c2d0ccb 100644 --- a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.h +++ b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer.h
@@ -52,8 +52,8 @@ void OnFeatureStatesChange( const FeatureStateManager::FeatureStatesMap& feature_states_map) override; - bool IsPwaNeeded(); - void InstallPwaIfNeeded(); + bool DoesFeatureStateAllowInstallation(); + void UpdatePwaInstallationState(); HostStatusProvider* host_status_provider_; FeatureStateManager* feature_state_manager_;
diff --git a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer_unittest.cc b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer_unittest.cc index caa9e26..c9a0a28 100644 --- a/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer_unittest.cc +++ b/chromeos/services/multidevice_setup/android_sms_app_installing_status_observer_unittest.cc
@@ -122,6 +122,19 @@ } TEST_F(MultiDeviceSetupAndroidSmsAppInstallingStatusObserverTest, + DoesNotInstallAfterHostVerifiedIfUninstalledByUser) { + fake_app_helper_delegate()->Reset(); + fake_app_helper_delegate()->set_has_app_been_manually_uninstalled(true); + + SetHostWithStatus(mojom::HostStatus::kNoEligibleHosts, + base::nullopt /* host_device */); + EXPECT_FALSE(fake_app_helper_delegate()->has_installed_app()); + + SetHostWithStatus(mojom::HostStatus::kHostVerified, GetFakePhone()); + EXPECT_FALSE(fake_app_helper_delegate()->has_installed_app()); +} + +TEST_F(MultiDeviceSetupAndroidSmsAppInstallingStatusObserverTest, DoesNotInstallsAfterHostVerifiedIfNotSupportedByPhone) { SetMessagesFeatureState(mojom::FeatureState::kNotSupportedByPhone); fake_app_helper_delegate()->Reset();
diff --git a/chromeos/services/multidevice_setup/feature_state_manager.cc b/chromeos/services/multidevice_setup/feature_state_manager.cc index 97eda105..46fa83e 100644 --- a/chromeos/services/multidevice_setup/feature_state_manager.cc +++ b/chromeos/services/multidevice_setup/feature_state_manager.cc
@@ -18,7 +18,9 @@ // Changing the state is only allowed when changing from enabled to disabled // or disabled to enabled. - if ((state == mojom::FeatureState::kEnabledByUser && !enabled) || + if ((((state == mojom::FeatureState::kEnabledByUser) || + (state == mojom::FeatureState::kFurtherSetupRequired)) && + !enabled) || (state == mojom::FeatureState::kDisabledByUser && enabled)) { PerformSetFeatureEnabledState(feature, enabled); return true;
diff --git a/chromeos/services/multidevice_setup/feature_state_manager.h b/chromeos/services/multidevice_setup/feature_state_manager.h index 98c259e..08447c752 100644 --- a/chromeos/services/multidevice_setup/feature_state_manager.h +++ b/chromeos/services/multidevice_setup/feature_state_manager.h
@@ -37,7 +37,8 @@ // Attempts to enable or disable the feature; returns whether this operation // succeeded. A feature can only be changed via this function if the current - // state is mojom::FeatureState::kEnabledByUser or + // state is mojom::FeatureState::kEnabledByUser, + // mojom::FeatureState::kFurtherSetupRequired or // mojom::FeatureState::kDisabledByUser. bool SetFeatureEnabledState(mojom::Feature feature, bool enabled);
diff --git a/chromeos/services/multidevice_setup/feature_state_manager_impl.cc b/chromeos/services/multidevice_setup/feature_state_manager_impl.cc index ea9545e1..04964f3 100644 --- a/chromeos/services/multidevice_setup/feature_state_manager_impl.cc +++ b/chromeos/services/multidevice_setup/feature_state_manager_impl.cc
@@ -385,6 +385,11 @@ if (feature != mojom::Feature::kMessages) return false; + if (GetEnabledOrDisabledState(feature) == + mojom::FeatureState::kDisabledByUser) { + return false; + } + return !android_sms_pairing_state_tracker_->IsAndroidSmsPairingComplete(); }
diff --git a/chromeos/services/multidevice_setup/public/cpp/android_sms_app_helper_delegate.h b/chromeos/services/multidevice_setup/public/cpp/android_sms_app_helper_delegate.h index 49841c3..e288793c 100644 --- a/chromeos/services/multidevice_setup/public/cpp/android_sms_app_helper_delegate.h +++ b/chromeos/services/multidevice_setup/public/cpp/android_sms_app_helper_delegate.h
@@ -25,6 +25,9 @@ // Cleans up previously setup Messages for Web PWA. This does not uninstall // the PWA but only clears state that was setup for the PWA. virtual void TearDownAndroidSmsApp() = 0; + // Returns true if the app was ever installed successfully since the feature + // was enabled and then been manually uninstalled by the user. + virtual bool HasAppBeenManuallyUninstalledByUser() = 0; protected: AndroidSmsAppHelperDelegate() = default;
diff --git a/chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.cc b/chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.cc index d32d0ec..c7378feec 100644 --- a/chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.cc +++ b/chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.cc
@@ -35,6 +35,10 @@ is_default_to_persist_cookie_set_ = false; } +bool FakeAndroidSmsAppHelperDelegate::HasAppBeenManuallyUninstalledByUser() { + return has_app_been_manually_uninstalled_; +} + } // namespace multidevice_setup } // namespace chromeos
diff --git a/chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.h b/chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.h index e0e28f90..a184d015 100644 --- a/chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.h +++ b/chromeos/services/multidevice_setup/public/cpp/fake_android_sms_app_helper_delegate.h
@@ -24,6 +24,11 @@ return is_default_to_persist_cookie_set_; } + void set_has_app_been_manually_uninstalled( + bool has_app_been_manually_uninstalled) { + has_app_been_manually_uninstalled_ = has_app_been_manually_uninstalled; + } + // Sets all booleans representing recorded actions to false. void Reset(); @@ -32,10 +37,12 @@ void SetUpAndroidSmsApp() override; void SetUpAndLaunchAndroidSmsApp() override; void TearDownAndroidSmsApp() override; + bool HasAppBeenManuallyUninstalledByUser() override; bool has_installed_app_ = false; bool has_launched_app_ = false; bool is_default_to_persist_cookie_set_ = false; + bool has_app_been_manually_uninstalled_ = false; DISALLOW_COPY_AND_ASSIGN(FakeAndroidSmsAppHelperDelegate); };
diff --git a/components/BUILD.gn b/components/BUILD.gn index 7c611803..4754a74e 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -295,7 +295,6 @@ "//components/gcm_driver/instance_id/android:instance_id_driver_test_support_java", "//components/invalidation/impl", "//components/invalidation/impl:java", - "//components/journey:unit_tests", "//components/policy/android:policy_java", "//components/signin/core/browser", "//components/signin/core/browser/android:java",
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index 0cd272f0..823105c 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc
@@ -1874,6 +1874,9 @@ card.GetMatchingTypes(value, app_locale, &matching_types); } + if (IsUPIVirtualPaymentAddress(value)) + matching_types.insert(UPI_VPA); + if (matching_types.empty()) { matching_types.insert(UNKNOWN_TYPE); ServerFieldTypeValidityStateMap matching_types_validities;
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h index d855b77..35472453 100644 --- a/components/autofill/core/browser/autofill_manager.h +++ b/components/autofill/core/browser/autofill_manager.h
@@ -630,6 +630,7 @@ FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DeterminePossibleFieldTypesForUploadStressTest); FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DisambiguateUploadTypes); + FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, CrowdsourceUPIVPA); FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DisabledAutofillDispatchesError); FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc index f17b106..853c5c1e 100644 --- a/components/autofill/core/browser/autofill_manager_unittest.cc +++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -83,6 +83,8 @@ using testing::_; using testing::AnyOf; using testing::AtLeast; +using testing::Contains; +using testing::ElementsAre; using testing::HasSubstr; using testing::Not; using testing::Return; @@ -5390,6 +5392,28 @@ } } +// When a field contains fields with UPI/VPA values, a crowdsourcing vote should +// be uploaded. +TEST_F(AutofillManagerTest, CrowdsourceUPIVPA) { + std::vector<AutofillProfile> profiles; + std::vector<CreditCard> credit_cards; + + FormData form; + FormFieldData field; + test::CreateTestFormField("", "name1", "1234@indianbank", "text", &field); + form.fields.push_back(field); + test::CreateTestFormField("", "name2", "not-upi@gmail.com", "text", &field); + form.fields.push_back(field); + FormStructure form_structure(form); + + AutofillManager::DeterminePossibleFieldTypesForUpload( + profiles, credit_cards, "en-us", &form_structure); + + EXPECT_THAT(form_structure.field(0)->possible_types(), ElementsAre(UPI_VPA)); + EXPECT_THAT(form_structure.field(1)->possible_types(), + Not(Contains(UPI_VPA))); +} + TEST_F(AutofillManagerTest, RemoveProfile) { // Add and remove an Autofill profile. AutofillProfile profile;
diff --git a/components/autofill/core/browser/autofill_type.cc b/components/autofill/core/browser/autofill_type.cc index 89d06bf7..a019c24 100644 --- a/components/autofill/core/browser/autofill_type.cc +++ b/components/autofill/core/browser/autofill_type.cc
@@ -107,6 +107,7 @@ case FIELD_WITH_DEFAULT_VALUE: case MERCHANT_EMAIL_SIGNUP: case MERCHANT_PROMO_CODE: + case UPI_VPA: return NO_GROUP; case MAX_VALID_FIELD_TYPE: @@ -419,15 +420,14 @@ case HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR: return CREDIT_CARD_EXP_4_DIGIT_YEAR; + case HTML_TYPE_UPI_VPA: + return UPI_VPA; + // These types aren't stored; they're transient. case HTML_TYPE_TRANSACTION_AMOUNT: case HTML_TYPE_TRANSACTION_CURRENCY: return UNKNOWN_TYPE; - // TODO(crbug/702223): Add autofill support for UPI-VPA. - case HTML_TYPE_UPI_VPA: - return UNKNOWN_TYPE; - case HTML_TYPE_UNRECOGNIZED: return UNKNOWN_TYPE; } @@ -783,6 +783,8 @@ return "SINGLE_USERNAME"; case NOT_USERNAME: return "NOT_USERNAME"; + case UPI_VPA: + return "UPI_VPA"; case AMBIGUOUS_TYPE: return "AMBIGUOUS_TYPE"; case MAX_VALID_FIELD_TYPE:
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h index 8be69f9..3080ba1 100644 --- a/components/autofill/core/browser/field_types.h +++ b/components/autofill/core/browser/field_types.h
@@ -185,9 +185,13 @@ // Text-type fields which are not usernames. NOT_USERNAME = 101, + // UPI/VPA is a payment method, which is stored and filled. See + // https://en.wikipedia.org/wiki/Unified_Payments_Interface + UPI_VPA = 102, + // No new types can be added without a corresponding change to the Autofill // server. - MAX_VALID_FIELD_TYPE = 102, + MAX_VALID_FIELD_TYPE = 103, }; // The list of all HTML autocomplete field type hints supported by Chrome.
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc index 9483f6a..1f4246d 100644 --- a/components/autofill/core/browser/form_structure.cc +++ b/components/autofill/core/browser/form_structure.cc
@@ -454,12 +454,16 @@ const FormSignature form_signature = form.form_signature(); constexpr FieldSignature kNullFieldSignature = 0; // Not relevant for form level metadata. - EncodeRandomizedValue(encoder, form_signature, kNullFieldSignature, - RandomizedEncoder::FORM_ID, form.id_attribute(), - metadata->mutable_id()); - EncodeRandomizedValue(encoder, form_signature, kNullFieldSignature, - RandomizedEncoder::FORM_NAME, form.name_attribute(), - metadata->mutable_name()); + if (!form.id_attribute().empty()) { + EncodeRandomizedValue(encoder, form_signature, kNullFieldSignature, + RandomizedEncoder::FORM_ID, form.id_attribute(), + metadata->mutable_id()); + } + if (!form.name_attribute().empty()) { + EncodeRandomizedValue(encoder, form_signature, kNullFieldSignature, + RandomizedEncoder::FORM_NAME, form.name_attribute(), + metadata->mutable_name()); + } } void PopulateRandomizedFieldMetadata( @@ -469,32 +473,47 @@ AutofillRandomizedFieldMetadata* metadata) { const FormSignature form_signature = form.form_signature(); const FieldSignature field_signature = field.GetFieldSignature(); - EncodeRandomizedValue(encoder, form_signature, field_signature, - RandomizedEncoder::FIELD_ID, field.id_attribute, - metadata->mutable_id()); - EncodeRandomizedValue(encoder, form_signature, field_signature, - RandomizedEncoder::FIELD_NAME, field.name_attribute, - metadata->mutable_name()); - EncodeRandomizedValue(encoder, form_signature, field_signature, - RandomizedEncoder::FIELD_CONTROL_TYPE, - field.form_control_type, metadata->mutable_type()); - EncodeRandomizedValue(encoder, form_signature, field_signature, - RandomizedEncoder::FIELD_LABEL, field.label, - metadata->mutable_label()); - EncodeRandomizedValue(encoder, form_signature, field_signature, - RandomizedEncoder::FIELD_ARIA_LABEL, field.aria_label, - metadata->mutable_aria_label()); - EncodeRandomizedValue(encoder, form_signature, field_signature, - RandomizedEncoder::FIELD_ARIA_DESCRIPTION, - field.aria_description, - metadata->mutable_aria_description()); - EncodeRandomizedValue(encoder, form_signature, field_signature, - RandomizedEncoder::FIELD_CSS_CLASS, field.css_classes, - metadata->mutable_css_class()); - EncodeRandomizedValue(encoder, form_signature, field_signature, - RandomizedEncoder::FIELD_PLACEHOLDER, field.placeholder, - metadata->mutable_placeholder()); - // TODO(rogerm): Add hash of initial value. + if (!field.id_attribute.empty()) { + EncodeRandomizedValue(encoder, form_signature, field_signature, + RandomizedEncoder::FIELD_ID, field.id_attribute, + metadata->mutable_id()); + } + if (!field.name_attribute.empty()) { + EncodeRandomizedValue(encoder, form_signature, field_signature, + RandomizedEncoder::FIELD_NAME, field.name_attribute, + metadata->mutable_name()); + } + if (!field.form_control_type.empty()) { + EncodeRandomizedValue(encoder, form_signature, field_signature, + RandomizedEncoder::FIELD_CONTROL_TYPE, + field.form_control_type, metadata->mutable_type()); + } + if (!field.label.empty()) { + EncodeRandomizedValue(encoder, form_signature, field_signature, + RandomizedEncoder::FIELD_LABEL, field.label, + metadata->mutable_label()); + } + if (!field.aria_label.empty()) { + EncodeRandomizedValue(encoder, form_signature, field_signature, + RandomizedEncoder::FIELD_ARIA_LABEL, field.aria_label, + metadata->mutable_aria_label()); + } + if (!field.aria_description.empty()) { + EncodeRandomizedValue(encoder, form_signature, field_signature, + RandomizedEncoder::FIELD_ARIA_DESCRIPTION, + field.aria_description, + metadata->mutable_aria_description()); + } + if (!field.css_classes.empty()) { + EncodeRandomizedValue(encoder, form_signature, field_signature, + RandomizedEncoder::FIELD_CSS_CLASS, field.css_classes, + metadata->mutable_css_class()); + } + if (!field.placeholder.empty()) { + EncodeRandomizedValue(encoder, form_signature, field_signature, + RandomizedEncoder::FIELD_PLACEHOLDER, + field.placeholder, metadata->mutable_placeholder()); + } } void EncodeFormMetadataForQuery(const FormStructure& form,
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc index e9e4ee7..7ebf1c720 100644 --- a/components/autofill/core/browser/form_structure_unittest.cc +++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -4487,9 +4487,12 @@ {"email_id", "email_name", "Email:", "Please enter your email address", "Type your email address", "You can type your email address here", "blah"}, + {"id_only", "", "", "", "", "", ""}, + {"", "name_only", "", "", "", "", ""}, }; FormData form; + form.id_attribute = ASCIIToUTF16("form-id"); form.url = GURL("http://www.foo.com/"); for (const auto& f : kFieldMetadata) { FormFieldData field; @@ -4518,49 +4521,91 @@ &upload)); const auto form_signature = form_structure.form_signature(); - EXPECT_EQ(upload.randomized_form_metadata().id().encoded_bits(), - encoder.Encode(form_signature, 0, RandomizedEncoder::FORM_ID, - form_structure.id_attribute())); - EXPECT_EQ(upload.randomized_form_metadata().name().encoded_bits(), - encoder.Encode(form_signature, 0, RandomizedEncoder::FORM_NAME, - form_structure.name_attribute())); + if (form.id_attribute.empty()) { + EXPECT_FALSE(upload.randomized_form_metadata().has_id()); + } else { + EXPECT_EQ(upload.randomized_form_metadata().id().encoded_bits(), + encoder.Encode(form_signature, 0, RandomizedEncoder::FORM_ID, + form_structure.id_attribute())); + } + + if (form.name_attribute.empty()) { + EXPECT_FALSE(upload.randomized_form_metadata().has_name()); + } else { + EXPECT_EQ(upload.randomized_form_metadata().name().encoded_bits(), + encoder.Encode(form_signature, 0, RandomizedEncoder::FORM_NAME, + form_structure.name_attribute())); + } ASSERT_EQ(static_cast<size_t>(upload.field_size()), base::size(kFieldMetadata)); for (int i = 0; i < upload.field_size(); ++i) { const auto& metadata = upload.field(i).randomized_field_metadata(); const auto& field = *form_structure.field(i); const auto field_signature = field.GetFieldSignature(); - EXPECT_EQ(metadata.id().encoded_bits(), - encoder.Encode(form_signature, field_signature, - RandomizedEncoder::FIELD_ID, field.id_attribute)); - EXPECT_EQ( - metadata.name().encoded_bits(), - encoder.Encode(form_signature, field_signature, - RandomizedEncoder::FIELD_NAME, field.name_attribute)); - EXPECT_EQ(metadata.type().encoded_bits(), - encoder.Encode(form_signature, field_signature, - RandomizedEncoder::FIELD_CONTROL_TYPE, - field.form_control_type)); - EXPECT_EQ(metadata.label().encoded_bits(), - encoder.Encode(form_signature, field_signature, - RandomizedEncoder::FIELD_LABEL, field.label)); - EXPECT_EQ( - metadata.aria_label().encoded_bits(), - encoder.Encode(form_signature, field_signature, - RandomizedEncoder::FIELD_ARIA_LABEL, field.aria_label)); - EXPECT_EQ(metadata.aria_description().encoded_bits(), - encoder.Encode(form_signature, field_signature, - RandomizedEncoder::FIELD_ARIA_DESCRIPTION, - field.aria_description)); - EXPECT_EQ( - metadata.css_class().encoded_bits(), - encoder.Encode(form_signature, field_signature, - RandomizedEncoder::FIELD_CSS_CLASS, field.css_classes)); - EXPECT_EQ(metadata.placeholder().encoded_bits(), - encoder.Encode(form_signature, field_signature, - RandomizedEncoder::FIELD_PLACEHOLDER, - field.placeholder)); + if (field.id_attribute.empty()) { + EXPECT_FALSE(metadata.has_id()); + } else { + EXPECT_EQ( + metadata.id().encoded_bits(), + encoder.Encode(form_signature, field_signature, + RandomizedEncoder::FIELD_ID, field.id_attribute)); + } + if (field.name.empty()) { + EXPECT_FALSE(metadata.has_name()); + } else { + EXPECT_EQ( + metadata.name().encoded_bits(), + encoder.Encode(form_signature, field_signature, + RandomizedEncoder::FIELD_NAME, field.name_attribute)); + } + if (field.form_control_type.empty()) { + EXPECT_FALSE(metadata.has_type()); + } else { + EXPECT_EQ(metadata.type().encoded_bits(), + encoder.Encode(form_signature, field_signature, + RandomizedEncoder::FIELD_CONTROL_TYPE, + field.form_control_type)); + } + if (field.label.empty()) { + EXPECT_FALSE(metadata.has_label()); + } else { + EXPECT_EQ(metadata.label().encoded_bits(), + encoder.Encode(form_signature, field_signature, + RandomizedEncoder::FIELD_LABEL, field.label)); + } + if (field.aria_label.empty()) { + EXPECT_FALSE(metadata.has_aria_label()); + } else { + EXPECT_EQ(metadata.aria_label().encoded_bits(), + encoder.Encode(form_signature, field_signature, + RandomizedEncoder::FIELD_ARIA_LABEL, + field.aria_label)); + } + if (field.aria_description.empty()) { + EXPECT_FALSE(metadata.has_aria_description()); + } else { + EXPECT_EQ(metadata.aria_description().encoded_bits(), + encoder.Encode(form_signature, field_signature, + RandomizedEncoder::FIELD_ARIA_DESCRIPTION, + field.aria_description)); + } + if (field.css_classes.empty()) { + EXPECT_FALSE(metadata.has_css_class()); + } else { + EXPECT_EQ(metadata.css_class().encoded_bits(), + encoder.Encode(form_signature, field_signature, + RandomizedEncoder::FIELD_CSS_CLASS, + field.css_classes)); + } + if (field.placeholder.empty()) { + EXPECT_FALSE(metadata.has_placeholder()); + } else { + EXPECT_EQ(metadata.placeholder().encoded_bits(), + encoder.Encode(form_signature, field_signature, + RandomizedEncoder::FIELD_PLACEHOLDER, + field.placeholder)); + } } }
diff --git a/components/autofill/core/common/autofill_payments_features.cc b/components/autofill/core/common/autofill_payments_features.cc index b138227a..1b376c7 100644 --- a/components/autofill/core/common/autofill_payments_features.cc +++ b/components/autofill/core/common/autofill_payments_features.cc
@@ -54,7 +54,7 @@ const base::Feature kAutofillDoNotUploadSaveUnsupportedCards{ "AutofillDoNotUploadSaveUnsupportedCards", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // Controls whether the credit card downstream keyboard accessory shows // the Google Pay logo animation on iOS.
diff --git a/components/autofill/core/common/autofill_regexes.cc b/components/autofill/core/common/autofill_regexes.cc index 3c289e3..c4402bc 100644 --- a/components/autofill/core/common/autofill_regexes.cc +++ b/components/autofill/core/common/autofill_regexes.cc
@@ -8,11 +8,11 @@ #include <unordered_map> #include <utility> -#include "base/lazy_instance.h" #include "base/logging.h" #include "base/macros.h" +#include "base/no_destructor.h" #include "base/strings/string16.h" -#include "base/threading/thread_local.h" +#include "base/synchronization/lock.h" #include "third_party/icu/source/i18n/unicode/regex.h" namespace { @@ -24,14 +24,13 @@ // singleton instance (https://crbug.com/812182). class AutofillRegexes { public: - static AutofillRegexes* ThreadSpecificInstance(); + AutofillRegexes() = default; // Returns the compiled regex matcher corresponding to |pattern|. icu::RegexMatcher* GetMatcher(const base::string16& pattern); private: - AutofillRegexes(); - ~AutofillRegexes(); + ~AutofillRegexes() = default; // Maps patterns to their corresponding regex matchers. std::unordered_map<base::string16, std::unique_ptr<icu::RegexMatcher>> @@ -40,24 +39,6 @@ DISALLOW_COPY_AND_ASSIGN(AutofillRegexes); }; -base::LazyInstance<base::ThreadLocalPointer<AutofillRegexes>>::Leaky - g_autofill_regexes_tls = LAZY_INSTANCE_INITIALIZER; - -// static -AutofillRegexes* AutofillRegexes::ThreadSpecificInstance() { - if (g_autofill_regexes_tls.Pointer()->Get()) - return g_autofill_regexes_tls.Pointer()->Get(); - return new AutofillRegexes; -} - -AutofillRegexes::AutofillRegexes() { - g_autofill_regexes_tls.Pointer()->Set(this); -} - -AutofillRegexes::~AutofillRegexes() { - g_autofill_regexes_tls.Pointer()->Set(nullptr); -} - icu::RegexMatcher* AutofillRegexes::GetMatcher(const base::string16& pattern) { auto it = matchers_.find(pattern); if (it == matchers_.end()) { @@ -82,8 +63,11 @@ bool MatchesPattern(const base::string16& input, const base::string16& pattern) { - icu::RegexMatcher* matcher = - AutofillRegexes::ThreadSpecificInstance()->GetMatcher(pattern); + static base::NoDestructor<AutofillRegexes> g_autofill_regexes; + static base::NoDestructor<base::Lock> g_lock; + base::AutoLock lock(*g_lock); + + icu::RegexMatcher* matcher = g_autofill_regexes->GetMatcher(pattern); icu::UnicodeString icu_input(FALSE, input.data(), input.length()); matcher->reset(icu_input);
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h index d00a57e..0001d5b 100644 --- a/components/autofill_assistant/browser/actions/action_delegate.h +++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -284,6 +284,11 @@ std::unique_ptr<FormProto> form, base::RepeatingCallback<void(const FormProto::Result*)> callback) = 0; + // Force showing the UI if no UI is shown. This is useful when executing a + // direct action which realizes it needs to interact with the user. Once + // shown, the UI stays up until the end of the flow. + virtual void RequireUI() = 0; + protected: ActionDelegate() = default; };
diff --git a/components/autofill_assistant/browser/actions/get_payment_information_action.cc b/components/autofill_assistant/browser/actions/get_payment_information_action.cc index 6e564f309..1197df8 100644 --- a/components/autofill_assistant/browser/actions/get_payment_information_action.cc +++ b/components/autofill_assistant/browser/actions/get_payment_information_action.cc
@@ -57,6 +57,9 @@ payment_options->additional_actions_callback = base::BindOnce(&GetPaymentInformationAction::OnAdditionalActionTriggered, weak_ptr_factory_.GetWeakPtr()); + payment_options->terms_link_callback = base::BindOnce( + &GetPaymentInformationAction::OnTermsAndConditionsLinkClicked, + weak_ptr_factory_.GetWeakPtr()); // Gather info for UMA histograms. if (!presented_to_user_) { @@ -156,13 +159,21 @@ std::move(callback_).Run(std::move(processed_action_proto_)); } +void GetPaymentInformationAction::OnTermsAndConditionsLinkClicked(int link) { + if (!callback_) + return; + + UpdateProcessedAction(ACTION_APPLIED); + processed_action_proto_->mutable_payment_details()->set_terms_link(link); + action_successful_ = true; + std::move(callback_).Run(std::move(processed_action_proto_)); +} + std::unique_ptr<PaymentRequestOptions> GetPaymentInformationAction::CreateOptionsFromProto() const { auto payment_options = std::make_unique<PaymentRequestOptions>(); auto get_payment_information = proto_.get_payment_information(); - payment_options->request_terms_and_conditions = - get_payment_information.request_terms_and_conditions(); if (get_payment_information.has_contact_details()) { auto contact_details = get_payment_information.contact_details(); payment_options->request_payer_email = @@ -208,6 +219,19 @@ payment_options->initial_terms_and_conditions = REQUIRES_REVIEW; break; } + + if (get_payment_information.request_terms_and_conditions()) { + payment_options->show_terms_as_checkbox = + get_payment_information.show_terms_as_checkbox(); + payment_options->accept_terms_and_conditions_text = + get_payment_information.accept_terms_and_conditions_text(); + if (payment_options->accept_terms_and_conditions_text.empty()) { + payment_options->accept_terms_and_conditions_text = + l10n_util::GetStringUTF8( + IDS_AUTOFILL_ASSISTANT_3RD_PARTY_TERMS_ACCEPT); + } + } + return payment_options; }
diff --git a/components/autofill_assistant/browser/actions/get_payment_information_action.h b/components/autofill_assistant/browser/actions/get_payment_information_action.h index 6a21aea..2de78be 100644 --- a/components/autofill_assistant/browser/actions/get_payment_information_action.h +++ b/components/autofill_assistant/browser/actions/get_payment_information_action.h
@@ -37,6 +37,7 @@ const GetPaymentInformationProto& get_payment_information, std::unique_ptr<PaymentInformation> payment_information); void OnAdditionalActionTriggered(int index); + void OnTermsAndConditionsLinkClicked(int link); // Creates a new instance of |PaymentRequestOptions| from |proto_|. std::unique_ptr<PaymentRequestOptions> CreateOptionsFromProto() const;
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h index c725031e..04225f2 100644 --- a/components/autofill_assistant/browser/actions/mock_action_delegate.h +++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -186,6 +186,8 @@ MOCK_METHOD1(OnWaitForWindowHeightChange, void(base::OnceCallback<void(const ClientStatus&)>& callback)); + MOCK_METHOD0(RequireUI, void()); + const ClientSettings& GetSettings() override { return client_settings_; } ClientSettings client_settings_;
diff --git a/components/autofill_assistant/browser/actions/tell_action.cc b/components/autofill_assistant/browser/actions/tell_action.cc index 4ed6eba8..c2f6260 100644 --- a/components/autofill_assistant/browser/actions/tell_action.cc +++ b/components/autofill_assistant/browser/actions/tell_action.cc
@@ -21,6 +21,10 @@ void TellAction::InternalProcessAction(ProcessActionCallback callback) { // tell.message in the proto is localized. delegate_->SetStatusMessage(proto_.tell().message()); + + if (proto_.tell().needs_ui()) + delegate_->RequireUI(); + UpdateProcessedAction(ACTION_APPLIED); std::move(callback).Run(std::move(processed_action_proto_)); }
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc index 3577b638..a8fff0c 100644 --- a/components/autofill_assistant/browser/controller.cc +++ b/components/autofill_assistant/browser/controller.cc
@@ -41,6 +41,49 @@ // Parameter that allows setting the color of the overlay. static const char* const kOverlayColorParameterName = "OVERLAY_COLORS"; +// Returns true if the state requires a UI to be shown. +// +// Note that the UI might be shown in RUNNING state, even if it doesn't require +// it. +bool StateNeedsUI(AutofillAssistantState state) { + switch (state) { + case AutofillAssistantState::STARTING: + case AutofillAssistantState::PROMPT: + case AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT: + case AutofillAssistantState::MODAL_DIALOG: + return true; + + case AutofillAssistantState::INACTIVE: + case AutofillAssistantState::TRACKING: + case AutofillAssistantState::STOPPED: + case AutofillAssistantState::RUNNING: + return false; + } + + NOTREACHED(); + return false; +} + +// Returns true if reaching that state signals the end of a flow. +bool StateEndsFlow(AutofillAssistantState state) { + switch (state) { + case AutofillAssistantState::TRACKING: + case AutofillAssistantState::STOPPED: + return true; + + case AutofillAssistantState::INACTIVE: + case AutofillAssistantState::STARTING: + case AutofillAssistantState::PROMPT: + case AutofillAssistantState::RUNNING: + case AutofillAssistantState::AUTOSTART_FALLBACK_PROMPT: + case AutofillAssistantState::MODAL_DIALOG: + return false; + } + + NOTREACHED(); + return false; +} + } // namespace Controller::Controller(content::WebContents* web_contents, @@ -217,6 +260,14 @@ return navigation_error_; } +void Controller::RequireUI() { + if (needs_ui_) + return; + + needs_ui_ = true; + client_->AttachUI(); +} + void Controller::AddListener(ScriptExecutorDelegate::Listener* listener) { auto found = std::find(listeners_.begin(), listeners_.end(), listener); if (found == listeners_.end()) @@ -446,15 +497,17 @@ DCHECK(state_ != AutofillAssistantState::STOPPED || (state == AutofillAssistantState::TRACKING && tracking_)); - bool old_needs_ui = NeedsUI(); state_ = state; for (ControllerObserver& observer : observers_) { observer.OnStateChanged(state); } - if (!old_needs_ui && NeedsUI()) - client_->AttachUI(); + if (!needs_ui_ && StateNeedsUI(state)) { + RequireUI(); + } else if (needs_ui_ && StateEndsFlow(state)) { + needs_ui_ = false; + } if (ShouldCheckScripts()) { GetOrCheckScripts(); @@ -538,7 +591,8 @@ std::string script_path = autostart_timeout_script_path_; autostart_timeout_script_path_.clear(); periodic_script_check_scheduled_ = false; - ExecuteScript(script_path, TriggerContext::CreateEmpty(), state_); + ExecuteScript(script_path, /* start_message= */ "", /* needs_ui= */ false, + TriggerContext::CreateEmpty(), state_); return; } @@ -622,11 +676,18 @@ } void Controller::ExecuteScript(const std::string& script_path, + const std::string& start_message, + bool needs_ui, std::unique_ptr<TriggerContext> context, AutofillAssistantState end_state) { DCHECK(!script_tracker()->running()); + if (!start_message.empty()) + SetStatusMessage(start_message); + EnterState(AutofillAssistantState::RUNNING); + if (needs_ui) + RequireUI(); touchable_element_area()->Clear(); @@ -712,20 +773,30 @@ if (!allow_autostart()) return false; - int autostart_count = 0; - std::string autostart_path; - for (const auto& script : runnable_scripts) { - if (script.autostart) { - autostart_count++; - autostart_path = script.path; + int autostart_index = -1; + for (size_t i = 0; i < runnable_scripts.size(); i++) { + if (runnable_scripts[i].autostart) { + if (autostart_index != -1) { + // To many autostartable scripts. + return false; + } + autostart_index = i; } } - if (autostart_count == 1) { - ExecuteScript(autostart_path, TriggerContext::CreateEmpty(), - AutofillAssistantState::PROMPT); - return true; - } - return false; + + if (autostart_index == -1) + return false; + + // Copying the strings is necessary, as ExecuteScript will invalidate + // runnable_scripts by calling ScriptTracker::ClearRunnableScripts. + // + // TODO(b/138367403): Cleanup this dangerous issue. + std::string path = runnable_scripts[autostart_index].path; + std::string start_message = runnable_scripts[autostart_index].start_message; + bool needs_ui = runnable_scripts[autostart_index].needs_ui; + ExecuteScript(path, start_message, needs_ui, TriggerContext::CreateEmpty(), + AutofillAssistantState::PROMPT); + return true; } void Controller::InitFromParameters() { @@ -772,12 +843,6 @@ } } -bool Controller::NeedsUI() const { - return state_ != AutofillAssistantState::INACTIVE && - state_ != AutofillAssistantState::TRACKING && - state_ != AutofillAssistantState::STOPPED; -} - bool Controller::Start(const GURL& deeplink_url, std::unique_ptr<TriggerContext> trigger_context) { if (state_ != AutofillAssistantState::INACTIVE && @@ -803,10 +868,10 @@ return state_; } -void Controller::OnScriptSelected(const std::string& script_path, +void Controller::OnScriptSelected(const ScriptHandle& handle, std::unique_ptr<TriggerContext> context) { - DCHECK(!script_path.empty()); - ExecuteScript(script_path, std::move(context), + ExecuteScript(handle.path, handle.start_message, handle.needs_ui, + std::move(context), state_ == AutofillAssistantState::TRACKING ? AutofillAssistantState::TRACKING : AutofillAssistantState::PROMPT); @@ -880,6 +945,15 @@ std::move(callback).Run(index); } +void Controller::OnTermsAndConditionsLinkClicked(int link) { + if (!payment_request_info_) + return; + + auto callback = std::move(payment_request_options_->terms_link_callback); + SetPaymentRequestOptions(nullptr); + std::move(callback).Run(link); +} + void Controller::SetShippingAddress( std::unique_ptr<autofill::AutofillProfile> address) { if (!payment_request_info_) @@ -948,6 +1022,7 @@ // should update the action buttons only if there are use cases of PR + // suggestions. if (!payment_request_options_ || !payment_request_info_) { + SetUserActions(nullptr); return; } @@ -964,8 +1039,9 @@ bool payment_method_ok = !payment_request_options_->request_payment_method || payment_request_info_->card; - bool terms_ok = payment_request_info_->terms_and_conditions != NOT_SELECTED || - !payment_request_options_->request_terms_and_conditions; + bool terms_ok = + payment_request_info_->terms_and_conditions != NOT_SELECTED || + payment_request_options_->accept_terms_and_conditions_text.empty(); bool confirm_button_enabled = contact_info_ok && shipping_address_ok && payment_method_ok && terms_ok; @@ -1014,6 +1090,7 @@ if (state_ == AutofillAssistantState::STOPPED) return; + RequireUI(); SetStatusMessage(error_message); EnterStoppedState(); @@ -1140,9 +1217,8 @@ if (!user_action.has_triggers()) continue; - user_action.SetCallback(base::BindOnce(&Controller::OnScriptSelected, - weak_ptr_factory_.GetWeakPtr(), - script.path)); + user_action.SetCallback(base::BindOnce( + &Controller::OnScriptSelected, weak_ptr_factory_.GetWeakPtr(), script)); user_actions->emplace_back(std::move(user_action)); } @@ -1264,7 +1340,8 @@ void Controller::SetPaymentRequestOptions( std::unique_ptr<PaymentRequestOptions> options) { DCHECK(!options || - (options->confirm_callback && options->additional_actions_callback)); + (options->confirm_callback && options->additional_actions_callback && + options->terms_link_callback)); if (payment_request_options_ == nullptr && options == nullptr) return;
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h index 4450a74..38325f9 100644 --- a/components/autofill_assistant/browser/controller.h +++ b/components/autofill_assistant/browser/controller.h
@@ -85,7 +85,7 @@ std::unique_ptr<TriggerContext> trigger_context); // Returns true if the controller is in a state where UI is necessary. - bool NeedsUI() const; + bool NeedsUI() const { return needs_ui_; } // Overrides ScriptExecutorDelegate: const ClientSettings& GetSettings() override; @@ -116,6 +116,11 @@ override; bool IsNavigatingToNewDocument() override; bool HasNavigationError() override; + + // Show the UI if it's not already shown. This is only meaningful while in + // states where showing the UI is optional, such as RUNNING, in tracking mode. + void RequireUI() override; + void AddListener(ScriptExecutorDelegate::Listener* listener) override; void RemoveListener(ScriptExecutorDelegate::Listener* listener) override; @@ -150,6 +155,7 @@ void SetCreditCard(std::unique_ptr<autofill::CreditCard> card) override; void SetTermsAndConditions( TermsAndConditionsState terms_and_conditions) override; + void OnTermsAndConditionsLinkClicked(int link) override; void GetTouchableArea(std::vector<RectF>* area) const override; void GetRestrictedArea(std::vector<RectF>* area) const override; void GetVisualViewport(RectF* visual_viewport) const override; @@ -189,6 +195,8 @@ // Execute |script_path| and, if execution succeeds, enter |end_state| and // call |on_success|. void ExecuteScript(const std::string& script_path, + const std::string& start_message, + bool needs_ui, std::unique_ptr<TriggerContext> context, AutofillAssistantState end_state); void OnScriptExecuted(const std::string& script_path, @@ -213,7 +221,7 @@ void InitFromParameters(); // Called when a script is selected. - void OnScriptSelected(const std::string& script_path, + void OnScriptSelected(const ScriptHandle& handle, std::unique_ptr<TriggerContext> context); void UpdatePaymentRequestActions(); @@ -364,6 +372,9 @@ // This is set by Track(). bool tracking_ = false; + // Whether the controller is in a state in which a UI should be shown. + bool needs_ui_ = false; + // True once the controller has run the first set of scripts and have either // declared it invalid - and entered stopped state - or have processed its // result - and updated the state and set of available actions.
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc index 920e4a9..fbedd27b 100644 --- a/components/autofill_assistant/browser/controller_unittest.cc +++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -462,6 +462,26 @@ EXPECT_EQ("script3 prompt", controller_->GetStatusMessage()); } +TEST_F(ControllerTest, ScriptStartMessage) { + SupportsScriptResponseProto script_response; + auto* script = AddRunnableScript(&script_response, "script"); + script->mutable_presentation()->set_start_message("Starting Script..."); + SetNextScriptResponse(script_response); + + ActionsResponseProto script_actions; + script_actions.add_actions()->mutable_tell()->set_message("Script running."); + SetupActionsForScript("script", script_actions); + + Start("http://a.example.com/path"); + + { + testing::InSequence seq; + EXPECT_CALL(mock_observer_, OnStatusMessageChanged("Starting Script...")); + EXPECT_CALL(mock_observer_, OnStatusMessageChanged("Script running.")); + } + EXPECT_TRUE(controller_->PerformUserAction(0)); +} + TEST_F(ControllerTest, Stop) { SupportsScriptResponseProto script_response; AddRunnableScript(&script_response, "stop"); @@ -1019,6 +1039,100 @@ SimulateNavigateToUrl(GURL("http://c.example.com/")); } +TEST_F(ControllerTest, TrackScriptWithNoUI) { + // The UI is never shown during this test. + EXPECT_CALL(fake_client_, AttachUI()).Times(0); + + SupportsScriptResponseProto script_response; + auto* script = AddRunnableScript(&script_response, "runnable"); + script->mutable_presentation()->set_needs_ui(false); + SetupScripts(script_response); + + // Script does nothing + ActionsResponseProto runnable_script; + auto* hidden_tell = runnable_script.add_actions()->mutable_tell(); + hidden_tell->set_message("optional message"); + hidden_tell->set_needs_ui(false); + runnable_script.add_actions()->mutable_stop(); + SetupActionsForScript("runnable", runnable_script); + + // Start tracking at example.com, with one script matching + SetLastCommittedUrl(GURL("http://example.com/")); + + controller_->Track(TriggerContext::CreateEmpty(), base::DoNothing()); + ASSERT_THAT(controller_->GetUserActions(), SizeIs(1)); + + EXPECT_TRUE(controller_->PerformUserAction(0)); + EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState()); + + // Check the full history of state transitions. + EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING, + AutofillAssistantState::RUNNING, + AutofillAssistantState::TRACKING)); +} + +TEST_F(ControllerTest, TrackScriptShowUIOnTell) { + SupportsScriptResponseProto script_response; + auto* script = AddRunnableScript(&script_response, "runnable"); + script->mutable_presentation()->set_needs_ui(false); + SetupScripts(script_response); + + ActionsResponseProto runnable_script; + runnable_script.add_actions()->mutable_tell()->set_message("error"); + SetupActionsForScript("runnable", runnable_script); + + // Start tracking at example.com, with one script matching + SetLastCommittedUrl(GURL("http://example.com/")); + + controller_->Track(TriggerContext::CreateEmpty(), base::DoNothing()); + ASSERT_THAT(controller_->GetUserActions(), SizeIs(1)); + + EXPECT_FALSE(controller_->NeedsUI()); + EXPECT_CALL(fake_client_, AttachUI()); + EXPECT_TRUE(controller_->PerformUserAction(0)); + EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState()); + + // As the controller is back in tracking mode; A UI is not needed anymore. + EXPECT_FALSE(controller_->NeedsUI()); + + // Check the full history of state transitions. + EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING, + AutofillAssistantState::RUNNING, + AutofillAssistantState::TRACKING)); +} + +TEST_F(ControllerTest, TrackScriptShowUIOnError) { + SupportsScriptResponseProto script_response; + auto* script = AddRunnableScript(&script_response, "runnable"); + script->mutable_presentation()->set_needs_ui(false); + SetupScripts(script_response); + + // Running the script fails, due to a backend issue. The error message should + // be shown. + EXPECT_CALL(*mock_service_, OnGetActions(_, _, _, _, _, _)) + .WillOnce(RunOnceCallback<5>(false, "")); + + // Start tracking at example.com, with one script matching + SetLastCommittedUrl(GURL("http://example.com/")); + + controller_->Track(TriggerContext::CreateEmpty(), base::DoNothing()); + ASSERT_THAT(controller_->GetUserActions(), SizeIs(1)); + + EXPECT_FALSE(controller_->NeedsUI()); + EXPECT_CALL(fake_client_, AttachUI()); + EXPECT_TRUE(controller_->PerformUserAction(0)); + EXPECT_EQ(AutofillAssistantState::TRACKING, controller_->GetState()); + + // As the controller is back in tracking mode; A UI is not needed anymore. + EXPECT_FALSE(controller_->NeedsUI()); + + // Check the full history of state transitions. + EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::TRACKING, + AutofillAssistantState::RUNNING, + AutofillAssistantState::STOPPED, + AutofillAssistantState::TRACKING)); +} + TEST_F(ControllerTest, TrackContinuesAfterScriptError) { SupportsScriptResponseProto script_response; AddRunnableScript(&script_response, "runnable");
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.cc b/components/autofill_assistant/browser/fake_script_executor_delegate.cc index 16615caa..dd6874d 100644 --- a/components/autofill_assistant/browser/fake_script_executor_delegate.cc +++ b/components/autofill_assistant/browser/fake_script_executor_delegate.cc
@@ -124,6 +124,10 @@ return navigating_to_new_document_; } +void FakeScriptExecutorDelegate::RequireUI() { + require_ui_ = true; +} + void FakeScriptExecutorDelegate::AddListener(Listener* listener) { listeners_.insert(listener); }
diff --git a/components/autofill_assistant/browser/fake_script_executor_delegate.h b/components/autofill_assistant/browser/fake_script_executor_delegate.h index 989897e..2d1e66ef 100644 --- a/components/autofill_assistant/browser/fake_script_executor_delegate.h +++ b/components/autofill_assistant/browser/fake_script_executor_delegate.h
@@ -58,6 +58,7 @@ override; bool HasNavigationError() override; bool IsNavigatingToNewDocument() override; + void RequireUI() override; void AddListener(Listener* listener) override; void RemoveListener(Listener* listener) override; @@ -96,6 +97,8 @@ bool HasListeners() { return !listeners_.empty(); } + bool IsUIRequired() { return require_ui_; } + private: ClientSettings client_settings_; GURL current_url_; @@ -115,6 +118,7 @@ bool resize_viewport_ = false; ConfigureBottomSheetProto::PeekMode peek_mode_ = ConfigureBottomSheetProto::HANDLE; + bool require_ui_ = false; DISALLOW_COPY_AND_ASSIGN(FakeScriptExecutorDelegate); };
diff --git a/components/autofill_assistant/browser/payment_request.h b/components/autofill_assistant/browser/payment_request.h index 2e1c2ac..c2b3c151 100644 --- a/components/autofill_assistant/browser/payment_request.h +++ b/components/autofill_assistant/browser/payment_request.h
@@ -54,7 +54,11 @@ bool request_payer_phone = false; bool request_shipping = false; bool request_payment_method = false; - bool request_terms_and_conditions = true; + + // If empty, terms and conditions should not be shown. + std::string accept_terms_and_conditions_text; + bool show_terms_as_checkbox = false; + std::vector<std::string> supported_basic_card_networks; std::string default_email; UserActionProto confirm_action; @@ -64,6 +68,7 @@ base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> confirm_callback; base::OnceCallback<void(int)> additional_actions_callback; + base::OnceCallback<void(int)> terms_link_callback; }; } // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/protocol_utils.cc b/components/autofill_assistant/browser/protocol_utils.cc index 2223653..2cff627 100644 --- a/components/autofill_assistant/browser/protocol_utils.cc +++ b/components/autofill_assistant/browser/protocol_utils.cc
@@ -100,6 +100,8 @@ script->handle.chip = Chip(presentation.chip()); } script->handle.direct_action = DirectAction(presentation.direct_action()); + script->handle.start_message = presentation.start_message(); + script->handle.needs_ui = presentation.needs_ui(); scripts->emplace_back(std::move(script)); }
diff --git a/components/autofill_assistant/browser/script.cc b/components/autofill_assistant/browser/script.cc index 1efb8fe..4a233eb0 100644 --- a/components/autofill_assistant/browser/script.cc +++ b/components/autofill_assistant/browser/script.cc
@@ -6,13 +6,13 @@ namespace autofill_assistant { -ScriptHandle::ScriptHandle() : autostart(false) {} +ScriptHandle::ScriptHandle() {} ScriptHandle::ScriptHandle(const ScriptHandle& orig) = default; ScriptHandle::~ScriptHandle() = default; -Script::Script() : priority(0) {} +Script::Script() {} Script::~Script() = default;
diff --git a/components/autofill_assistant/browser/script.h b/components/autofill_assistant/browser/script.h index 78b3345..f5878a6 100644 --- a/components/autofill_assistant/browser/script.h +++ b/components/autofill_assistant/browser/script.h
@@ -25,14 +25,16 @@ DirectAction direct_action; std::string path; std::string initial_prompt; + std::string start_message; + bool needs_ui = false; // When set to true this script can be run in 'autostart mode'. Script won't // be shown. - bool autostart; + bool autostart = false; // If set, the script might be run during WaitForDom actions with // allow_interrupt=true. - bool interrupt; + bool interrupt = false; }; // Script represents a sequence of actions. @@ -45,7 +47,7 @@ // Display priority of the script. Lowest number has highest priority, which // means a script with priority 0 should be displayed before a script with // priority 1. - int priority; + int priority = 0; std::unique_ptr<ScriptPrecondition> precondition; };
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc index 83a4ecf..276b967 100644 --- a/components/autofill_assistant/browser/script_executor.cc +++ b/components/autofill_assistant/browser/script_executor.cc
@@ -216,6 +216,9 @@ base::BindOnce(&ScriptExecutor::OnAdditionalActionTriggered, weak_ptr_factory_.GetWeakPtr(), std::move(options->additional_actions_callback)); + options->terms_link_callback = base::BindOnce( + &ScriptExecutor::OnTermsAndConditionsLinkClicked, + weak_ptr_factory_.GetWeakPtr(), std::move(options->terms_link_callback)); delegate_->SetPaymentRequestOptions(std::move(options)); delegate_->EnterState(AutofillAssistantState::PROMPT); } @@ -234,6 +237,13 @@ std::move(callback).Run(index); } +void ScriptExecutor::OnTermsAndConditionsLinkClicked( + base::OnceCallback<void(int)> callback, + int link) { + delegate_->EnterState(AutofillAssistantState::RUNNING); + std::move(callback).Run(link); +} + void ScriptExecutor::GetFullCard(GetFullCardCallback callback) { DCHECK(GetClientMemory()->selected_card()); @@ -514,6 +524,10 @@ return delegate_->SetForm(std::move(form), std::move(callback)); } +void ScriptExecutor::RequireUI() { + delegate_->RequireUI(); +} + void ScriptExecutor::OnGetActions(bool result, const std::string& response) { bool success = result && ProcessNextActionResponse(response); DVLOG(2) << __func__ << " result=" << result;
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h index 706eee7..d732ae4b 100644 --- a/components/autofill_assistant/browser/script_executor.h +++ b/components/autofill_assistant/browser/script_executor.h
@@ -193,6 +193,7 @@ bool SetForm(std::unique_ptr<FormProto> form, base::RepeatingCallback<void(const FormProto::Result*)> callback) override; + void RequireUI() override; private: // Helper for WaitForElementVisible that keeps track of the state required to @@ -328,6 +329,8 @@ std::unique_ptr<PaymentInformation> result); void OnAdditionalActionTriggered(base::OnceCallback<void(int)> callback, int index); + void OnTermsAndConditionsLinkClicked(base::OnceCallback<void(int)> callback, + int link); void OnGetFullCard(GetFullCardCallback callback, std::unique_ptr<autofill::CreditCard> card, const base::string16& cvc);
diff --git a/components/autofill_assistant/browser/script_executor_delegate.h b/components/autofill_assistant/browser/script_executor_delegate.h index f2eadd6..333678c 100644 --- a/components/autofill_assistant/browser/script_executor_delegate.h +++ b/components/autofill_assistant/browser/script_executor_delegate.h
@@ -105,6 +105,11 @@ // Changes to this value is reported to Listener::OnNavigationStateChanged() virtual bool HasNavigationError() = 0; + // Force showing the UI, if necessary. This is useful when executing a direct + // action which realizes it needs to interact with the user. The UI stays up + // until the end of the flow. + virtual void RequireUI() = 0; + // Register a listener that can be told about changes. Duplicate calls are // ignored. virtual void AddListener(Listener* listener) = 0;
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto index 2a9a70b..ded2d9b 100644 --- a/components/autofill_assistant/browser/service.proto +++ b/components/autofill_assistant/browser/service.proto
@@ -146,6 +146,14 @@ // When set to true this script will be run from WaitForDom actions with // allow_interrupt=true. optional bool interrupt = 9; + + // Message to show once the script has been started. This is shown while + // loading the actions. + optional string start_message = 10; + + // Show the UI if it's not shown yet. Setting this to false is useful for + // scripts started by direct actions. + optional bool needs_ui = 11 [default = true]; } optional PresentationProto presentation = 2; } @@ -414,6 +422,9 @@ // |GetPaymentInformationProto.additional_actions| that has index // |additional_action_index|. optional int32 additional_action_index = 4; + // If set, this means that the user clicked on one of the terms and conditions + // links. + optional int32 terms_link = 5; } message ProcessedActionProto { @@ -719,6 +730,10 @@ // Contain a localized text message from the server. message TellProto { optional string message = 1; + + // Show the UI if it's not shown yet, such as when a script has been started + // by a direct action. + optional bool needs_ui = 2 [default = true]; } // Contain all arguments to focus on an element. @@ -1034,6 +1049,17 @@ optional TermsAndConditionsState terms_and_conditions_state = 8; // When 'false', hide the terms and conditions box in the UI. optional bool request_terms_and_conditions = 9 [default = true]; + // Whether the terms and conditions should be displayed as a single checkbox + // with |accept_terms_and_conditions_text| as text. If false, the accept terms + // will be displayed as a radio button next to an additional "Read and agree + // later on domain.com" choice. + optional bool show_terms_as_checkbox = 12; + // The text for the terms and conditions "I accept..." choice. The text is + // formatted such that '<b>text</b>' will be bold and '<link0>clickable + // link</link0>', '<link1>other link</link1>', etc will be clickable links + // that will finish this action and return the clicked link in the action + // result. + optional string accept_terms_and_conditions_text = 13; // Optionally allows confiriming through the given direct actions. optional DirectActionProto confirm_direct_action = 10; // Additional actions available to the user. This can be used for instance to
diff --git a/components/autofill_assistant/browser/ui_delegate.h b/components/autofill_assistant/browser/ui_delegate.h index cb4ad765..3788ad1 100644 --- a/components/autofill_assistant/browser/ui_delegate.h +++ b/components/autofill_assistant/browser/ui_delegate.h
@@ -118,6 +118,9 @@ virtual void SetTermsAndConditions( TermsAndConditionsState terms_and_conditions) = 0; + // Called when the user clicks a link on the terms & conditions message. + virtual void OnTermsAndConditionsLinkClicked(int link) = 0; + // Adds the rectangles that correspond to the current touchable area to the // given vector. //
diff --git a/components/autofill_assistant_strings.grdp b/components/autofill_assistant_strings.grdp index f18b0a7..3c096bd 100644 --- a/components/autofill_assistant_strings.grdp +++ b/components/autofill_assistant_strings.grdp
@@ -27,5 +27,8 @@ <message name="IDS_AUTOFILL_ASSISTANT_STOPPED" desc="Text label that is shown when stopping the Autofill Assistant."> Google Assistant in Chrome stopping </message> + <message name="IDS_AUTOFILL_ASSISTANT_3RD_PARTY_TERMS_ACCEPT" desc="Message that indicates that the user agrees to the terms and conditions of a 3rd party's domain, e.g., 'odeon.co.uk'."> + I agree to the terms & conditions, privacy policy, and right of withdrawal of <ph name="BEGIN_BOLD"><b></ph><ph name="DOMAIN">%1$s<ex>google.com</ex></ph><ph name="END_BOLD"></b></ph> + </message> </if> </grit-part>
diff --git a/components/captive_portal/BUILD.gn b/components/captive_portal/BUILD.gn index 49ebbfb..93a263cb 100644 --- a/components/captive_portal/BUILD.gn +++ b/components/captive_portal/BUILD.gn
@@ -21,6 +21,10 @@ "//services/network/public/cpp", "//url", ] + + if (is_chromeos) { + deps += [ "//chromeos/network" ] + } } static_library("test_support") {
diff --git a/components/captive_portal/DEPS b/components/captive_portal/DEPS index a1d15fd..7b5f1e0 100644 --- a/components/captive_portal/DEPS +++ b/components/captive_portal/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+chromeos/network", "+services/network/public/cpp", "+services/network/public/mojom", "+services/network/test",
diff --git a/components/captive_portal/captive_portal_detector.cc b/components/captive_portal/captive_portal_detector.cc index e81b285f..f92dda9 100644 --- a/components/captive_portal/captive_portal_detector.cc +++ b/components/captive_portal/captive_portal_detector.cc
@@ -4,14 +4,37 @@ #include "components/captive_portal/captive_portal_detector.h" +#include <utility> + #include "base/bind.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" +#include "base/task_runner_util.h" #include "net/base/load_flags.h" #include "net/http/http_response_headers.h" #include "net/http/http_util.h" #include "net/url_request/url_request_status.h" +#if defined(OS_CHROMEOS) +#include "chromeos/network/network_configuration_handler.h" +#include "chromeos/network/network_handler.h" +#include "chromeos/network/network_state_handler.h" +#endif + +namespace { +#if defined(OS_CHROMEOS) +GURL GetProbeUrl(const GURL& default_url) { + DCHECK_EQ(chromeos::NetworkHandler::Get()->task_runner(), + base::ThreadTaskRunnerHandle::Get().get()); + const chromeos::NetworkState* network = chromeos::NetworkHandler::Get() + ->network_state_handler() + ->DefaultNetwork(); + return network && !network->probe_url().is_empty() ? network->probe_url() + : default_url; +} +#endif +} // namespace + namespace captive_portal { const char CaptivePortalDetector::kDefaultURL[] = @@ -19,7 +42,7 @@ CaptivePortalDetector::CaptivePortalDetector( network::mojom::URLLoaderFactory* loader_factory) - : loader_factory_(loader_factory) {} + : loader_factory_(loader_factory), weak_factory_(this) {} CaptivePortalDetector::~CaptivePortalDetector() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -35,8 +58,25 @@ detection_callback_ = std::move(detection_callback); +#if defined(OS_CHROMEOS) + if (chromeos::NetworkHandler::IsInitialized()) { + base::PostTaskAndReplyWithResult( + chromeos::NetworkHandler::Get()->task_runner(), FROM_HERE, + base::BindOnce(&GetProbeUrl, url), + base::BindOnce(&CaptivePortalDetector::StartProbe, + weak_factory_.GetWeakPtr(), traffic_annotation)); + return; + } +#endif + StartProbe(traffic_annotation, url); +} + +void CaptivePortalDetector::StartProbe( + const net::NetworkTrafficAnnotationTag& traffic_annotation, + const GURL& url) { auto resource_request = std::make_unique<network::ResourceRequest>(); resource_request->url = url; + probe_url_ = url; // Can't safely use net::LOAD_DISABLE_CERT_NETWORK_FETCHES here, // since then the connection may be reused without checking the cert.
diff --git a/components/captive_portal/captive_portal_detector.h b/components/captive_portal/captive_portal_detector.h index 069f26d0..5642663 100644 --- a/components/captive_portal/captive_portal_detector.h +++ b/components/captive_portal/captive_portal_detector.h
@@ -6,11 +6,13 @@ #define COMPONENTS_CAPTIVE_PORTAL_CAPTIVE_PORTAL_DETECTOR_H_ #include <memory> +#include <string> #include "base/callback.h" #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "base/sequence_checker.h" #include "base/time/time.h" #include "components/captive_portal/captive_portal_export.h" @@ -76,6 +78,10 @@ net::HttpResponseHeaders* headers, Results* results) const; + // Starts portal detection probe after GetProbeUrl finishes running. + void StartProbe(const net::NetworkTrafficAnnotationTag& traffic_annotation, + const GURL& url); + // Returns the current time. Used only when determining time until a // Retry-After date. base::Time GetCurrentTime() const; @@ -101,8 +107,13 @@ // Test time used by unit tests. base::Time time_for_testing_; + // Probe URL accessed by tests. + GURL probe_url_; + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<CaptivePortalDetector> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(CaptivePortalDetector); };
diff --git a/components/captive_portal/captive_portal_testing_utils.h b/components/captive_portal/captive_portal_testing_utils.h index 559e36d2..3559be8b 100644 --- a/components/captive_portal/captive_portal_testing_utils.h +++ b/components/captive_portal/captive_portal_testing_utils.h
@@ -43,6 +43,8 @@ CaptivePortalDetector* detector() { return detector_; } + const GURL& get_probe_url() { return detector_->probe_url_; } + protected: CaptivePortalDetector* detector_; network::TestURLLoaderFactory test_loader_factory_;
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn index d9c9d40..419b726 100644 --- a/components/cronet/android/BUILD.gn +++ b/components/cronet/android/BUILD.gn
@@ -10,6 +10,8 @@ import("//build/util/lastchange.gni") import("//build/util/process_version.gni") import("//build/util/version.gni") +import("//components/cronet/native/include/headers.gni") +import("//components/grpc_support/include/headers.gni") import("//testing/test.gni") import("//third_party/netty4/netty4.gni") import("//third_party/protobuf/proto_library.gni") @@ -1306,6 +1308,14 @@ ] } + copy("cronet_package_copy_native_headers") { + sources = cronet_native_public_headers + grpc_public_headers + + outputs = [ + "$_package_dir/include/{{source_file_part}}", + ] + } + copy("cronet_package_copy_native_lib") { sources = [ "$root_out_dir/" + _cronet_shared_lib_file_name, @@ -1490,6 +1500,7 @@ deps = [ ":api_static_checks", ":cronet_package_copy", + ":cronet_package_copy_native_headers", ":cronet_package_copy_native_lib", ":cronet_package_copy_native_lib_unstripped", ":cronet_package_copy_resources",
diff --git a/components/feed/core/feed_logging_metrics.cc b/components/feed/core/feed_logging_metrics.cc index e487ff43..dfac2ea 100644 --- a/components/feed/core/feed_logging_metrics.cc +++ b/components/feed/core/feed_logging_metrics.cc
@@ -688,9 +688,10 @@ void FeedLoggingMetrics::OnInternalError(int internal_error) { // TODO(https://crbug.com/935602): The max value here is fragile, figure out - // some way to test the @IntDef size. + // some way to test the @IntDef size. For now the count needs to be kept in + // sync with InternalFeedError.java and enums.xml. UMA_HISTOGRAM_ENUMERATION("ContentSuggestions.Feed.InternalError", - internal_error, 13); + internal_error, 18); } void FeedLoggingMetrics::OnTokenCompleted(bool was_synthetic,
diff --git a/components/gcm_driver/gcm_driver.h b/components/gcm_driver/gcm_driver.h index af33a35..9abeea2 100644 --- a/components/gcm_driver/gcm_driver.h +++ b/components/gcm_driver/gcm_driver.h
@@ -268,7 +268,7 @@ // The InstanceIDHandler provides an implementation for the InstanceID system. virtual InstanceIDHandler* GetInstanceIDHandlerInternal() = 0; // Allows the InstanceID system to integrate with GCM encryption storage. - GCMEncryptionProvider* GetEncryptionProviderInternal(); + virtual GCMEncryptionProvider* GetEncryptionProviderInternal(); // Adds or removes a custom client requested heartbeat interval. If multiple // components set that setting, the lowest setting will be used. If the
diff --git a/components/gcm_driver/instance_id/instance_id.h b/components/gcm_driver/instance_id/instance_id.h index 398fab33..dfe35b404 100644 --- a/components/gcm_driver/instance_id/instance_id.h +++ b/components/gcm_driver/instance_id/instance_id.h
@@ -116,8 +116,8 @@ // created. // |authorized_entity|: the authorized entity passed when obtaining the token. // |callback|: to be called once the asynchronous operation is done. - void GetEncryptionInfo(const std::string& authorized_entity, - GetEncryptionInfoCallback callback); + virtual void GetEncryptionInfo(const std::string& authorized_entity, + GetEncryptionInfoCallback callback); // Revokes a granted token. // |authorized_entity|: the authorized entity passed when obtaining the token.
diff --git a/components/image_fetcher/core/BUILD.gn b/components/image_fetcher/core/BUILD.gn index c34dbca..1e8c44aa 100644 --- a/components/image_fetcher/core/BUILD.gn +++ b/components/image_fetcher/core/BUILD.gn
@@ -27,9 +27,9 @@ ] deps = [ ":metrics", - "cache", ] public_deps = [ + "cache", "//base", "//components/keyed_service/core", "//net",
diff --git a/components/invalidation/impl/invalidation_switches.cc b/components/invalidation/impl/invalidation_switches.cc index b70acc4..4da0bbb 100644 --- a/components/invalidation/impl/invalidation_switches.cc +++ b/components/invalidation/impl/invalidation_switches.cc
@@ -20,7 +20,7 @@ "sync-allow-insecure-xmpp-connection"; const base::Feature kFCMInvalidations = {"FCMInvalidations", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kFCMInvalidationsConservativeEnabling = { "FCMInvalidationsConservativeEnabling", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/journey/BUILD.gn b/components/journey/BUILD.gn deleted file mode 100644 index acd967d..0000000 --- a/components/journey/BUILD.gn +++ /dev/null
@@ -1,40 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -static_library("journey_info_fetcher") { - sources = [ - "journey_info_fetcher.cc", - "journey_info_fetcher.h", - "journey_info_json_request.cc", - "journey_info_json_request.h", - ] - - deps = [ - "//base", - "//components/journey/proto", - "//components/signin/public/identity_manager", - "//components/variations/net:net", - "//net", - "//services/data_decoder/public/cpp", - "//services/network/public/cpp", - "//url", - ] -} - -source_set("unit_tests") { - testonly = true - sources = [ - "journey_info_fetcher_unittest.cc", - ] - - deps = [ - ":journey_info_fetcher", - "//base/test:test_support", - "//components/signin/public/identity_manager:test_support", - "//services/data_decoder/public/cpp:test_support", - "//services/network:test_support", - "//testing/gmock", - "//testing/gtest", - ] -}
diff --git a/components/journey/DEPS b/components/journey/DEPS deleted file mode 100644 index 8aa14497..0000000 --- a/components/journey/DEPS +++ /dev/null
@@ -1,10 +0,0 @@ -include_rules = [ - "+base", - "+components/signin/public", - "+components/variations", - "+net", - "+services/data_decoder/public/cpp", - "+services/network/public/cpp", - "+services/network/test", - "+url", -]
diff --git a/components/journey/OWNERS b/components/journey/OWNERS deleted file mode 100644 index bb69daa..0000000 --- a/components/journey/OWNERS +++ /dev/null
@@ -1,3 +0,0 @@ -acolwell@chromium.org -wychen@chromium.org -yusufo@chromium.org
diff --git a/components/journey/README.md b/components/journey/README.md deleted file mode 100644 index a6dcdc2..0000000 --- a/components/journey/README.md +++ /dev/null
@@ -1,19 +0,0 @@ -# Overview -This component deals with multiple tabs or pages navigation that starts with an -explicit user action, and has similar context. The component contains tools to -process these navigations and present them in a way that provides users a -smoother UI flow within their tabs. - -# Understanding Terms -This component introduces several terms, include: -* Pageload: A load of a page by a given user at a moment in time, and they are -derived from the user's Chrome History data. -* User Journey: A set of connected pageloads that are determined based on an -explicit user action, such as omnibox search, and the semantic relationship -with others. - -# Provisions -This component provides a `JourneyInfoFetcher`, an authenticated fetcher that -fetches a list of pageload information in a json format from the user journey -endpoint server. This fetcher can be used by any client that needs access to -these information from the server.
diff --git a/components/journey/journey_info_fetcher.cc b/components/journey/journey_info_fetcher.cc deleted file mode 100644 index c1d6fcd..0000000 --- a/components/journey/journey_info_fetcher.cc +++ /dev/null
@@ -1,136 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/journey/journey_info_fetcher.h" - -#include "base/bind.h" -#include "base/strings/stringprintf.h" -#include "base/values.h" -#include "components/journey/journey_info_json_request.h" -#include "components/signin/public/identity_manager/access_token_info.h" -#include "services/data_decoder/public/cpp/safe_json_parser.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" - -namespace journey { - -namespace { -const char kChromeSyncScope[] = "https://www.googleapis.com/auth/chromememex"; -} // namespace - -JourneyInfoFetcher::JourneyInfoFetcher( - signin::IdentityManager* identity_manager, - const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory) - : identity_manager_(identity_manager), loader_factory_(loader_factory) {} - -JourneyInfoFetcher::~JourneyInfoFetcher() = default; - -void JourneyInfoFetcher::FetchJourneyInfo( - std::vector<int64_t> timestamps, - FetchResponseAvailableCallback callback) { - if (!identity_manager_->HasPrimaryAccount()) { - FetchFinished(std::move(callback), /*result=*/base::nullopt, - "Primary Account is not Available. Sign in is required"); - return; - } - pending_requests_.emplace(std::move(timestamps), std::move(callback)); - RequestOAuthTokenService(); -} - -void JourneyInfoFetcher::RequestOAuthTokenService() { - if (token_fetcher_) - return; - - OAuth2AccessTokenManager::ScopeSet scopes{kChromeSyncScope}; - token_fetcher_ = std::make_unique<signin::PrimaryAccountAccessTokenFetcher>( - "journey_info", identity_manager_, scopes, - base::BindOnce(&JourneyInfoFetcher::AccessTokenFetchFinished, - base::Unretained(this)), - signin::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable); -} - -void JourneyInfoFetcher::AccessTokenFetchFinished( - GoogleServiceAuthError error, - signin::AccessTokenInfo access_token_info) { - DCHECK(token_fetcher_); - std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher> - token_fetcher_deleter(std::move(token_fetcher_)); - - if (error.state() != GoogleServiceAuthError::NONE) { - AccessTokenError(error); - return; - } - - DCHECK(!access_token_info.token.empty()); - - while (!pending_requests_.empty()) { - std::pair<std::vector<int64_t>, FetchResponseAvailableCallback> - timestamp_and_callback = std::move(pending_requests_.front()); - pending_requests_.pop(); - StartRequest(timestamp_and_callback.first, - std::move(timestamp_and_callback.second), - access_token_info.token); - } -} - -void JourneyInfoFetcher::AccessTokenError(const GoogleServiceAuthError& error) { - DCHECK_NE(error.state(), GoogleServiceAuthError::NONE); - DLOG(WARNING) << "JourneyInfoFetcher::AccessTokenError " - "Unable to get token: " - << error.ToString(); - - while (!pending_requests_.empty()) { - std::pair<std::vector<int64_t>, FetchResponseAvailableCallback> - timestamp_and_callback = std::move(pending_requests_.front()); - pending_requests_.pop(); - - FetchFinished(std::move(timestamp_and_callback.second), - /*result=*/base::nullopt, error.ToString()); - } -} - -void JourneyInfoFetcher::StartRequest(const std::vector<int64_t>& timestamps, - FetchResponseAvailableCallback callback, - const std::string& oauth_access_token) { - JourneyInfoJsonRequest::Builder builder; - builder.SetTimestamps(timestamps) - .SetAuthentication( - base::StringPrintf("bearer %s", oauth_access_token.c_str())) - .SetParseJsonCallback(base::BindRepeating( - &data_decoder::SafeJsonParser::Parse, - /*connector=*/nullptr)); // This is an Android-only component, - // connector is unused on Android. - auto json_request = builder.Build(); - JourneyInfoJsonRequest* raw_request = json_request.get(); - raw_request->Start( - base::BindOnce(&JourneyInfoFetcher::JsonRequestDone, - base::Unretained(this), std::move(json_request), - std::move(callback)), - loader_factory_); -} - -const std::string& JourneyInfoFetcher::GetLastJsonForDebugging() const { - return last_fetch_json_; -} - -void JourneyInfoFetcher::JsonRequestDone( - std::unique_ptr<JourneyInfoJsonRequest> request, - FetchResponseAvailableCallback callback, - base::Optional<base::Value> result, - const std::string& error_detail) { - DCHECK(request); - - last_fetch_json_ = request->GetResponseString(); - FetchFinished(std::move(callback), std::move(result), error_detail); -} - -void JourneyInfoFetcher::FetchFinished(FetchResponseAvailableCallback callback, - base::Optional<base::Value> result, - const std::string& error_detail) { - DCHECK((result && !result->is_none()) || error_detail != ""); - - // Returned |result| can be empty while |error_detail| is "". - std::move(callback).Run(std::move(result), error_detail); -} - -} // namespace journey
diff --git a/components/journey/journey_info_fetcher.h b/components/journey/journey_info_fetcher.h deleted file mode 100644 index bb1cf0bd..0000000 --- a/components/journey/journey_info_fetcher.h +++ /dev/null
@@ -1,93 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_JOURNEY_JOURNEY_INFO_FETCHER_H_ -#define COMPONENTS_JOURNEY_JOURNEY_INFO_FETCHER_H_ - -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/callback.h" -#include "base/containers/queue.h" -#include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h" - -namespace base { -class Value; -} // namespace base - -namespace signin { -class IdentityManager; -} // namespace signin - -namespace network { -class SharedURLLoaderFactory; -} // namespace network - -namespace journey { - -class JourneyInfoJsonRequest; - -using FetchResponseAvailableCallback = - base::OnceCallback<void(base::Optional<base::Value>, const std::string&)>; - -// This class is used to fetch SwitcherJourney information from the server. -class JourneyInfoFetcher { - public: - JourneyInfoFetcher( - signin::IdentityManager* identity_manager, - const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory); - - ~JourneyInfoFetcher(); - - // This method fetches journey information based on |timestamps|, - // and calls back to |callback| when complete. - // TODO(meiliang): Add a parameter, GURL url, as the fetching url instead of - // hard code the url. - void FetchJourneyInfo(std::vector<int64_t> timestamps, - FetchResponseAvailableCallback callback); - - // This method gets last json response as a string. - const std::string& GetLastJsonForDebugging() const; - - private: - void RequestOAuthTokenService(); - - void StartRequest(const std::vector<int64_t>& timestamps, - FetchResponseAvailableCallback callback, - const std::string& oauth_access_token); - - void AccessTokenFetchFinished(GoogleServiceAuthError error, - signin::AccessTokenInfo access_token_info); - - void AccessTokenError(const GoogleServiceAuthError& error); - - void FetchFinished(FetchResponseAvailableCallback callback, - base::Optional<base::Value> result, - const std::string& error_detail); - - void JsonRequestDone(std::unique_ptr<JourneyInfoJsonRequest> request, - FetchResponseAvailableCallback callback, - base::Optional<base::Value> result, - const std::string& error_detail); - - signin::IdentityManager* identity_manager_; - - std::unique_ptr<signin::PrimaryAccountAccessTokenFetcher> token_fetcher_; - - const scoped_refptr<network::SharedURLLoaderFactory> loader_factory_; - - std::string last_fetch_json_; - - // This queues stores requests that wait for an access token. - base::queue<std::pair<std::vector<int64_t>, FetchResponseAvailableCallback>> - pending_requests_; - - DISALLOW_COPY_AND_ASSIGN(JourneyInfoFetcher); -}; - -} // namespace journey - -#endif // COMPONENTS_JOURNEY_JOURNEY_INFO_FETCHER_H_
diff --git a/components/journey/journey_info_fetcher_unittest.cc b/components/journey/journey_info_fetcher_unittest.cc deleted file mode 100644 index 789a619..0000000 --- a/components/journey/journey_info_fetcher_unittest.cc +++ /dev/null
@@ -1,245 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/journey/journey_info_fetcher.h" - -#include <utility> - -#include "base/run_loop.h" -#include "base/strings/string_number_conversions.h" -#include "base/strings/stringprintf.h" -#include "base/test/mock_callback.h" -#include "base/test/scoped_task_environment.h" -#include "components/signin/public/identity_manager/identity_test_environment.h" -#include "net/http/http_util.h" -#include "services/data_decoder/public/cpp/testing_json_parser.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" -#include "services/network/test/test_url_loader_factory.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using testing::_; - -namespace journey { -const char kEmail[] = "foo_email"; -const char kJourneyServer[] = - "https://chrome-memex-dev.appspot.com/api/journey_from_pageload"; -const char kEmptyErrorString[] = ""; -const std::vector<int64_t> kTimestamps = {1532563271195406}; - -using MockFetchResponseAvailableCallback = - base::MockCallback<FetchResponseAvailableCallback>; - -class JourneyInfoFetcherTest : public testing::Test { - protected: - JourneyInfoFetcherTest() {} - - ~JourneyInfoFetcherTest() override {} - - void SetUp() override { - scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory = - base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( - &test_url_loader_factory_); - journey_info_fetcher_ = std::make_unique<JourneyInfoFetcher>( - identity_test_env_.identity_manager(), test_shared_loader_factory); - - SignIn(); - } - - void TearDown() override {} - - void SignIn() { - identity_test_env_.MakePrimaryAccountAvailable(kEmail); - identity_test_env_.SetAutomaticIssueOfAccessTokens(true); - } - - void SignOut() { identity_test_env_.ClearPrimaryAccount(); } - - std::string GenerateJsonResponse(const std::vector<int64_t>& timestamps) { - int timestamps_size = timestamps.size(); - std::string response_string = R"( - [ - { - "status": "STATUS_OK", - "default_autotabs": { - "pageloads": [ - { - "title": { - "weight": 1.0, - "title": "foo" - }, - "url": "https://foo.com/", - "image": { - "snippet": "PRS_REPRESENTATIVE_IMAGE", - "confidence": 1.0, - "thumbnail_url": "https://foo-png" - }, - "timestamp_us": "1532563271195406", - "is_pruned": false - } - ], - "selection_type": "SELECTION_TYPE_LEAVES_AND_TAB_AND_TASK" - }, - "journey_id": "3021296114337328326", - "source_page_timestamp_usec": [ - )"; - - for (int i = 0; i < timestamps_size; i++) { - response_string += "\"" + base::NumberToString(timestamps[i]) + "\""; - if (i < timestamps_size - 1) - response_string += ", "; - } - - response_string += R"( - ] - } - ] - )"; - - return response_string; - } - - void SetFakeResponse(const GURL& request_url, - const std::string& response_data, - net::HttpStatusCode response_code, - net::Error error) { - network::ResourceResponseHead head; - std::string headers(base::StringPrintf( - "HTTP/1.1 %d %s\nContent-type: application/json\n\n", - static_cast<int>(response_code), GetHttpReasonPhrase(response_code))); - head.headers = base::MakeRefCounted<net::HttpResponseHeaders>( - net::HttpUtil::AssembleRawHeaders(headers)); - head.mime_type = "application/json"; - network::URLLoaderCompletionStatus status(error); - status.decoded_body_length = response_data.size(); - test_url_loader_factory_.AddResponse(request_url, head, response_data, - status); - } - - void SendAndAwaitResponse(std::vector<int64_t> timestamps) { - journey_info_fetcher()->FetchJourneyInfo( - timestamps, journey_info_available_callback().Get()); - base::RunLoop().RunUntilIdle(); - } - - MockFetchResponseAvailableCallback& journey_info_available_callback() { - return mock_callback_; - } - - JourneyInfoFetcher* journey_info_fetcher() { - return journey_info_fetcher_.get(); - } - - network::TestURLLoaderFactory* test_url_loader_factory() { - return &test_url_loader_factory_; - } - - signin::IdentityTestEnvironment& identity_test_env() { - return identity_test_env_; - } - - private: - base::test::ScopedTaskEnvironment scoped_task_environment_; - data_decoder::TestingJsonParser::ScopedFactoryOverride factory_override_; - signin::IdentityTestEnvironment identity_test_env_; - MockFetchResponseAvailableCallback mock_callback_; - network::TestURLLoaderFactory test_url_loader_factory_; - std::unique_ptr<JourneyInfoFetcher> journey_info_fetcher_; - - DISALLOW_COPY_AND_ASSIGN(JourneyInfoFetcherTest); -}; - -TEST_F(JourneyInfoFetcherTest, FetchJourneyInfo) { - std::string json_response_string = GenerateJsonResponse(kTimestamps); - SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK, - net::OK); - EXPECT_CALL(journey_info_available_callback(), - Run(testing::Ne(base::nullopt), kEmptyErrorString)); - - SendAndAwaitResponse(kTimestamps); - - EXPECT_THAT(journey_info_fetcher()->GetLastJsonForDebugging(), - testing::Eq(json_response_string)); -} - -TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoOAuthError) { - identity_test_env().SetAutomaticIssueOfAccessTokens(false); - - EXPECT_CALL(journey_info_available_callback(), - Run(testing::Eq(base::nullopt), testing::Ne(kEmptyErrorString))); - - journey_info_fetcher()->FetchJourneyInfo( - kTimestamps, journey_info_available_callback().Get()); - - identity_test_env().WaitForAccessTokenRequestIfNecessaryAndRespondWithError( - GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE)); - - base::RunLoop().RunUntilIdle(); -} - -#if !defined(OS_CHROMEOS) -TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoUserNotSignedIn) { - SignOut(); - - EXPECT_CALL(journey_info_available_callback(), - Run(testing::Eq(base::nullopt), testing::Ne(kEmptyErrorString))); - - SendAndAwaitResponse(kTimestamps); - - EXPECT_EQ(journey_info_fetcher()->GetLastJsonForDebugging(), ""); -} -#endif - -TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoWithNonParsableResponse) { - std::string json_response_string = "["; - SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK, - net::OK); - EXPECT_CALL(journey_info_available_callback(), - Run(testing::Eq(base::nullopt), testing::Ne(kEmptyErrorString))); - - SendAndAwaitResponse(kTimestamps); - - EXPECT_THAT(journey_info_fetcher()->GetLastJsonForDebugging(), - testing::Eq(json_response_string)); -} - -TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoWithBadJSONResponse) { - std::string json_response_string = "[]"; - SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK, - net::OK); - EXPECT_CALL(journey_info_available_callback(), - Run(testing::Ne(base::nullopt), kEmptyErrorString)); - - SendAndAwaitResponse(kTimestamps); - - EXPECT_THAT(journey_info_fetcher()->GetLastJsonForDebugging(), - testing::Eq(json_response_string)); -} - -TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoNetworkError) { - std::string json_response_string = "[]"; - SetFakeResponse(GURL(kJourneyServer), json_response_string, net::HTTP_OK, - net::ERR_FAILED); - EXPECT_CALL(journey_info_available_callback(), - Run(testing::Eq(base::nullopt), testing::Ne(kEmptyErrorString))); - - SendAndAwaitResponse(kTimestamps); - - EXPECT_EQ(journey_info_fetcher()->GetLastJsonForDebugging(), ""); -} - -TEST_F(JourneyInfoFetcherTest, FetchJourneyInfoHttpError) { - std::string json_response_string = "[]"; - SetFakeResponse(GURL(kJourneyServer), json_response_string, - net::HTTP_BAD_REQUEST, net::OK); - EXPECT_CALL(journey_info_available_callback(), - Run(testing::Eq(base::nullopt), testing::Ne(kEmptyErrorString))); - - SendAndAwaitResponse(kTimestamps); - - EXPECT_EQ(journey_info_fetcher()->GetLastJsonForDebugging(), ""); -} - -} // namespace journey
diff --git a/components/journey/journey_info_json_request.cc b/components/journey/journey_info_json_request.cc deleted file mode 100644 index b8cba83..0000000 --- a/components/journey/journey_info_json_request.cc +++ /dev/null
@@ -1,178 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/journey/journey_info_json_request.h" - -#include <algorithm> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/strings/stringprintf.h" -#include "base/values.h" -#include "components/journey/proto/batch_get_switcher_journey_from_pageload_request.pb.h" -#include "components/variations/net/variations_http_headers.h" -#include "net/base/load_flags.h" -#include "net/http/http_request_headers.h" -#include "net/traffic_annotation/network_traffic_annotation.h" -#include "services/network/public/cpp/resource_request.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/network/public/cpp/simple_url_loader.h" - -namespace journey { - -namespace { - -const int k5xxRetries = 2; - -std::string GetSerializedJourneyRequest( - const std::vector<int64_t>& timestamps) { - BatchGetSwitcherJourneyFromPageloadRequest request; - - for (const auto timestamp : timestamps) { - request.add_page_timestamp_usec(timestamp); - } - - return request.SerializeAsString(); -} - -} // namespace - -JourneyInfoJsonRequest::JourneyInfoJsonRequest( - const ParseJSONCallback& callback) - : parse_json_callback_(callback), weak_ptr_factory_(this) {} - -JourneyInfoJsonRequest::~JourneyInfoJsonRequest() {} - -void JourneyInfoJsonRequest::Start( - CompletedCallback callback, - const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory) { - completed_callback_ = std::move(callback); - last_response_string_.clear(); - - simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - loader_factory.get(), - base::BindOnce(&JourneyInfoJsonRequest::OnSimpleURLLoaderComplete, - base::Unretained(this))); -} - -const std::string& JourneyInfoJsonRequest::GetResponseString() const { - return last_response_string_; -} - -void JourneyInfoJsonRequest::OnSimpleURLLoaderComplete( - std::unique_ptr<std::string> response_body) { - DCHECK(simple_url_loader_); - - int response_code = -1; - if (simple_url_loader_->ResponseInfo() && - simple_url_loader_->ResponseInfo()->headers) { - response_code = - simple_url_loader_->ResponseInfo()->headers->response_code(); - } - - int net_error = simple_url_loader_->NetError(); - simple_url_loader_.reset(); - - if (net_error != net::OK) { - std::move(completed_callback_) - .Run(base::nullopt, - base::StringPrintf("Network error code: %d", net_error)); - } else if (response_code / 100 != 2) { - std::move(completed_callback_) - .Run(base::nullopt, - base::StringPrintf("Http response error code: %d", response_code)); - } else { - last_response_string_ = std::move(*response_body); - parse_json_callback_.Run( - last_response_string_, - base::BindRepeating(&JourneyInfoJsonRequest::OnJsonParsed, - weak_ptr_factory_.GetWeakPtr()), - base::BindRepeating(&JourneyInfoJsonRequest::OnJsonError, - weak_ptr_factory_.GetWeakPtr())); - } -} - -void JourneyInfoJsonRequest::OnJsonParsed(base::Value result) { - std::move(completed_callback_).Run(std::move(result), std::string()); -} - -void JourneyInfoJsonRequest::OnJsonError(const std::string& error) { - DLOG(WARNING) << "Received invalid JSON (" << error - << "): " << last_response_string_; - std::move(completed_callback_).Run(base::nullopt, error); -} - -JourneyInfoJsonRequest::Builder::Builder() - : url_(GURL( - "https://chrome-memex-dev.appspot.com/api/journey_from_pageload")) {} - -JourneyInfoJsonRequest::Builder::~Builder() = default; - -std::unique_ptr<JourneyInfoJsonRequest> JourneyInfoJsonRequest::Builder::Build() - const { - auto request = std::make_unique<JourneyInfoJsonRequest>(parse_json_callback_); - request->simple_url_loader_ = BuildSimpleURLLoader(); - - return request; -} - -JourneyInfoJsonRequest::Builder& -JourneyInfoJsonRequest::Builder::SetAuthentication( - const std::string& auth_header) { - DVLOG(0) << "Authorization header " << auth_header; - auth_header_ = auth_header; - return *this; -} - -JourneyInfoJsonRequest::Builder& JourneyInfoJsonRequest::Builder::SetTimestamps( - const std::vector<int64_t>& timestamps) { - body_ = GetSerializedJourneyRequest(timestamps); - return *this; -} - -JourneyInfoJsonRequest::Builder& -JourneyInfoJsonRequest::Builder::SetParseJsonCallback( - ParseJSONCallback callback) { - parse_json_callback_ = std::move(callback); - return *this; -} - -net::HttpRequestHeaders -JourneyInfoJsonRequest::Builder::BuildSimpleURLLoaderHeaders() const { - net::HttpRequestHeaders headers; - headers.SetHeader("Content-Type", "application/json; charset=UTF-8"); - if (!auth_header_.empty()) { - headers.SetHeader("Authorization", auth_header_); - } - return headers; -} - -std::unique_ptr<network::SimpleURLLoader> -JourneyInfoJsonRequest::Builder::BuildSimpleURLLoader() const { - // TODO(meiliang): update the policy section with correct setting and - // chrome_policy - net::NetworkTrafficAnnotationTag traffic_annotation = NO_TRAFFIC_ANNOTATION_YET; - - auto resource_request = std::make_unique<network::ResourceRequest>(); - resource_request->url = GURL(url_); - resource_request->allow_credentials = false; - resource_request->headers = BuildSimpleURLLoaderHeaders(); - variations::AppendVariationsHeader(url_, variations::InIncognito::kNo, - variations::SignedIn::kNo, - resource_request.get()); - resource_request->method = "POST"; - - auto simple_loader = network::SimpleURLLoader::Create( - std::move(resource_request), traffic_annotation); - simple_loader->SetAllowHttpErrorResults(true); - simple_loader->AttachStringForUpload(body_, - "application/json; charset=UTF-8"); - simple_loader->SetRetryOptions( - k5xxRetries, network::SimpleURLLoader::RetryMode::RETRY_ON_5XX); - - return simple_loader; -} - -} // namespace journey
diff --git a/components/journey/journey_info_json_request.h b/components/journey/journey_info_json_request.h deleted file mode 100644 index b1a643a..0000000 --- a/components/journey/journey_info_json_request.h +++ /dev/null
@@ -1,112 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_JOURNEY_JOURNEY_INFO_JSON_REQUEST_H_ -#define COMPONENTS_JOURNEY_JOURNEY_INFO_JSON_REQUEST_H_ - -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/callback.h" -#include "base/memory/weak_ptr.h" -#include "url/gurl.h" - -namespace base { -class Value; -} // namespace base - -namespace net { -class HttpRequestHeaders; -} -namespace network { -class SimpleURLLoader; -class SharedURLLoaderFactory; -} // namespace network - -namespace journey { - -// This class represents a request of journey info. It encapsulates the -// request-response lifecycle. It is also responsible for building and -// serializing the request body protos. -class JourneyInfoJsonRequest { - // Callbacks for JSON parsing to allow injecting platform-dependent code. - using SuccessCallback = base::OnceCallback<void(base::Value result)>; - using ErrorCallback = base::OnceCallback<void(const std::string& error)>; - using ParseJSONCallback = - base::RepeatingCallback<void(const std::string& raw_json_string, - SuccessCallback success_callback, - ErrorCallback error_callback)>; - using CompletedCallback = - base::OnceCallback<void(base::Optional<base::Value> result, - const std::string& error_detail)>; - - public: - // This class is used to build authenticated and non-authenticated - // JourneyInfoJsonRequest. - class Builder { - public: - Builder(); - ~Builder(); - - // This method is used to builds a Request object that contains all - // data to fetch new snippets. - std::unique_ptr<JourneyInfoJsonRequest> Build() const; - - Builder& SetAuthentication(const std::string& auth_header); - Builder& SetParseJsonCallback(ParseJSONCallback callback); - Builder& SetTimestamps(const std::vector<int64_t>& timestamps); - - private: - std::unique_ptr<network::SimpleURLLoader> BuildSimpleURLLoader() const; - net::HttpRequestHeaders BuildSimpleURLLoaderHeaders() const; - - // The url for which we're fetching journey info. - GURL url_; - std::string auth_header_; - std::string body_; - ParseJSONCallback parse_json_callback_; - - DISALLOW_COPY_AND_ASSIGN(Builder); - }; - - explicit JourneyInfoJsonRequest(const ParseJSONCallback& callback); - ~JourneyInfoJsonRequest(); - - // This method is used to start fetching journey info using |loader_factory| - // to create a URLLoader, and call |callback| when finished. - void Start( - CompletedCallback callback, - const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory); - - // Get the last response as a string - const std::string& GetResponseString() const; - - private: - void OnSimpleURLLoaderComplete(std::unique_ptr<std::string> response_body); - void OnJsonParsed(base::Value result); - void OnJsonError(const std::string& error); - - // This callback is called to parse a json string. It contains callbacks for - // error and success cases. - ParseJSONCallback parse_json_callback_; - - // The loader for downloading the snippets. Only non-null if a fetch is - // currently ongoing. - std::unique_ptr<network::SimpleURLLoader> simple_url_loader_; - - std::string last_response_string_; - - // The callback to call when journey info are available. - CompletedCallback completed_callback_; - - base::WeakPtrFactory<JourneyInfoJsonRequest> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(JourneyInfoJsonRequest); -}; - -} // namespace journey - -#endif // COMPONENTS_JOURNEY_JOURNEY_INFO_JSON_REQUEST_H_
diff --git a/components/journey/proto/BUILD.gn b/components/journey/proto/BUILD.gn deleted file mode 100644 index 0556af1..0000000 --- a/components/journey/proto/BUILD.gn +++ /dev/null
@@ -1,11 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//third_party/protobuf/proto_library.gni") - -proto_library("proto") { - sources = [ - "batch_get_switcher_journey_from_pageload_request.proto", - ] -}
diff --git a/components/journey/proto/batch_get_switcher_journey_from_pageload_request.proto b/components/journey/proto/batch_get_switcher_journey_from_pageload_request.proto deleted file mode 100644 index 4f56565..0000000 --- a/components/journey/proto/batch_get_switcher_journey_from_pageload_request.proto +++ /dev/null
@@ -1,91 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Protocol buffer definition for a delta file. - -syntax = "proto2"; - -option optimize_for = LITE_RUNTIME; - -package journey; - -message BatchGetSwitcherJourneyFromPageloadRequest { - // Next ID to use: 5 - - // The timestamps of the pageloads to request journeys from. This will be - // ignored if task_id is present. - // TODO(ghyde): Deprecate this once client moves over. - repeated int64 page_timestamp_usec = 1; - - // Override journey creation parameters. - optional JourneyCreationOverrides journey_overrides = 2; - - // The maximum number of pageloads allowed per autotabs. - optional int64 max_pageloads = 3 [default = 50]; - - // The task ids frokm the client to request journeys from. - repeated int64 task_id = 4; -} - -message JourneyCreationOverrides { - optional JourneyAlgorithmParameters journey_algorithm_parameters = 1; -} - -message JourneyAlgorithmParameters { - // Next ID to use: 11 - - // Similarity threshold in [0,1]. Clusters with similarity greater - // then this threshold and which were done in short timespans will be - // merged. If set to 1, non temporal merging is performed. - optional float temporal_merge_threshold = 1 [default = 1]; - - // Similarity threshold in [0,1]. Threshold above which journeys are - // considered to be related to each other. - optional float semantically_related_threshold = 2 [default = 0.1]; - - // Similarity threshold in [0, 1]. Threshold above which journeys appear in - // searches for a given query. - optional float search_threshold = 3 [default = 0.1]; - - // If true, dedupe pageloads in journeys by URL. remove_duplicate_titles - // and remove_duplicates_between_tasks will only be used if this value is - // true. - optional bool remove_duplicate_urls = 6 [default = true]; - - // If true, remove URLs as duplicates if they are from the same domain and - // have the same title. Otherwise, only remove duplicate URLs that have - // identical URLs. - // This value is only used if remove_duplicate_urls is also true. - optional bool remove_duplicate_titles = 4 [default = true]; - - // If true, remove duplicates across the whole journey. Otherwise, - // only remove duplicates within each task. - // Note: This value is only used if remove_duplicate_urls is also true. - optional bool remove_duplicates_between_tasks = 7 [default = false]; - - // Type of labels to use for subtitles. - enum SubtitleTermsType { - TYPE_UNKNOWN = 0; - - // Use knowledge entities as subtitle terms. - TYPE_KE = 1; - - // Use petacat as subtitle terms. - TYPE_PETACAT = 2; - } - optional SubtitleTermsType subtitle_type = 5 [default = TYPE_KE]; - - // If set to true, bookmarks will be fetched and pageloads will be annotated - // with them. - optional bool get_bookmarks = 8 [default = false]; - - // The number of days between tasks in the same cluster required in order - // to break into a new journey. - optional int32 journey_break_days = 9 [default = 7]; - - // The max number of pageloads to be added to a journey. - // NOTE: We will actually add tasks as long as we are under this limit, so - // it is possible that the last task pushes us over. - optional int32 max_pages_in_journey = 10 [default = 500]; -} \ No newline at end of file
diff --git a/components/media_message_center/media_notification_item.h b/components/media_message_center/media_notification_item.h index 1911694a..08f817e6 100644 --- a/components/media_message_center/media_notification_item.h +++ b/components/media_message_center/media_notification_item.h
@@ -62,6 +62,8 @@ override; void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override {} + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} // media_session::mojom::MediaControllerImageObserver: void MediaControllerImageChanged(
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc index d2653b7..965ddde 100644 --- a/components/omnibox/browser/autocomplete_result.cc +++ b/components/omnibox/browser/autocomplete_result.cc
@@ -213,9 +213,16 @@ if (OmniboxFieldTrial::IsGroupSuggestionsBySearchVsUrlFeatureEnabled() && matches_.size() > 2) { - // "Bunch" first by search type, then all others. - std::stable_sort(std::next(matches_.begin()), matches_.end(), - CompareBySearchVsUrl()); + // Skip over default match. + auto next = std::next(matches_.begin()); + // If it has submatches, skip them too. + if (matches_.front().subrelevance != 0) { + while (next != matches_.end() && + AutocompleteMatch::IsSameFamily(matches_.front().subrelevance, + next->subrelevance)) + next = std::next(next); + } + GroupSuggestionsBySearchVsURL(next, matches_.end()); } // There is no default match for chromeOS launcher zero prefix query @@ -770,3 +777,63 @@ }), matches_.end()); } + +// static +void AutocompleteResult::GroupSuggestionsBySearchVsURL(iterator begin, + iterator end) { + // The following routine implements a semi-stateful stable partition. It + // moves all search-type matches towards the beginning of the range, (and + // non-search-type towards the end) but has to keep any submatches of a + // match together with that match. + // + // It does this by iterating through the list, top to bottom, so that it + // can associate submatches with their match simply by position. It finds + // a section of matches to be moved down, then finds the following section + // of matches to be moved up: + // + // Search-type (a search-type in the correct position, skipped) + // Navigation-type <- begin + // submatch Search-type + // Navigation-type + // Search-type <- mid + // submatch Navigation-type + // ... <- temp_end + // + // We then call rotate() with those 3 iterators, then repeat the search, + // starting with where the navigation-types landed. + + // Find the first element to be moved downwards. Skip matches in correct + // position. + while (begin != end && + (AutocompleteMatch::IsSearchType(begin->type) || + // Any submatch present would belong to the previous search-type + // match. + begin->IsSubMatch())) { + begin = std::next(begin); + } + while (begin != end) { + // Find the last element (technically, the end of the range) to be moved + // downwards. + auto mid = begin; + while (mid != end && + (!AutocompleteMatch::IsSearchType(mid->type) || mid->IsSubMatch())) { + mid = std::next(mid); + } + // Find the last element (technically, the end of the range) to be moved + // upwards. + auto temp_end = mid; + while (temp_end != end && + (AutocompleteMatch::IsSearchType(temp_end->type) || + temp_end->IsSubMatch())) { + temp_end = std::next(temp_end); + } + if (mid != end) { + std::rotate(begin, mid, temp_end); + // Advance |begin| iterator over the elements now in correct position. + // |begin += temp_end - mid;| + begin = std::next(begin, std::distance(mid, temp_end)); + } else { + break; + } + } +}
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h index 69079ea..e83c103 100644 --- a/components/omnibox/browser/autocomplete_result.h +++ b/components/omnibox/browser/autocomplete_result.h
@@ -145,6 +145,8 @@ FRIEND_TEST_ALL_PREFIXES(AutocompleteResultTest, ConvertsOpenTabsCorrectly); FRIEND_TEST_ALL_PREFIXES(AutocompleteResultTest, PedalSuggestionsRemainUnique); + FRIEND_TEST_ALL_PREFIXES(AutocompleteResultTest, + TestGroupSuggestionsBySearchVsURL); typedef std::map<AutocompleteProvider*, ACMatches> ProviderToMatches; @@ -203,6 +205,12 @@ size_t max_url_count, const CompareWithDemoteByType<AutocompleteMatch>& comparing_object); + // This method implements a stateful stable partition. Matches which are + // search types, and their submatches regardless of type, are shifted + // earlier in the range, while non-search types and their submatches + // are shifted later. + static void GroupSuggestionsBySearchVsURL(iterator begin, iterator end); + ACMatches matches_; const_iterator default_match_;
diff --git a/components/omnibox/browser/autocomplete_result_unittest.cc b/components/omnibox/browser/autocomplete_result_unittest.cc index 05dbd5f5..edc9f596 100644 --- a/components/omnibox/browser/autocomplete_result_unittest.cc +++ b/components/omnibox/browser/autocomplete_result_unittest.cc
@@ -1480,3 +1480,43 @@ EXPECT_EQ(result.match_at(4)->relevance, 500); EXPECT_EQ(result.match_at(4)->pedal, nullptr); } + +TEST_F(AutocompleteResultTest, TestGroupSuggestionsBySearchVsURL) { + ACMatches matches; + matches.resize(10); + // A search-type to stay. + matches[0].type = AutocompleteMatchType::SEARCH_SUGGEST; + // A non-search-type to move down. + matches[1].type = AutocompleteMatchType::HISTORY_URL; + // A search-type to move up. + matches[2].type = AutocompleteMatchType::SEARCH_SUGGEST; + // It's submatch to move up with it. + matches[3].type = AutocompleteMatchType::HISTORY_URL; + matches[3].subrelevance = 4 + 1; + // A non-search-type to move down. + matches[4].type = AutocompleteMatchType::HISTORY_URL; + // It's submatch to move down with it. + matches[5].type = AutocompleteMatchType::SEARCH_SUGGEST; + matches[5].subrelevance = 8 + 1; + // A search-type to move up. + matches[6].type = AutocompleteMatchType::SEARCH_SUGGEST; + // It's submatch to move up with it. + matches[7].type = AutocompleteMatchType::HISTORY_URL; + matches[7].subrelevance = 12 + 1; + // A non-search-type to "move down" (really, to stay). + matches[8].type = AutocompleteMatchType::HISTORY_URL; + // It's submatch to move down with it. + matches[9].type = AutocompleteMatchType::SEARCH_SUGGEST; + matches[9].subrelevance = 16 + 1; + + AutocompleteResult::GroupSuggestionsBySearchVsURL(matches.begin(), + matches.end()); + for (size_t i = 0; i < 5; ++i) { + EXPECT_TRUE(AutocompleteMatch::IsSearchType(matches[i].type) || + matches[i].IsSubMatch()); + } + for (size_t i = 5; i < 10; ++i) { + EXPECT_TRUE(!AutocompleteMatch::IsSearchType(matches[i].type) || + matches[i].IsSubMatch()); + } +}
diff --git a/components/omnibox/browser/match_compare.h b/components/omnibox/browser/match_compare.h index 4842cfae..7cb6b5f8 100644 --- a/components/omnibox/browser/match_compare.h +++ b/components/omnibox/browser/match_compare.h
@@ -71,15 +71,4 @@ CompareWithDemoteByType<Match> demote_by_type_; }; -// Such a simple comparison should only be used by std::stable_sort(). -class CompareBySearchVsUrl { - public: - bool operator()(const AutocompleteMatch& elem1, - const AutocompleteMatch& elem2) { - // Put search matches first, followed by all other types. - return AutocompleteMatch::IsSearchType(elem1.type) && - !AutocompleteMatch::IsSearchType(elem2.type); - } -}; - #endif // COMPONENTS_OMNIBOX_BROWSER_MATCH_COMPARE_H_
diff --git a/components/omnibox/browser/zero_suggest_provider.cc b/components/omnibox/browser/zero_suggest_provider.cc index 01c71de..11fb26e 100644 --- a/components/omnibox/browser/zero_suggest_provider.cc +++ b/components/omnibox/browser/zero_suggest_provider.cc
@@ -546,11 +546,11 @@ if (client()->IsOffTheRecord()) return false; - // Check if ZeroSuggest is allowed in an empty state. + // When the omnibox is empty, only allow zero suggest for the ChromeOS + // Launcher and NTP. if (input_type == metrics::OmniboxInputType::EMPTY && !(page_class == metrics::OmniboxEventProto::CHROMEOS_APP_LIST || - (IsNTPPage(page_class) && - base::FeatureList::IsEnabled(omnibox::kZeroSuggestionsOnNTP)))) { + IsNTPPage(page_class))) { return false; }
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index 9a79a47..495e2f5 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -86,11 +86,6 @@ #endif }; -// Feature used to enable enhanced presentation showing larger images. -// This is currently only used on Android. -const base::Feature kOmniboxNewAnswerLayout{"OmniboxNewAnswerLayout", - base::FEATURE_DISABLED_BY_DEFAULT}; - const base::Feature kOmniboxPreserveDefaultMatchScore{ "OmniboxPreserveDefaultMatchScore", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h index a63a17b..19edd216 100644 --- a/components/omnibox/common/omnibox_features.h +++ b/components/omnibox/common/omnibox_features.h
@@ -20,7 +20,6 @@ extern const base::Feature kOmniboxLocalEntitySuggestions; extern const base::Feature kOmniboxMaxURLMatches; extern const base::Feature kOmniboxRichEntitySuggestions; -extern const base::Feature kOmniboxNewAnswerLayout; extern const base::Feature kOmniboxReverseAnswers; extern const base::Feature kOmniboxShortBookmarkSuggestions; extern const base::Feature kOmniboxTailSuggestions;
diff --git a/components/optimization_guide/hints_component_util.cc b/components/optimization_guide/hints_component_util.cc index 646222cc..4e89c40 100644 --- a/components/optimization_guide/hints_component_util.cc +++ b/components/optimization_guide/hints_component_util.cc
@@ -29,6 +29,9 @@ } // namespace +const char kComponentHintsUpdatedResultHistogramString[] = + "OptimizationGuide.UpdateComponentHints.Result"; + void RecordProcessHintsComponentResult(ProcessHintsComponentResult result) { UMA_HISTOGRAM_ENUMERATION(kProcessHintsComponentResultHistogramString, result);
diff --git a/components/optimization_guide/hints_component_util.h b/components/optimization_guide/hints_component_util.h index 97c3b3a..620c936e 100644 --- a/components/optimization_guide/hints_component_util.h +++ b/components/optimization_guide/hints_component_util.h
@@ -13,6 +13,10 @@ struct HintsComponentInfo; +// The local histogram used to record that the component hints are stored in +// the cache and are ready for use. +extern const char kComponentHintsUpdatedResultHistogramString[]; + // Enumerates the possible outcomes of processing the hints component. // // Used in UMA histograms, so the order of enumerators should not be changed.
diff --git a/components/password_manager/core/browser/form_parsing/form_parser.cc b/components/password_manager/core/browser/form_parsing/form_parser.cc index 452d023..83c53df 100644 --- a/components/password_manager/core/browser/form_parsing/form_parser.cc +++ b/components/password_manager/core/browser/form_parsing/form_parser.cc
@@ -109,9 +109,12 @@ // True if field->form_control_type == "password". bool is_password = false; - // True if the server predicts this field not to be a password. + // True if the server predicts that this field is not a password field. bool server_hints_not_password = false; + // True if the server predicts that this field is not a username field. + bool server_hints_not_username = false; + Interactability interactability = Interactability::kUnlikely; }; @@ -135,6 +138,11 @@ field.autocomplete_flag == AutocompleteFlag::kCreditCard; } +// Returns true if the |field| is suspected to be not the username field. +bool IsNotUsernameField(const ProcessedField& field) { + return field.server_hints_not_username; +} + // Returns true iff |field_type| is one of password types. bool IsPasswordPrediction(const CredentialFieldType field_type) { switch (field_type) { @@ -359,11 +367,14 @@ // For the use of basic heuristics, also mark CVC fields and NOT_PASSWORD // fields as such. for (const PasswordFieldPrediction& prediction : predictions) { + ProcessedField* current_field = FindField(processed_fields, prediction); + if (!current_field) + continue; if (prediction.type == autofill::CREDIT_CARD_VERIFICATION_CODE || prediction.type == autofill::NOT_PASSWORD) { - ProcessedField* processed_field = FindField(processed_fields, prediction); - if (processed_field) - processed_field->server_hints_not_password = true; + current_field->server_hints_not_password = true; + } else if (prediction.type == autofill::NOT_USERNAME) { + current_field->server_hints_not_username = true; } } } @@ -388,7 +399,8 @@ } switch (processed_field.autocomplete_flag) { case AutocompleteFlag::kUsername: - if (processed_field.is_password || result->username) + if (processed_field.is_password || result->username || + processed_field.server_hints_not_username) continue; username_fields_found++; field_marked_as_username = processed_field.field; @@ -605,6 +617,7 @@ const FormFieldData* focusable_username = nullptr; const FormFieldData* username = nullptr; + // Do reverse search to find the closest candidates preceding the password. for (auto it = std::make_reverse_iterator(first_relevant_password); it != processed_fields.rend(); ++it) { @@ -616,6 +629,9 @@ continue; if (!is_fallback && IsNotPasswordField(*it)) continue; + if (!is_fallback && IsNotUsernameField(*it)) { + continue; + } if (!username) username = it->field; if (it->field->is_focusable) {
diff --git a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc index 72ea19d6..059fbb4 100644 --- a/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc +++ b/components/password_manager/core/browser/form_parsing/form_parser_unittest.cc
@@ -418,13 +418,15 @@ TEST(FormParserTest, NotPasswordForm) { CheckTestData({ { - "No fields", {}, + "No fields", + {}, }, { .description_for_logging = "No password fields", .fields = { - {.form_control_type = "text"}, {.form_control_type = "text"}, + {.form_control_type = "text"}, + {.form_control_type = "text"}, }, .number_of_all_possible_passwords = 0, .number_of_all_possible_usernames = 0, @@ -1097,7 +1099,6 @@ {.role_saving = ElementRole::CURRENT_PASSWORD, .form_control_type = "password"}, {.role_filling = ElementRole::NEW_PASSWORD, - .prediction = {.type = autofill::ACCOUNT_CREATION_PASSWORD}, .form_control_type = "password"}, {.role_filling = ElementRole::CONFIRMATION_PASSWORD, @@ -1120,7 +1121,6 @@ .form_control_type = "password"}, }, }, - }); } @@ -1520,6 +1520,62 @@ }); } +// The parser should avoid identifying NOT_USERNAME fields as usernames. +TEST(FormParserTest, NotUsernameField) { + CheckTestData({ + { + "Server hints: NOT_USERNAME.", + {{.role = ElementRole::USERNAME, .form_control_type = "text"}, + {.role = ElementRole::NONE, + .form_control_type = "text", + .prediction = {.type = autofill::NOT_USERNAME}}, + {.role = ElementRole::CURRENT_PASSWORD, + .form_control_type = "password", + .prediction = {.type = autofill::PASSWORD}}}, + .fallback_only = false, + }, + { + "Server hints: NOT_USERNAME on only username.", + {{.role = ElementRole::NONE, + .form_control_type = "text", + .prediction = {.type = autofill::NOT_USERNAME}}, + {.role = ElementRole::CURRENT_PASSWORD, + .form_control_type = "password"}}, + .fallback_only = false, + }, + }); +} + +// The parser should avoid identifying NOT_USERNAME fields as usernames despite +// autocomplete attribute. +TEST(FormParserTest, NotUsernameFieldDespiteAutocompelteAtrribute) { + CheckTestData({ + { + "Server hints: NOT_USERNAME.", + {{.role = ElementRole::USERNAME, .form_control_type = "text"}, + {.form_control_type = "text", + .autocomplete_attribute = "username", + .prediction = {.type = autofill::NOT_USERNAME}}, + {.role = ElementRole::CURRENT_PASSWORD, + .form_control_type = "password", + .prediction = {.type = autofill::PASSWORD}}}, + .fallback_only = false, + }, + { + "Server hints: NOT_USERNAME on only username.", + { + {.role = ElementRole::NONE, + .form_control_type = "text", + .autocomplete_attribute = "username", + .prediction = {.type = autofill::NOT_USERNAME}}, + {.role = ElementRole::CURRENT_PASSWORD, + .form_control_type = "password"}, + }, + .fallback_only = false, + }, + }); +} + // The parser should avoid identifying NOT_PASSWORD fields as passwords. TEST(FormParserTest, NotPasswordFieldDespiteAutocompleteAttribute) { CheckTestData({ @@ -1968,8 +2024,7 @@ // saving mode. SCOPED_TRACE(histogram_test_case.parsing_data.description_for_logging); tester.ExpectUniqueSample("PasswordManager.UsernameDetectionMethod", - histogram_test_case.expected_method, - 2); + histogram_test_case.expected_method, 2); } }
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index 0735964..5e3dc0e 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc
@@ -1459,6 +1459,12 @@ return true; } +bool LoginDatabase::IsEmpty() { + sql::Statement s( + db_.GetCachedStatement(SQL_FROM_HERE, "SELECT COUNT(*) FROM logins")); + return s.Step() && s.ColumnInt(0) == 0; +} + bool LoginDatabase::DeleteAndRecreateDatabaseFile() { DCHECK(db_.is_open()); meta_table_.Reset();
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h index 303210a..8934c46 100644 --- a/components/password_manager/core/browser/login_database.h +++ b/components/password_manager/core/browser/login_database.h
@@ -152,6 +152,8 @@ // whether further use of this login database will succeed is unspecified. bool DeleteAndRecreateDatabaseFile(); + bool IsEmpty(); + // On MacOS, it deletes all logins from the database that cannot be decrypted // when encryption key from Keychain is available. If the Keychain is locked, // it does nothing and returns ENCRYPTION_UNAVAILABLE. If it's not running on
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc index e150ca1..58721ec 100644 --- a/components/password_manager/core/browser/login_database_unittest.cc +++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -283,6 +283,7 @@ // Verify the database is empty. EXPECT_TRUE(db().GetAutofillableLogins(&result)); EXPECT_EQ(0U, result.size()); + EXPECT_TRUE(db().IsEmpty()); EXPECT_EQ(db().GetAllLogins(&key_to_form_map), FormRetrievalResult::kSuccess); EXPECT_EQ(0U, key_to_form_map.size()); @@ -299,6 +300,7 @@ EXPECT_TRUE(db().GetAutofillableLogins(&result)); ASSERT_EQ(1U, result.size()); EXPECT_EQ(form, *result[0]); + EXPECT_FALSE(db().IsEmpty()); result.clear(); EXPECT_EQ(db().GetAllLogins(&key_to_form_map), FormRetrievalResult::kSuccess); @@ -391,6 +393,7 @@ EXPECT_EQ(2, changes[0].primary_key()); EXPECT_TRUE(db().GetAutofillableLogins(&result)); EXPECT_EQ(0U, result.size()); + EXPECT_TRUE(db().IsEmpty()); } TEST_F(LoginDatabaseTest, AddLoginReturnsPrimaryKey) {
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json index a03cc3a..72e7f12 100644 --- a/components/policy/resources/policy_templates.json +++ b/components/policy/resources/policy_templates.json
@@ -3349,7 +3349,7 @@ 'dynamic_refresh': False, 'per_profile': False, }, - 'example_value': '*example.com,foobar.com,*baz', + 'example_value': '*.example.com,example.com', 'id': 29, 'caption': '''Authentication server whitelist''', 'tags': [],
diff --git a/components/previews/content/previews_optimization_guide.cc b/components/previews/content/previews_optimization_guide.cc index 33b4c586..49a8a9ed 100644 --- a/components/previews/content/previews_optimization_guide.cc +++ b/components/previews/content/previews_optimization_guide.cc
@@ -8,6 +8,7 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/metrics/histogram_macros.h" +#include "base/metrics/histogram_macros_local.h" #include "base/rand_util.h" #include "base/task/post_task.h" #include "base/task_runner_util.h" @@ -15,6 +16,7 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h" #include "components/optimization_guide/hint_cache_store.h" #include "components/optimization_guide/hints_component_info.h" +#include "components/optimization_guide/hints_component_util.h" #include "components/optimization_guide/hints_fetcher.h" #include "components/optimization_guide/optimization_guide_features.h" #include "components/optimization_guide/optimization_guide_prefs.h" @@ -328,6 +330,13 @@ base::OnceClosure update_closure) { DCHECK(ui_task_runner_->BelongsToCurrentThread()); DCHECK(pref_service_); + + // Record the result of updating the hints. This is used as a signal for the + // hints being fully processed in release tools and testing. + LOCAL_HISTOGRAM_BOOLEAN( + optimization_guide::kComponentHintsUpdatedResultHistogramString, + hints_ != nullptr); + if (!update_closure.is_null()) std::move(update_closure).Run();
diff --git a/components/previews/content/previews_optimization_guide_unittest.cc b/components/previews/content/previews_optimization_guide_unittest.cc index c83f6fd4..6f7a58c 100644 --- a/components/previews/content/previews_optimization_guide_unittest.cc +++ b/components/previews/content/previews_optimization_guide_unittest.cc
@@ -244,12 +244,21 @@ void ProcessHints(const optimization_guide::proto::Configuration& config, const std::string& version) { + base::HistogramTester histogram_tester; + optimization_guide::HintsComponentInfo info( base::Version(version), temp_dir().Append(FILE_PATH_LITERAL("somefile.pb"))); ASSERT_NO_FATAL_FAILURE(WriteConfigToFile(config, info.path)); + base::RunLoop run_loop; + guide_->ListenForNextUpdateForTesting(run_loop.QuitClosure()); guide_->OnHintsComponentAvailable(info); - RunUntilIdle(); + run_loop.Run(); + + // Check for histogram to ensure that we do not remove this histogram since + // it's relied on in release tools. + histogram_tester.ExpectTotalCount( + "OptimizationGuide.UpdateComponentHints.Result", 1); } void EnableDataSaver() {
diff --git a/components/safe_browsing/db/v4_database.cc b/components/safe_browsing/db/v4_database.cc index cad85de..435b4b3 100644 --- a/components/safe_browsing/db/v4_database.cc +++ b/components/safe_browsing/db/v4_database.cc
@@ -292,18 +292,8 @@ bool V4Database::IsStoreAvailable(const ListIdentifier& identifier) const { const auto& store_pair = store_map_->find(identifier); - bool store_found = store_pair != store_map_->end(); - UMA_HISTOGRAM_BOOLEAN("SafeBrowsing.V4Store.IsStoreAvailable.ValidStore", - store_found); - if (!store_found) { - // Store not in our list - return false; - } - if (!store_pair->second->HasValidData()) { - // Store never properly populated - return false; - } - return true; + return (store_pair != store_map_->end()) && + store_pair->second->HasValidData(); } void V4Database::RecordFileSizeHistograms() {
diff --git a/components/signin/core/browser/android/BUILD.gn b/components/signin/core/browser/android/BUILD.gn index 6365991..faf5325 100644 --- a/components/signin/core/browser/android/BUILD.gn +++ b/components/signin/core/browser/android/BUILD.gn
@@ -39,8 +39,6 @@ "java/src/org/chromium/components/signin/ChildAccountStatus.java", "java/src/org/chromium/components/signin/ChromeSigninController.java", "java/src/org/chromium/components/signin/ConsistencyCookieManager.java", - "java/src/org/chromium/components/signin/CoreAccountId.java", - "java/src/org/chromium/components/signin/CoreAccountInfo.java", "java/src/org/chromium/components/signin/GmsAvailabilityException.java", "java/src/org/chromium/components/signin/GmsJustUpdatedException.java", "java/src/org/chromium/components/signin/util/PatternMatcher.java",
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountIdProvider.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountIdProvider.java index 4a95792..a56464d 100644 --- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountIdProvider.java +++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountIdProvider.java
@@ -4,24 +4,24 @@ package org.chromium.components.signin; +import com.google.android.gms.auth.GoogleAuthException; +import com.google.android.gms.auth.GoogleAuthUtil; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import org.chromium.base.ContextUtils; +import org.chromium.base.Log; import org.chromium.base.StrictModeContext; import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; -import java.util.List; +import java.io.IOException; /** * Returns a stable id that can be used to identify a Google Account. This * id does not change if the email address associated to the account changes, * nor does it change depending on whether the email has dots or varying * capitalization. - * - * TODO(https://crbug.com/831257): remove this class after all clients start using {@link - * AccountManagerFacade} methods instead. */ public class AccountIdProvider { private static AccountIdProvider sProvider; @@ -40,16 +40,12 @@ * @param accountName The email address of a Google account. */ public String getAccountId(String accountName) { - List<CoreAccountInfo> accountInfos = AccountManagerFacade.get().tryGetAccounts(); - if (accountInfos == null) { + try { + return GoogleAuthUtil.getAccountId(ContextUtils.getApplicationContext(), accountName); + } catch (IOException | GoogleAuthException ex) { + Log.e("cr.AccountIdProvider", "AccountIdProvider.getAccountId", ex); return null; } - for (CoreAccountInfo accountInfo : accountInfos) { - if (accountInfo.getName().equals(accountName)) { - return accountInfo.getId().getGaiaIdAsString(); - } - } - return null; } /**
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java index 057d9ae0..a35a24a42 100644 --- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java +++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerDelegate.java
@@ -16,8 +16,6 @@ import org.chromium.base.Callback; -import java.util.List; - /** * Abstraction of account management implementation. * Provides methods for getting accounts and managing auth tokens. @@ -44,10 +42,10 @@ void removeObserver(AccountsChangeObserver observer); /** - * Get information about all the accounts synchronously. + * Get all the accounts synchronously. */ @WorkerThread - List<CoreAccountInfo> getAccountInfosSync() throws AccountManagerDelegateException; + Account[] getAccountsSync() throws AccountManagerDelegateException; /** * Get an auth token.
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java index 4c23d12..be552d5 100644 --- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java +++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
@@ -33,6 +33,7 @@ import org.chromium.components.signin.util.PatternMatcher; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -81,9 +82,9 @@ // These two variables should be accessed from either UI thread or during initialization phase. private PatternMatcher[] mAccountRestrictionPatterns; - private AccountManagerResult<List<CoreAccountInfo>> mAllAccounts; + private AccountManagerResult<List<Account>> mAllAccounts; - private final AtomicReference<AccountManagerResult<List<CoreAccountInfo>>> mFilteredAccounts = + private final AtomicReference<AccountManagerResult<List<Account>>> mFilteredAccounts = new AtomicReference<>(); private final CountDownLatch mPopulateAccountCacheLatch = new CountDownLatch(1); private final CachedMetrics.TimesHistogramSample mPopulateAccountCacheWaitingTimeHistogram = @@ -227,14 +228,74 @@ } /** - * Retrieves {@link CoreAccountInfo} for all Google accounts on the device. + * Retrieves a list of the Google account names on the device. * * @throws AccountManagerDelegateException if Google Play Services are out of date, * Chrome lacks necessary permissions, etc. */ @AnyThread - public List<CoreAccountInfo> getAccounts() throws AccountManagerDelegateException { - AccountManagerResult<List<CoreAccountInfo>> maybeAccounts = mFilteredAccounts.get(); + public List<String> getGoogleAccountNames() throws AccountManagerDelegateException { + List<String> accountNames = new ArrayList<>(); + for (Account account : getGoogleAccounts()) { + accountNames.add(account.name); + } + return accountNames; + } + + /** + * Retrieves a list of the Google account names on the device. + * Returns an empty list if Google Play Services aren't available or out of date. + */ + @AnyThread + public List<String> tryGetGoogleAccountNames() { + List<String> accountNames = new ArrayList<>(); + List<Account> tryGetGoogleAccounts = tryGetGoogleAccounts(); + for (int i = 0; i < tryGetGoogleAccounts.size(); i++) { + Account account = tryGetGoogleAccounts.get(i); + accountNames.add(account.name); + } + return accountNames; + } + + /** + * Asynchronous version of {@link #tryGetGoogleAccountNames()}. + */ + @MainThread + public void tryGetGoogleAccountNames(final Callback<List<String>> callback) { + runAfterCacheIsPopulated(() -> callback.onResult(tryGetGoogleAccountNames())); + } + + /** + * Asynchronous version of {@link #tryGetGoogleAccountNames()}. + */ + @MainThread + public void getGoogleAccountNames( + final Callback<AccountManagerResult<List<String>>> callback) { + runAfterCacheIsPopulated(() -> { + final AccountManagerResult<List<Account>> accounts = mFilteredAccounts.get(); + final AccountManagerResult<List<String>> result; + if (accounts.hasValue()) { + List<String> accountNames = new ArrayList<>(accounts.getValue().size()); + for (Account account : accounts.getValue()) { + accountNames.add(account.name); + } + result = new AccountManagerResult<>(accountNames); + } else { + result = new AccountManagerResult<>(accounts.getException()); + } + callback.onResult(result); + }); + } + + /** + * Retrieves all Google accounts on the device. + * + * @throws AccountManagerDelegateException if Google Play Services are out of date, + * Chrome lacks necessary permissions, etc. + */ + @AnyThread + public List<Account> getGoogleAccounts() throws AccountManagerDelegateException { + AccountManagerResult<List<Account>> maybeAccounts = mFilteredAccounts.get(); if (maybeAccounts == null) { try { // First call to update hasn't finished executing yet, should wait for it @@ -253,148 +314,16 @@ } /** - * Asynchronous version of {@link #getAccounts()}. The {@code callback} will be executed on the - * UI thread after the account cache is populated. - */ - @MainThread - public void getAccounts(Callback<AccountManagerResult<List<CoreAccountInfo>>> callback) { - runAfterCacheIsPopulated(() -> callback.onResult(mFilteredAccounts.get())); - } - - /** - * Retrieves {@link CoreAccountInfo} for all Google accounts on the device. - * Returns an empty array if an error occurs while getting account information list. - */ - @AnyThread - public List<CoreAccountInfo> tryGetAccounts() { - try { - return getAccounts(); - } catch (AccountManagerDelegateException e) { - return Collections.emptyList(); - } - } - - /** - * Asynchronous version of {@link #tryGetAccounts()}. The {@code callback} will be executed on - * the UI thread after the account cache is populated. - */ - @MainThread - public void tryGetAccounts(final Callback<List<CoreAccountInfo>> callback) { - runAfterCacheIsPopulated(() -> callback.onResult(tryGetAccounts())); - } - - /** - * Retrieves a list of the Google account names on the device. - * TODO(https://crbug.com/831257): Move all callers to getAccounts and remove this - * method. - * - * @throws AccountManagerDelegateException if Google Play Services are out of date, - * Chrome lacks necessary permissions, etc. - */ - @AnyThread - public List<String> getGoogleAccountNames() throws AccountManagerDelegateException { - List<String> accountNames = new ArrayList<>(); - for (CoreAccountInfo account : getAccounts()) { - accountNames.add(account.getName()); - } - return accountNames; - } - - /** - * Asynchronous version of {@link #getGoogleAccountNames()}. - * TODO(https://crbug.com/831257): Move all callers to getAccounts and remove this - * method. - */ - @MainThread - public void getGoogleAccountNames( - final Callback<AccountManagerResult<List<String>>> callback) { - runAfterCacheIsPopulated(() -> { - final AccountManagerResult<List<CoreAccountInfo>> accounts = mFilteredAccounts.get(); - final AccountManagerResult<List<String>> result; - if (accounts.hasValue()) { - List<String> accountNames = new ArrayList<>(accounts.getValue().size()); - for (CoreAccountInfo account : accounts.getValue()) { - accountNames.add(account.getName()); - } - result = new AccountManagerResult<>(accountNames); - } else { - result = new AccountManagerResult<>(accounts.getException()); - } - callback.onResult(result); - }); - } - - /** - * Retrieves a list of the Google account names on the device. - * Returns an empty list if Google Play Services aren't available or out of date. - * TODO(https://crbug.com/831257): Move all callers to tryGetAccounts and remove this - * method. - */ - @AnyThread - public List<String> tryGetGoogleAccountNames() { - try { - return getGoogleAccountNames(); - } catch (AccountManagerDelegateException e) { - return Collections.emptyList(); - } - } - - /** - * Asynchronous version of {@link #tryGetGoogleAccountNames()}. - * TODO(https://crbug.com/831257): Move all callers to tryGetAccounts and remove this - * method. - */ - @MainThread - public void tryGetGoogleAccountNames(final Callback<List<String>> callback) { - runAfterCacheIsPopulated(() -> callback.onResult(tryGetGoogleAccountNames())); - } - - /** - * Retrieves all Google accounts on the device. - * TODO(https://crbug.com/831257): Move all callers to getAccounts and remove this - * method. - * - * @throws AccountManagerDelegateException if Google Play Services are out of date, - * Chrome lacks necessary permissions, etc. - */ - @AnyThread - public List<Account> getGoogleAccounts() throws AccountManagerDelegateException { - List<Account> accounts = new ArrayList<>(); - for (CoreAccountInfo account : getAccounts()) { - accounts.add(account.getAccount()); - } - return accounts; - } - - /** * Asynchronous version of {@link #getGoogleAccounts()}. - * TODO(https://crbug.com/831257): Move all callers to getAccounts and remove this - * method. */ @MainThread public void getGoogleAccounts(Callback<AccountManagerResult<List<Account>>> callback) { - runAfterCacheIsPopulated(() -> { - final AccountManagerResult<List<CoreAccountInfo>> accountInfos = - mFilteredAccounts.get(); - final AccountManagerResult<List<Account>> result; - if (accountInfos.hasValue()) { - List<Account> accounts = new ArrayList<>(accountInfos.getValue().size()); - for (CoreAccountInfo account : accountInfos.getValue()) { - accounts.add(account.getAccount()); - } - result = new AccountManagerResult<>(accounts); - } else { - result = new AccountManagerResult<>(accountInfos.getException()); - } - callback.onResult(result); - }); + runAfterCacheIsPopulated(() -> callback.onResult(mFilteredAccounts.get())); } /** * Retrieves all Google accounts on the device. * Returns an empty array if an error occurs while getting account list. - * TODO(https://crbug.com/831257): Move all callers to tryGetAccounts and remove this - * method. */ @AnyThread public List<Account> tryGetGoogleAccounts() { @@ -407,8 +336,6 @@ /** * Asynchronous version of {@link #tryGetGoogleAccounts()}. - * TODO(https://crbug.com/831257): Move all callers to tryGetAccounts and remove this - * method. */ @MainThread public void tryGetGoogleAccounts(final Callback<List<Account>> callback) { @@ -635,22 +562,22 @@ ContextUtils.getApplicationContext().registerReceiver(receiver, filter); } - private AccountManagerResult<List<CoreAccountInfo>> getAllAccounts() { + private AccountManagerResult<List<Account>> getAllAccounts() { try { - List<CoreAccountInfo> accounts = mDelegate.getAccountInfosSync(); + List<Account> accounts = Arrays.asList(mDelegate.getAccountsSync()); return new AccountManagerResult<>(Collections.unmodifiableList(accounts)); } catch (AccountManagerDelegateException ex) { return new AccountManagerResult<>(ex); } } - private AccountManagerResult<List<CoreAccountInfo>> getFilteredAccounts() { + private AccountManagerResult<List<Account>> getFilteredAccounts() { if (mAllAccounts.hasException() || mAccountRestrictionPatterns == null) return mAllAccounts; - ArrayList<CoreAccountInfo> filteredAccounts = new ArrayList<>(); - for (CoreAccountInfo accountInfo : mAllAccounts.getValue()) { + ArrayList<Account> filteredAccounts = new ArrayList<>(); + for (Account account : mAllAccounts.getValue()) { for (PatternMatcher pattern : mAccountRestrictionPatterns) { - if (pattern.matches(accountInfo.getName())) { - filteredAccounts.add(accountInfo); + if (pattern.matches(account.name)) { + filteredAccounts.add(account); break; // Don't check other patterns } } @@ -694,7 +621,7 @@ fireOnAccountsChangedNotification(); } - private void setAllAccounts(AccountManagerResult<List<CoreAccountInfo>> allAccounts) { + private void setAllAccounts(AccountManagerResult<List<Account>> allAccounts) { mAllAccounts = allAccounts; mFilteredAccounts.set(getFilteredAccounts()); fireOnAccountsChangedNotification(); @@ -771,20 +698,19 @@ } } - private class UpdateAccountsTask - extends AsyncTask<AccountManagerResult<List<CoreAccountInfo>>> { + private class UpdateAccountsTask extends AsyncTask<AccountManagerResult<List<Account>>> { @Override protected void onPreExecute() { incrementUpdateCounter(); } @Override - protected AccountManagerResult<List<CoreAccountInfo>> doInBackground() { + protected AccountManagerResult<List<Account>> doInBackground() { return getAllAccounts(); } @Override - protected void onPostExecute(AccountManagerResult<List<CoreAccountInfo>> allAccounts) { + protected void onPostExecute(AccountManagerResult<List<Account>> allAccounts) { setAllAccounts(allAccounts); decrementUpdateCounter(); }
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/CoreAccountId.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/CoreAccountId.java deleted file mode 100644 index 2535f9a..0000000 --- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/CoreAccountId.java +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.signin; - -import android.support.annotation.NonNull; - -/** - * A wrapper around Gaia ID that represents a stable account identifier. - * - * This wrapper helps to make sure that code using accounts doesn't accidentally use account name in - * place of Gaia ID and vice versa. - * - * This class has a native counterpart called CoreAccountId. - */ -public class CoreAccountId { - private final String mGaiaId; - - /** - * Constructs a new CoreAccountId from a String representation of Gaia ID. - */ - public CoreAccountId(@NonNull String gaiaId) { - assert gaiaId != null; - // Check that a user email is not used by mistake. - assert !gaiaId.contains("@"); - - mGaiaId = gaiaId; - } - - public String getGaiaIdAsString() { - return mGaiaId; - } - - @Override - public String toString() { - return mGaiaId; - } - - @Override - public int hashCode() { - return mGaiaId.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof CoreAccountId)) return false; - CoreAccountId other = (CoreAccountId) obj; - return mGaiaId.equals(other.mGaiaId); - } -}
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/CoreAccountInfo.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/CoreAccountInfo.java deleted file mode 100644 index 15e9731..0000000 --- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/CoreAccountInfo.java +++ /dev/null
@@ -1,73 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.components.signin; - -import android.accounts.Account; -import android.support.annotation.NonNull; - -/** - * Structure storing the core information about a Google account that is always known. The {@link - * CoreAccountInfo} for a given user is almost always the same but it may change in some rare cases. - * For example, the {@link android.accounts.Account} will change if a user changes email. - * - * This class has a native counterpart called CoreAccountInfo. There are several differences between - * these two classes: - * - Android class doesn't store Gaia ID as a string because {@link CoreAccountId} already contains - * it. - * - Android class additionally exposes {@link android.accounts.Account} object for interactions - * with the system. - * - Android class has the "account name" whereas the native class has "email". This is the same - * string, only the naming in different. - */ -public class CoreAccountInfo { - private final CoreAccountId mId; - private final Account mAccount; - - public CoreAccountInfo(@NonNull CoreAccountId id, @NonNull Account account) { - assert id != null; - assert account != null; - - mId = id; - mAccount = account; - } - - /** - * Returns a unique identifier of the current account. - */ - public CoreAccountId getId() { - return mId; - } - - /** - * Returns a name of the current account. - */ - public String getName() { - return mAccount.name; - } - - /** - * Returns {@link android.accounts.Account} object holding a name of the current account. - */ - public Account getAccount() { - return mAccount; - } - - @Override - public String toString() { - return String.format("CoreAccountInfo{id[%s], name[%s]}", getId(), getName()); - } - - @Override - public int hashCode() { - return 31 * mId.hashCode() + mAccount.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof CoreAccountInfo)) return false; - CoreAccountInfo other = (CoreAccountInfo) obj; - return mId.equals(other.mId) && mAccount.equals(other.mAccount); - } -}
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java index 32be60ee..d722020 100644 --- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java +++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/SystemAccountManagerDelegate.java
@@ -40,8 +40,6 @@ import org.chromium.base.metrics.RecordHistogram; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; /** * Default implementation of {@link AccountManagerDelegate} which delegates all calls to the @@ -113,64 +111,23 @@ } @Override - public List<CoreAccountInfo> getAccountInfosSync() throws AccountManagerDelegateException { - // GoogleAuthUtil.getAccountId requires Google Play Services being up to date. + public Account[] getAccountsSync() throws AccountManagerDelegateException { + // Account seeding relies on GoogleAuthUtil.getAccountId to get GAIA ids, + // so don't report any accounts if Google Play Services are out of date. checkCanUseGooglePlayServices(); - long startTime = SystemClock.elapsedRealtime(); - Account[] accounts = getAccountsSync(); - long accountsTime = SystemClock.elapsedRealtime(); - List<CoreAccountInfo> accountInfos = buildAccountInfoList(accounts); - long endTime = SystemClock.elapsedRealtime(); - recordElapsedTimeHistogram( - "Signin.AndroidGetAccountsTime_AccountManager.Accounts", accountsTime - startTime); - recordElapsedTimeHistogram( - "Signin.AndroidGetAccountsTime_AccountManager.Ids", endTime - accountsTime); - recordElapsedTimeHistogram( - "Signin.AndroidGetAccountsTime_AccountManager.Total", endTime - startTime); - return accountInfos; - } - - // TODO(https://crbug.com/831257): remove this. - public Account[] getAccountsSync() throws AccountManagerDelegateException { - return getAccountsFromAccountManager(); - } - - private Account[] getAccountsFromAccountManager() { if (!hasGetAccountsPermission()) { return new Account[] {}; } - return mAccountManager.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE); - } - - protected final List<CoreAccountInfo> buildAccountInfoList(Account[] accounts) - throws AccountManagerDelegateException { - List<CoreAccountInfo> accountInfos = new ArrayList<>(accounts.length); - for (Account account : accounts) { - CoreAccountId accountId = getAccountId(account.name); - if (accountId != null) { - accountInfos.add(new CoreAccountInfo(accountId, account)); - } + long now = SystemClock.elapsedRealtime(); + Account[] accounts = mAccountManager.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE); + long elapsed = SystemClock.elapsedRealtime() - now; + recordElapsedTimeHistogram("Signin.AndroidGetAccountsTime_AccountManager", elapsed); + if (ThreadUtils.runningOnUiThread()) { + recordElapsedTimeHistogram( + "Signin.AndroidGetAccountsTimeUiThread_AccountManager", elapsed); } - return accountInfos; - } - - private CoreAccountId getAccountId(String accountName) throws AccountManagerDelegateException { - try { - String accountId = - GoogleAuthUtil.getAccountId(ContextUtils.getApplicationContext(), accountName); - return new CoreAccountId(accountId); - } catch (GooglePlayServicesAvailabilityException ex) { - Log.e(TAG, "Availability error while getting an account id", ex); - throw new GmsAvailabilityException( - String.format("Can't use Google Play Services: %s", - GoogleApiAvailability.getInstance().getErrorString( - ex.getConnectionStatusCode())), - ex.getConnectionStatusCode()); - } catch (IOException | GoogleAuthException ex) { - Log.e(TAG, "Error while getting an account id", ex); - return null; - } + return accounts; } @Override
diff --git a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/AccountManagerFacadeTest.java b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/AccountManagerFacadeTest.java index 53d0f4f..4c1ed67 100644 --- a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/AccountManagerFacadeTest.java +++ b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/AccountManagerFacadeTest.java
@@ -27,11 +27,7 @@ import org.chromium.components.signin.AccountManagerDelegateException; import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.AccountsChangeObserver; -import org.chromium.components.signin.CoreAccountId; -import org.chromium.components.signin.CoreAccountInfo; -import java.util.Arrays; -import java.util.List; import java.util.concurrent.CountDownLatch; /** @@ -53,15 +49,14 @@ public void removeObserver(AccountsChangeObserver observer) {} @Override - public List<CoreAccountInfo> getAccountInfosSync() { + public Account[] getAccountsSync() { // Block background thread that's trying to get accounts from the delegate. try { mBlockGetAccounts.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } - return Arrays.asList(new CoreAccountInfo(new CoreAccountId("testid"), - AccountManagerFacade.createAccountFromName("test@gmail.com"))); + return new Account[] {AccountManagerFacade.createAccountFromName("test@gmail.com")}; } void unblockGetAccounts() {
diff --git a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/AccountHolder.java b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/AccountHolder.java index 4578550..42df492 100644 --- a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/AccountHolder.java +++ b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/AccountHolder.java
@@ -7,9 +7,6 @@ import android.accounts.Account; import android.support.annotation.NonNull; -import org.chromium.components.signin.CoreAccountId; -import org.chromium.components.signin.CoreAccountInfo; - import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -20,28 +17,28 @@ * account, such as its password and set of granted auth tokens. */ public class AccountHolder { - private final CoreAccountInfo mAccountInfo; + private final Account mAccount; private final Map<String, String> mAuthTokens; private final Map<String, Boolean> mHasBeenAccepted; private final boolean mAlwaysAccept; private final Set<String> mFeatures; - private AccountHolder(CoreAccountInfo accountInfo, Map<String, String> authTokens, + private AccountHolder(Account account, Map<String, String> authTokens, Map<String, Boolean> hasBeenAccepted, boolean alwaysAccept, Set<String> features) { - assert accountInfo != null; + assert account != null; assert authTokens != null; assert hasBeenAccepted != null; assert features != null; - mAccountInfo = accountInfo; + mAccount = account; mAuthTokens = authTokens; mHasBeenAccepted = hasBeenAccepted; mAlwaysAccept = alwaysAccept; mFeatures = features; } - public CoreAccountInfo getAccountInfo() { - return mAccountInfo; + public Account getAccount() { + return mAccount; } public boolean hasAuthTokenRegistered(String authTokenType) { @@ -86,13 +83,13 @@ @Override public int hashCode() { - return mAccountInfo.hashCode(); + return mAccount.hashCode(); } @Override public boolean equals(Object that) { return that instanceof AccountHolder - && mAccountInfo.equals(((AccountHolder) that).getAccountInfo()); + && mAccount.equals(((AccountHolder) that).getAccount()); } public static Builder builder(@NonNull Account account) { @@ -116,8 +113,7 @@ } private Builder copy() { - return builder(mAccountInfo.getAccount()) - .accountId(mAccountInfo.getId()) + return builder(mAccount) .authTokens(mAuthTokens) .hasBeenAcceptedMap(mHasBeenAccepted) .alwaysAccept(mAlwaysAccept); @@ -128,7 +124,6 @@ */ public static class Builder { private Account mAccount; - private CoreAccountId mAccountId; private Map<String, String> mAuthTokens = new HashMap<>(); private Map<String, Boolean> mHasBeenAccepted = new HashMap<>(); private boolean mAlwaysAccept; @@ -143,11 +138,6 @@ return this; } - public Builder accountId(@NonNull CoreAccountId accountId) { - mAccountId = accountId; - return this; - } - public Builder authToken(String authTokenType, String authToken) { mAuthTokens.put(authTokenType, authToken); return this; @@ -190,13 +180,8 @@ } public AccountHolder build() { - if (mAccountId == null) { - // CoreAccountId rejects strings containing '@' symbol. - String fakeGaiaId = "gaia-id-" + mAccount.name.replace("@", "[at]"); - mAccountId = new CoreAccountId(fakeGaiaId); - } - return new AccountHolder(new CoreAccountInfo(mAccountId, mAccount), mAuthTokens, - mHasBeenAccepted, mAlwaysAccept, mFeatures); + return new AccountHolder( + mAccount, mAuthTokens, mHasBeenAccepted, mAlwaysAccept, mFeatures); } } }
diff --git a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java index 6eb1d2d..5009bcc 100644 --- a/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java +++ b/components/signin/core/browser/android/javatests/src/org/chromium/components/signin/test/util/FakeAccountManagerDelegate.java
@@ -22,14 +22,12 @@ import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.AccountsChangeObserver; import org.chromium.components.signin.AuthException; -import org.chromium.components.signin.CoreAccountInfo; import org.chromium.components.signin.ProfileDataSource; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.LinkedHashSet; -import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.CountDownLatch; @@ -105,18 +103,18 @@ } @Override - public List<CoreAccountInfo> getAccountInfosSync() throws AccountManagerDelegateException { + public Account[] getAccountsSync() throws AccountManagerDelegateException { return getAccountsSyncNoThrow(); } - public List<CoreAccountInfo> getAccountsSyncNoThrow() { - List<CoreAccountInfo> result = new ArrayList<>(); + public Account[] getAccountsSyncNoThrow() { + ArrayList<Account> result = new ArrayList<>(); synchronized (mAccounts) { for (AccountHolder ah : mAccounts) { - result.add(ah.getAccountInfo()); + result.add(ah.getAccount()); } } - return result; + return result.toArray(new Account[0]); } /** @@ -220,7 +218,7 @@ // No authtoken registered. Need to create one. String authToken = UUID.randomUUID().toString(); Log.d(TAG, - "Created new auth token for " + ah.getAccountInfo() + ": authTokenScope = " + "Created new auth token for " + ah.getAccount() + ": authTokenScope = " + authTokenScope + ", authToken = " + authToken); ah = ah.withAuthToken(authTokenScope, authToken); mAccounts.add(ah); @@ -293,7 +291,7 @@ } synchronized (mAccounts) { for (AccountHolder accountHolder : mAccounts) { - if (account.equals(accountHolder.getAccountInfo().getAccount())) { + if (account.equals(accountHolder.getAccount())) { return accountHolder; } }
diff --git a/components/sync/base/pref_names.cc b/components/sync/base/pref_names.cc index 4e1df29..1677615 100644 --- a/components/sync/base/pref_names.cc +++ b/components/sync/base/pref_names.cc
@@ -101,12 +101,6 @@ // that we only want to use once. const char kSyncPassphrasePrompted[] = "sync.passphrase_prompted"; -// Stores how many times received MEMORY_PRESSURE_LEVEL_CRITICAL. -const char kSyncMemoryPressureWarningCount[] = "sync.memory_warning_count"; - -// Stores if sync shutdown cleanly. -const char kSyncShutdownCleanly[] = "sync.shutdown_cleanly"; - // Dictionary of last seen invalidation versions for each model type. const char kSyncInvalidationVersions[] = "sync.invalidation_versions"; @@ -121,20 +115,32 @@ // flag is present. const char kLocalSyncBackendDir[] = "sync.local_sync_backend_dir"; -// Stores birth year of the syncing user that is provided by the sync server. -// Should not be logged to UMA directly. -const char kSyncDemographicsBirthYear[] = "sync.demographics.birth_year"; +// Root dictionary pref to store user demographics provided by the sync server. +// This is a read-only syncable priority pref, sent from the sync server to the +// client. +const char kSyncDemographics[] = "sync.demographics"; -// Stores offset that is used to randomize the birth year for metrics reporting. -// Should not be logged to UMA directly. -const char kSyncDemographicsBirthYearNoiseOffset[] = - "sync.demographics.birth_year_offset"; +// This pref value is subordinate to the kSyncDemographics dictionary pref and +// is synced to the client. It stores the self-reported birth year of the +// syncing user. as provided by the sync server. This value should not be logged +// to UMA directly; instead, it should be summed with the +// kSyncDemographicsBirthYearNoiseOffset. +const char kSyncDemographics_BirthYearPath[] = "birth_year"; -// Stores the encoded gender of the syncing user that is provided by the sync -// server. The gender is encoded using the Gender enum defined in -// metrics::UserDemographicsProto -// (third_party/metrics_proto/user_demographics.proto). -const char kSyncDemographicsGender[] = "sync.demographics.gender"; +// This pref value is subordinate to the kSyncDemographics dictionary pref and +// is synced to the client. It stores the self-reported gender of the syncing +// user, as provided by the sync server. The gender is encoded using the Gender +// enum defined in metrics::UserDemographicsProto +// (see third_party/metrics_proto/user_demographics.proto). +const char kSyncDemographics_GenderPath[] = "gender"; + +// Stores a "secret" offset that is used to randomize the birth year for metrics +// reporting. This value should not be logged to UMA directly; instead, it +// should be summed with the kSyncDemographicsBirthYear. This value is both +// generated and stored locally on the client and is not known outside of the +// client. It is not synced. +const char kSyncDemographicsBirthYearOffset[] = + "sync.demographics_birth_year_offset"; } // namespace prefs
diff --git a/components/sync/base/pref_names.h b/components/sync/base/pref_names.h index 542ed1c..6c4bd2b6 100644 --- a/components/sync/base/pref_names.h +++ b/components/sync/base/pref_names.h
@@ -70,9 +70,6 @@ extern const char kSyncPassphrasePrompted[]; -extern const char kSyncMemoryPressureWarningCount[]; -extern const char kSyncShutdownCleanly[]; - extern const char kSyncInvalidationVersions[]; extern const char kSyncLastRunVersion[]; @@ -80,9 +77,12 @@ extern const char kEnableLocalSyncBackend[]; extern const char kLocalSyncBackendDir[]; -extern const char kSyncDemographicsBirthYear[]; -extern const char kSyncDemographicsBirthYearNoiseOffset[]; -extern const char kSyncDemographicsGender[]; +extern const char kSyncDemographics[]; +extern const char kSyncDemographicsBirthYearOffset[]; + +// These are not prefs, they are paths inside of kSyncDemographics. +extern const char kSyncDemographics_BirthYearPath[]; +extern const char kSyncDemographics_GenderPath[]; } // namespace prefs
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc index 11af5eb..5ba3d8c 100644 --- a/components/sync/base/sync_prefs.cc +++ b/components/sync/base/sync_prefs.cc
@@ -48,6 +48,13 @@ // kSyncRequested. const char kSyncSuppressStart[] = "sync.suppress_start"; +// Obsolete pref that stored how many times sync received memory pressure +// warnings. +const char kSyncMemoryPressureWarningCount[] = "sync.memory_warning_count"; + +// Obsolete pref that stored if sync shutdown cleanly. +const char kSyncShutdownCleanly[] = "sync.shutdown_cleanly"; + std::vector<std::string> GetObsoleteUserTypePrefs() { return {prefs::kSyncAutofillProfile, prefs::kSyncAutofillWallet, @@ -121,62 +128,76 @@ // prefs. int GetBirthYearOffset(PrefService* pref_service) { int offset = - pref_service->GetInteger(prefs::kSyncDemographicsBirthYearNoiseOffset); + pref_service->GetInteger(prefs::kSyncDemographicsBirthYearOffset); if (offset == kUserDemographicsBirthYearNoiseOffsetDefaultValue) { // Generate a random offset when not cached in prefs. offset = base::RandInt(-kUserDemographicsBirthYearNoiseOffsetRange, kUserDemographicsBirthYearNoiseOffsetRange); - pref_service->SetInteger(prefs::kSyncDemographicsBirthYearNoiseOffset, - offset); + pref_service->SetInteger(prefs::kSyncDemographicsBirthYearOffset, offset); } return offset; } -// Determines whether the user can provide birth year considering that: (1) it +// Determines whether the user can provide demographics considering that: (1) it // is not possible to infer the month and the day of the birth date when the // user is in an age transition, and (2) only users of at least 18 years old can // report demographics. -bool CanUserProvideBirthYear(base::Time now, int user_birth_year) { +bool CanProvideDemographics(base::Time now, int user_birth_year, int offset) { + // Compute user age. base::Time::Exploded exploded_now_time; now.LocalExplode(&exploded_now_time); - // Use > rather than >= because we want to be sure that the user is at - // least |kUserDemographicsMinAgeInYears| without disclosing their birth date, - // which requires to add an extra year margin to minimal age to be safe. For - // example, if we are in 2019-07-10 (now) and the user was born in 1999-08-10, - // the user is not yet 20 years old (minimal age) but we cannot know that - // because we only have access to the year of the dates (2019 and 1999 - // respectively). If we make sure that the minimal age is at least 21, we are - // 100% sure that the user will be at least 20 years old when reporting - // demographics. - return exploded_now_time.year - user_birth_year > - kUserDemographicsMinAgeInYears; + int user_age = exploded_now_time.year - (user_birth_year + offset); + + // Verify if the user's age has a population size in the age distribution of + // the society that is big enough to not rise entropy of the user. At a + // certain point, as the age increase, the size of the population starts + // declining sharply as you can see in this rough representation of the age + // distribution: + // | ________ max age + // |______/ \_________ | + // | |\ + // | | \ + // +--------------------------|--------- + // 0 10 20 30 40 50 60 70 80 90 100+ + if (user_age > kUserDemographicsMaxAgeInYears) + return false; + + // Verify if user is old enough. Use > rather than >= because we want to be + // sure that the user is at least |kUserDemographicsMinAgeInYears| without + // disclosing their birth date, which requires to add an extra year margin to + // minimal age to be safe. For example, if we are in 2019-07-10 (now) and the + // user was born in 1999-08-10, the user is not yet 20 years old (minimal age) + // but we cannot know that because we only have access to the year of the + // dates (2019 and 1999 respectively). If we make sure that the minimal age is + // at least 21, we are 100% sure that the user will be at least 20 years old + // when reporting demographics. + return user_age > kUserDemographicsMinAgeInYears; } // Gets user's birth year from prefs. -base::Optional<int> GetUserBirthYear(PrefService* pref_service, - base::Time now) { - int birth_year = pref_service->GetInteger(prefs::kSyncDemographicsBirthYear); +base::Optional<int> GetUserBirthYear( + const base::DictionaryValue* demographics) { + const base::Value* value = + demographics->FindPath(prefs::kSyncDemographics_BirthYearPath); + int birth_year = (value != nullptr && value->is_int()) + ? value->GetInt() + : kUserDemographicsBirthYearDefaultValue; // Verify that there is a birth year. if (birth_year == kUserDemographicsBirthYearDefaultValue) return base::nullopt; - // Add noise to birth year. - birth_year += GetBirthYearOffset(pref_service); - - DCHECK(!now.is_null()); - - // Verify that the user is old enough to provide demographics. - if (!CanUserProvideBirthYear(now, birth_year)) - return base::nullopt; - return birth_year; } // Gets user's gender from prefs. base::Optional<metrics::UserDemographicsProto_Gender> GetUserGender( - const PrefService& pref_service) { - int gender_int = pref_service.GetInteger(prefs::kSyncDemographicsGender); + const base::DictionaryValue* demographics) { + const base::Value* value = + demographics->FindPath(prefs::kSyncDemographics_GenderPath); + int gender_int = (value != nullptr && value->is_int()) + ? value->GetInt() + : kUserDemographicsGenderDefaultValue; // Verify gender is not default. if (gender_int == kUserDemographicsGenderDefaultValue) @@ -256,23 +277,18 @@ registry->RegisterStringPref(prefs::kSyncKeystoreEncryptionBootstrapToken, std::string()); registry->RegisterBooleanPref(prefs::kSyncPassphrasePrompted, false); - registry->RegisterIntegerPref(prefs::kSyncMemoryPressureWarningCount, -1); - registry->RegisterBooleanPref(prefs::kSyncShutdownCleanly, false); registry->RegisterDictionaryPref(prefs::kSyncInvalidationVersions); registry->RegisterStringPref(prefs::kSyncLastRunVersion, std::string()); registry->RegisterBooleanPref(prefs::kEnableLocalSyncBackend, false); registry->RegisterFilePathPref(prefs::kLocalSyncBackendDir, base::FilePath()); // Demographic prefs. - registry->RegisterIntegerPref( - prefs::kSyncDemographicsBirthYear, kUserDemographicsBirthYearDefaultValue, + registry->RegisterDictionaryPref( + prefs::kSyncDemographics, user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); registry->RegisterIntegerPref( - prefs::kSyncDemographicsBirthYearNoiseOffset, + prefs::kSyncDemographicsBirthYearOffset, kUserDemographicsBirthYearNoiseOffsetDefaultValue); - registry->RegisterIntegerPref( - prefs::kSyncDemographicsGender, kUserDemographicsGenderDefaultValue, - user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF); // Obsolete prefs that will be removed after a grace period. RegisterObsoleteUserTypePrefs(registry); @@ -287,6 +303,8 @@ registry->RegisterStringPref(kSyncSpareBootstrapToken, ""); #endif registry->RegisterBooleanPref(kSyncSuppressStart, false); + registry->RegisterIntegerPref(kSyncMemoryPressureWarningCount, -1); + registry->RegisterBooleanPref(kSyncShutdownCleanly, false); } void SyncPrefs::AddSyncPrefObserver(SyncPrefObserver* sync_pref_observer) { @@ -303,9 +321,11 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Clear user demographics. - pref_service_->ClearPref(prefs::kSyncDemographicsBirthYear); - pref_service_->ClearPref(prefs::kSyncDemographicsBirthYearNoiseOffset); - pref_service_->ClearPref(prefs::kSyncDemographicsGender); + // Note that we retain kSyncDemographicsBirthYearOffset. If the user resumes + // syncing, causing these prefs to be recreated, we don't want them to start + // reporting a different randomized birth year as this could narrow down or + // even reveal their true birth year. + pref_service_->ClearPref(prefs::kSyncDemographics); ClearDirectoryConsistencyPreferences(); @@ -315,8 +335,6 @@ pref_service_->ClearPref(prefs::kSyncEncryptionBootstrapToken); pref_service_->ClearPref(prefs::kSyncKeystoreEncryptionBootstrapToken); pref_service_->ClearPref(prefs::kSyncPassphrasePrompted); - pref_service_->ClearPref(prefs::kSyncMemoryPressureWarningCount); - pref_service_->ClearPref(prefs::kSyncShutdownCleanly); pref_service_->ClearPref(prefs::kSyncInvalidationVersions); pref_service_->ClearPref(prefs::kSyncLastRunVersion); // No need to clear kManaged, kEnableLocalSyncBackend or kLocalSyncBackendDir, @@ -544,22 +562,6 @@ pref_service_->SetBoolean(prefs::kSyncPassphrasePrompted, value); } -int SyncPrefs::GetMemoryPressureWarningCount() const { - return pref_service_->GetInteger(prefs::kSyncMemoryPressureWarningCount); -} - -void SyncPrefs::SetMemoryPressureWarningCount(int value) { - pref_service_->SetInteger(prefs::kSyncMemoryPressureWarningCount, value); -} - -bool SyncPrefs::DidSyncShutdownCleanly() const { - return pref_service_->GetBoolean(prefs::kSyncShutdownCleanly); -} - -void SyncPrefs::SetCleanShutdown(bool value) { - pref_service_->SetBoolean(prefs::kSyncShutdownCleanly, value); -} - void SyncPrefs::GetInvalidationVersions( std::map<ModelType, int64_t>* invalidation_versions) const { const base::DictionaryValue* invalidation_dictionary = @@ -609,19 +611,31 @@ if (now.is_null()) return base::nullopt; - // Get birth year and gender. - base::Optional<int> birth_year = GetUserBirthYear(pref_service_, now); + // Get the pref that contains the demographic info. + const base::DictionaryValue* demographics = + pref_service_->GetDictionary(prefs::kSyncDemographics); + DCHECK(demographics != nullptr); + + // Get the user's birth year. + base::Optional<int> birth_year = GetUserBirthYear(demographics); if (!birth_year.has_value()) return base::nullopt; + + // Get the user's gender. base::Optional<metrics::UserDemographicsProto_Gender> gender = - GetUserGender(*pref_service_); + GetUserGender(demographics); if (!gender.has_value()) return base::nullopt; - // Set birth year and gender in demographics. + // Get the offset and do one last check that demographics are allowed. + int offset = GetBirthYearOffset(pref_service_); + if (!CanProvideDemographics(now, *birth_year, offset)) + return base::nullopt; + + // Set gender and offset birth year in demographics. UserDemographics user_demographics; - user_demographics.birth_year = *birth_year; user_demographics.gender = *gender; + user_demographics.birth_year = *birth_year + offset; return user_demographics; } @@ -701,4 +715,9 @@ // profile. } +void ClearObsoleteMemoryPressurePrefs(PrefService* pref_service) { + pref_service->ClearPref(kSyncMemoryPressureWarningCount); + pref_service->ClearPref(kSyncShutdownCleanly); +} + } // namespace syncer
diff --git a/components/sync/base/sync_prefs.h b/components/sync/base/sync_prefs.h index a22f91f..20ba54d 100644 --- a/components/sync/base/sync_prefs.h +++ b/components/sync/base/sync_prefs.h
@@ -158,16 +158,6 @@ // For testing. void SetManagedForTest(bool is_managed); - // Get/Set number of memory warnings received. - int GetMemoryPressureWarningCount() const; - void SetMemoryPressureWarningCount(int value); - - // Check if the previous shutdown was clean. - bool DidSyncShutdownCleanly() const; - - // Set whether the last shutdown was clean. - void SetCleanShutdown(bool value); - // Get/set for the last known sync invalidation versions. void GetInvalidationVersions( std::map<ModelType, int64_t>* invalidation_versions) const; @@ -226,6 +216,7 @@ void ClearObsoleteSyncSpareBootstrapToken(PrefService* pref_service); #endif // defined(OS_CHROMEOS) void MigrateSyncSuppressedPref(PrefService* pref_service); +void ClearObsoleteMemoryPressurePrefs(PrefService* pref_service); } // namespace syncer
diff --git a/components/sync/base/sync_prefs_unittest.cc b/components/sync/base/sync_prefs_unittest.cc index fa5f78c3..427be733 100644 --- a/components/sync/base/sync_prefs_unittest.cc +++ b/components/sync/base/sync_prefs_unittest.cc
@@ -39,6 +39,15 @@ sync_prefs_ = std::make_unique<SyncPrefs>(&pref_service_); } + void SetDemographics(int birth_year, + metrics::UserDemographicsProto::Gender gender) { + base::DictionaryValue dict; + dict.SetIntPath(prefs::kSyncDemographics_BirthYearPath, birth_year); + dict.SetIntPath(prefs::kSyncDemographics_GenderPath, + static_cast<int>(gender)); + pref_service_.Set(prefs::kSyncDemographics, dict); + } + base::test::ScopedTaskEnvironment task_environment_; sync_preferences::TestingPrefServiceSyncable pref_service_; std::unique_ptr<SyncPrefs> sync_prefs_; @@ -151,10 +160,7 @@ metrics::UserDemographicsProto::GENDER_MALE; // Set user demographic prefs. - pref_service_.SetInteger(prefs::kSyncDemographicsBirthYear, - user_demographics_birth_year); - pref_service_.SetInteger(prefs::kSyncDemographicsGender, - static_cast<int>(user_demographics_gender)); + SetDemographics(user_demographics_birth_year, user_demographics_gender); int provided_birth_year; { @@ -172,8 +178,8 @@ // Verify that the offset is cached and that the randomized birth year is the // same when doing more that one read of the birth year. { - ASSERT_TRUE(pref_service_.HasPrefPath( - prefs::kSyncDemographicsBirthYearNoiseOffset)); + ASSERT_TRUE( + pref_service_.HasPrefPath(prefs::kSyncDemographicsBirthYearOffset)); base::Optional<UserDemographics> demographics = sync_prefs_->GetUserDemographics(GetNowTime()); ASSERT_TRUE(demographics.has_value()); @@ -188,12 +194,10 @@ // Set demographic prefs directly from the pref service interface because // demographic prefs will only be set on the server-side. The SyncPrefs // interface cannot set demographic prefs. - pref_service_.SetInteger(prefs::kSyncDemographicsBirthYear, 1983); - pref_service_.SetInteger( - prefs::kSyncDemographicsGender, - static_cast<int>(metrics::UserDemographicsProto::GENDER_FEMALE)); + SetDemographics(1983, metrics::UserDemographicsProto::GENDER_FEMALE); + // Set birth year noise offset to not have it randomized. - pref_service_.SetInteger(prefs::kSyncDemographicsBirthYearNoiseOffset, 2); + pref_service_.SetInteger(prefs::kSyncDemographicsBirthYearOffset, 2); // Verify that demographics are provided. { @@ -204,12 +208,15 @@ sync_prefs_->ClearPreferences(); - // Verify that demographics are not provided and all their prefs are cleared. + // Verify that demographics are not provided and kSyncDemographics is cleared. + // Note that we retain kSyncDemographicsBirthYearOffset. If the user resumes + // syncing, causing these prefs to be recreated, we don't want them to start + // reporting a different randomized birth year as this could narrow down or + // even reveal their true birth year. EXPECT_FALSE(sync_prefs_->GetUserDemographics(GetNowTime()).has_value()); - EXPECT_FALSE(pref_service_.HasPrefPath(prefs::kSyncDemographicsBirthYear)); - EXPECT_FALSE( - pref_service_.HasPrefPath(prefs::kSyncDemographicsBirthYearNoiseOffset)); - EXPECT_FALSE(pref_service_.HasPrefPath(prefs::kSyncDemographicsGender)); + EXPECT_FALSE(pref_service_.HasPrefPath(prefs::kSyncDemographics)); + EXPECT_TRUE( + pref_service_.HasPrefPath(prefs::kSyncDemographicsBirthYearOffset)); } TEST_F(SyncPrefsTest, Basic) { @@ -485,29 +492,19 @@ bool should_return_demographics = false; }; -// Test fixture for parameterized tests on demographics. +// Extend SyncPrefsTest fixture for parameterized tests on demographics. class SyncPrefsDemographicsTest - : public testing::TestWithParam<DemographicsTestParam> { - protected: - SyncPrefsDemographicsTest() { - SyncPrefs::RegisterProfilePrefs(pref_service_.registry()); - sync_prefs_ = std::make_unique<SyncPrefs>(&pref_service_); - } - - base::test::ScopedTaskEnvironment task_environment_; - sync_preferences::TestingPrefServiceSyncable pref_service_; - std::unique_ptr<SyncPrefs> sync_prefs_; -}; + : public SyncPrefsTest, + public testing::WithParamInterface<DemographicsTestParam> {}; TEST_P(SyncPrefsDemographicsTest, ReadDemographics_OffsetIsNotRandom) { DemographicsTestParam param = GetParam(); // Set user demographic prefs. - pref_service_.SetInteger(prefs::kSyncDemographicsBirthYear, param.birth_year); - pref_service_.SetInteger(prefs::kSyncDemographicsGender, - static_cast<int>(param.gender)); + SetDemographics(param.birth_year, param.gender); + // Set birth year noise offset to not have it randomized. - pref_service_.SetInteger(prefs::kSyncDemographicsBirthYearNoiseOffset, + pref_service_.SetInteger(prefs::kSyncDemographicsBirthYearOffset, param.birth_year_offset); // Verify provided demographics for the different parameterized test cases. @@ -545,6 +542,13 @@ /*birth_year_offset=*/-2, /*gender=*/metrics::UserDemographicsProto::GENDER_FEMALE, /*should_return_demographics=*/false}, + // Test where birth year should not be provided because age of user is + // |kUserDemographicsMaxAge| + 1, which is over the max age. + DemographicsTestParam{ + /*birth_year=*/1933, + /*birth_year_offset=*/0, + /*gender=*/metrics::UserDemographicsProto::GENDER_FEMALE, + /*should_return_demographics=*/false}, // Test where gender should not be provided because it has a low // population that can have their privacy compromised because of high // entropy.
diff --git a/components/sync/base/user_demographics.h b/components/sync/base/user_demographics.h index f87a0a72..73ef0b7e 100644 --- a/components/sync/base/user_demographics.h +++ b/components/sync/base/user_demographics.h
@@ -33,6 +33,9 @@ // Minimal user age in years to provide demographics for. constexpr int kUserDemographicsMinAgeInYears = 20; +// Max user age to provide demopgrahics for. +constexpr int kUserDemographicsMaxAgeInYears = 85; + // Container of user demographics. struct UserDemographics { int birth_year = 0;
diff --git a/components/sync/driver/glue/sync_engine_impl_unittest.cc b/components/sync/driver/glue/sync_engine_impl_unittest.cc index 964d8e1..302d8a7 100644 --- a/components/sync/driver/glue/sync_engine_impl_unittest.cc +++ b/components/sync/driver/glue/sync_engine_impl_unittest.cc
@@ -732,66 +732,6 @@ fake_manager_->GetTypesWithEmptyProgressMarkerToken(error_types).Empty()); } -// Ensure that redundant invalidations are ignored and that the most recent -// set of invalidation version is persisted across restarts. -TEST_F(SyncEngineImplTest, IgnoreOldInvalidations) { - // Set up some old persisted invalidations. - std::map<ModelType, int64_t> invalidation_versions; - invalidation_versions[BOOKMARKS] = 20; - sync_prefs_->UpdateInvalidationVersions(invalidation_versions); - InitializeBackend(true); - EXPECT_EQ(0, fake_manager_->GetInvalidationCount()); - - // Receiving an invalidation with an old version should do nothing. - ObjectIdInvalidationMap invalidation_map; - std::string notification_type; - RealModelTypeToNotificationType(BOOKMARKS, ¬ification_type); - invalidation_map.Insert(Invalidation::Init( - invalidation::ObjectId(0, notification_type), 10, "payload")); - backend_->OnIncomingInvalidation(invalidation_map); - fake_manager_->WaitForSyncThread(); - EXPECT_EQ(0, fake_manager_->GetInvalidationCount()); - - // Invalidations with new versions should be acted upon. - invalidation_map.Insert(Invalidation::Init( - invalidation::ObjectId(0, notification_type), 30, "payload")); - backend_->OnIncomingInvalidation(invalidation_map); - fake_manager_->WaitForSyncThread(); - EXPECT_EQ(1, fake_manager_->GetInvalidationCount()); - - // Invalidation for new data types should be acted on. - RealModelTypeToNotificationType(SESSIONS, ¬ification_type); - invalidation_map.Insert(Invalidation::Init( - invalidation::ObjectId(0, notification_type), 10, "payload")); - backend_->OnIncomingInvalidation(invalidation_map); - fake_manager_->WaitForSyncThread(); - EXPECT_EQ(2, fake_manager_->GetInvalidationCount()); - - // But redelivering that same invalidation should be ignored. - backend_->OnIncomingInvalidation(invalidation_map); - fake_manager_->WaitForSyncThread(); - EXPECT_EQ(2, fake_manager_->GetInvalidationCount()); - - // If an invalidation with an unknown version is received, it should be - // acted on, but should not affect the persisted versions. - invalidation_map.Insert(Invalidation::InitUnknownVersion( - invalidation::ObjectId(0, notification_type))); - backend_->OnIncomingInvalidation(invalidation_map); - fake_manager_->WaitForSyncThread(); - EXPECT_EQ(3, fake_manager_->GetInvalidationCount()); - - // Verify that the invalidation versions were updated in the prefs. - invalidation_versions[BOOKMARKS] = 30; - invalidation_versions[SESSIONS] = 10; - std::map<ModelType, int64_t> persisted_invalidation_versions; - sync_prefs_->GetInvalidationVersions(&persisted_invalidation_versions); - EXPECT_EQ(invalidation_versions.size(), - persisted_invalidation_versions.size()); - for (auto iter : persisted_invalidation_versions) { - EXPECT_EQ(invalidation_versions[iter.first], iter.second); - } -} - // Tests that SyncEngineImpl retains ModelTypeConnector after call to // StopSyncingForShutdown. This is needed for datatype deactivation during // DataTypeManager shutdown.
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc index 5b6581c..2484f3f 100644 --- a/components/sync/driver/profile_sync_service.cc +++ b/components/sync/driver/profile_sync_service.cc
@@ -195,10 +195,6 @@ if (identity_manager_) identity_manager_->AddObserver(this); - - memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>( - base::BindRepeating(&ProfileSyncService::OnMemoryPressure, - sync_enabled_weak_factory_.GetWeakPtr())); } ProfileSyncService::~ProfileSyncService() { @@ -510,8 +506,6 @@ } engine_->Initialize(std::move(params)); - - ReportPreviousSessionMemoryWarningCount(); } void ProfileSyncService::Shutdown() { @@ -598,9 +592,6 @@ } NotifyObservers(); - - // Mark this as a clean shutdown(without crash). - sync_prefs_.SetCleanShutdown(true); } void ProfileSyncService::StopImpl(SyncStopDataFate data_fate) { @@ -1833,34 +1824,6 @@ } } -void ProfileSyncService::OnMemoryPressure( - base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { - if (memory_pressure_level == - base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) { - sync_prefs_.SetMemoryPressureWarningCount( - sync_prefs_.GetMemoryPressureWarningCount() + 1); - } -} - -void ProfileSyncService::ReportPreviousSessionMemoryWarningCount() { - int warning_received = sync_prefs_.GetMemoryPressureWarningCount(); - - if (-1 != warning_received) { - // -1 means it is new client. - if (!sync_prefs_.DidSyncShutdownCleanly()) { - UMA_HISTOGRAM_COUNTS_1M("Sync.MemoryPressureWarningBeforeUncleanShutdown", - warning_received); - } else { - UMA_HISTOGRAM_COUNTS_1M("Sync.MemoryPressureWarningBeforeCleanShutdown", - warning_received); - } - } - sync_prefs_.SetMemoryPressureWarningCount(0); - // Will set to true during a clean shutdown, so crash or something else will - // remain this as false. - sync_prefs_.SetCleanShutdown(false); -} - void ProfileSyncService::RecordMemoryUsageHistograms() { ModelTypeSet active_types = GetActiveDataTypes(); for (ModelType type : active_types) {
diff --git a/components/sync/driver/profile_sync_service.h b/components/sync/driver/profile_sync_service.h index 43f9f1d48..7491b7a0 100644 --- a/components/sync/driver/profile_sync_service.h +++ b/components/sync/driver/profile_sync_service.h
@@ -12,7 +12,6 @@ #include "base/location.h" #include "base/macros.h" -#include "base/memory/memory_pressure_listener.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" @@ -344,10 +343,6 @@ // Tell the sync server that this client has disabled sync. void RemoveClientFromServer() const; - // Called when the system is under memory pressure. - void OnMemoryPressure( - base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level); - // Check if previous shutdown is shutdown cleanly. void ReportPreviousSessionMemoryWarningCount(); @@ -481,9 +476,6 @@ std::unique_ptr<SyncStoppedReporter> sync_stopped_reporter_; - // Listens for the system being under memory pressure. - std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_; - // Whether the major version has changed since the last time Chrome ran, // and therefore a passphrase required state should result in prompting // the user. This logic is only enabled on platforms that consume the
diff --git a/components/sync/driver/profile_sync_service_unittest.cc b/components/sync/driver/profile_sync_service_unittest.cc index 852fae37..6536737 100644 --- a/components/sync/driver/profile_sync_service_unittest.cc +++ b/components/sync/driver/profile_sync_service_unittest.cc
@@ -291,6 +291,31 @@ return profile_sync_service_bundle_.component_factory(); } + void SetDemographics(int birth_year, + metrics::UserDemographicsProto_Gender gender) { + base::DictionaryValue dict; + dict.SetIntPath(prefs::kSyncDemographics_BirthYearPath, birth_year); + dict.SetIntPath(prefs::kSyncDemographics_GenderPath, + static_cast<int>(gender)); + prefs()->Set(prefs::kSyncDemographics, dict); + } + + static bool HasBirthYearDemographic(const PrefService* pref_service) { + return pref_service->HasPrefPath(prefs::kSyncDemographics) && + pref_service->GetDictionary(prefs::kSyncDemographics) + ->FindIntPath(prefs::kSyncDemographics_BirthYearPath); + } + + static bool HasGenderDemographic(const PrefService* pref_service) { + return pref_service->HasPrefPath(prefs::kSyncDemographics) && + pref_service->GetDictionary(prefs::kSyncDemographics) + ->FindIntPath(prefs::kSyncDemographics_GenderPath); + } + + static bool HasBirthYearOffset(const PrefService* pref_service) { + return pref_service->HasPrefPath(prefs::kSyncDemographicsBirthYearOffset); + } + private: base::test::ScopedTaskEnvironment scoped_task_environment_; ProfileSyncServiceBundle profile_sync_service_bundle_; @@ -834,19 +859,19 @@ base::Time last_synced_time = service()->GetLastSyncedTimeForDebugging(); ASSERT_LT(base::Time::Now() - last_synced_time, base::TimeDelta::FromMinutes(1)); + // Set demographic prefs that are normally fetched from server when syncing. - prefs()->SetInteger(prefs::kSyncDemographicsBirthYear, - kOldEnoughForDemographicsUserBirthYear); - prefs()->SetInteger( - prefs::kSyncDemographicsGender, - static_cast<int>(metrics::UserDemographicsProto_Gender_GENDER_FEMALE)); + SetDemographics(kOldEnoughForDemographicsUserBirthYear, + metrics::UserDemographicsProto_Gender_GENDER_FEMALE); + // Set the birth year offset pref that would be normally set when calling // SyncPrefs::GetUserDemographics. - prefs()->SetInteger(prefs::kSyncDemographicsBirthYearNoiseOffset, 2); - ASSERT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYear)); - ASSERT_TRUE( - prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYearNoiseOffset)); - ASSERT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsGender)); + prefs()->SetInteger(prefs::kSyncDemographicsBirthYearOffset, 2); + + // Verify that the demographics prefs exist (i.e., that the test is set up). + ASSERT_TRUE(HasBirthYearDemographic(prefs())); + ASSERT_TRUE(HasGenderDemographic(prefs())); + ASSERT_TRUE(HasBirthYearOffset(prefs())); // Sign out. service()->StopAndClear(); @@ -860,10 +885,14 @@ EXPECT_NE(service()->GetLastSyncedTimeForDebugging(), last_synced_time); // Check that the demographic prefs are cleared. - EXPECT_FALSE(prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYear)); - EXPECT_FALSE( - prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYearNoiseOffset)); - EXPECT_FALSE(prefs()->HasPrefPath(prefs::kSyncDemographicsGender)); + EXPECT_FALSE(prefs()->HasPrefPath(prefs::kSyncDemographics)); + EXPECT_FALSE(HasBirthYearDemographic(prefs())); + EXPECT_FALSE(HasGenderDemographic(prefs())); + + // Verify that the random offset is preserved. If the user signs in again, + // we don't want them to start reporting a different randomized birth year + // as this could narrow down or ever reveal their true birth year. + EXPECT_TRUE(HasBirthYearOffset(prefs())); } // Verify that demographic prefs are cleared when the service is initializing @@ -872,18 +901,17 @@ // Set demographic prefs that are leftovers from previous sync. We can imagine // that due to some crash, sync service did not clear demographics when // account was signed out. - prefs()->SetInteger(prefs::kSyncDemographicsBirthYear, - kOldEnoughForDemographicsUserBirthYear); - prefs()->SetInteger( - prefs::kSyncDemographicsGender, - static_cast<int>(metrics::UserDemographicsProto_Gender_GENDER_FEMALE)); + SetDemographics(kOldEnoughForDemographicsUserBirthYear, + metrics::UserDemographicsProto_Gender_GENDER_FEMALE); + // Set the birth year offset pref that would be normally set when calling // SyncPrefs::GetUserDemographics. - prefs()->SetInteger(prefs::kSyncDemographicsBirthYearNoiseOffset, 2); - ASSERT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYear)); - ASSERT_TRUE( - prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYearNoiseOffset)); - ASSERT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsGender)); + prefs()->SetInteger(prefs::kSyncDemographicsBirthYearOffset, 2); + + // Verify that the demographics prefs exist (i.e., that the test is set up). + ASSERT_TRUE(HasBirthYearDemographic(prefs())); + ASSERT_TRUE(HasGenderDemographic(prefs())); + ASSERT_TRUE(HasBirthYearOffset(prefs())); // Don't sign-in before creating the service. CreateService(ProfileSyncService::AUTO_START); @@ -891,10 +919,14 @@ InitializeForNthSync(); // Verify that the demographic prefs are cleared. - EXPECT_FALSE(prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYear)); - EXPECT_FALSE( - prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYearNoiseOffset)); - EXPECT_FALSE(prefs()->HasPrefPath(prefs::kSyncDemographicsGender)); + EXPECT_FALSE(prefs()->HasPrefPath(prefs::kSyncDemographics)); + EXPECT_FALSE(HasBirthYearDemographic(prefs())); + EXPECT_FALSE(HasGenderDemographic(prefs())); + + // Verify that the random offset is preserved. If the user signs in again, + // we don't want them to start reporting a different randomized birth year + // as this could narrow down or ever reveal their true birth year. + EXPECT_TRUE(HasBirthYearOffset(prefs())); } TEST_F(ProfileSyncServiceTest, CancelSyncAfterSignOut) { @@ -1063,43 +1095,6 @@ EXPECT_TRUE(switches::IsSyncAllowedByFlag()); } -// Test Sync will stop after receive memory pressure -TEST_F(ProfileSyncServiceTest, MemoryPressureRecording) { - CreateService(ProfileSyncService::AUTO_START); - SignIn(); - InitializeForNthSync(); - - ASSERT_TRUE(prefs()->GetBoolean(prefs::kSyncRequested)); - ASSERT_EQ(SyncService::TransportState::ACTIVE, - service()->GetTransportState()); - - testing::Mock::VerifyAndClearExpectations(component_factory()); - - SyncPrefs sync_prefs(prefs()); - - ASSERT_EQ(prefs()->GetInteger(prefs::kSyncMemoryPressureWarningCount), 0); - ASSERT_FALSE(sync_prefs.DidSyncShutdownCleanly()); - - // Simulate memory pressure notification. - base::MemoryPressureListener::NotifyMemoryPressure( - base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); - base::RunLoop().RunUntilIdle(); - - // Verify memory pressure recorded. - EXPECT_EQ(prefs()->GetInteger(prefs::kSyncMemoryPressureWarningCount), 1); - EXPECT_FALSE(sync_prefs.DidSyncShutdownCleanly()); - - // Simulate memory pressure notification. - base::MemoryPressureListener::NotifyMemoryPressure( - base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); - base::RunLoop().RunUntilIdle(); - ShutdownAndDeleteService(); - - // Verify memory pressure and shutdown recorded. - EXPECT_EQ(prefs()->GetInteger(prefs::kSyncMemoryPressureWarningCount), 2); - EXPECT_TRUE(sync_prefs.DidSyncShutdownCleanly()); -} - // Test that the passphrase prompt due to version change logic gets triggered // on a datatype type requesting startup, but only happens once. TEST_F(ProfileSyncServiceTest, PassphrasePromptDueToVersion) { @@ -1286,13 +1281,11 @@ metrics::UserDemographicsProto_Gender_GENDER_FEMALE; // Set demographic prefs that are normally fetched from server when syncing. - prefs()->SetInteger(prefs::kSyncDemographicsBirthYear, - user_demographics_birth_year); - prefs()->SetInteger(prefs::kSyncDemographicsGender, - static_cast<int>(user_demographics_gender)); + SetDemographics(user_demographics_birth_year, user_demographics_gender); + // Directly set birth year offset in demographic prefs to avoid it being set // with a random value when calling GetUserDemographics(). - prefs()->SetInteger(prefs::kSyncDemographicsBirthYearNoiseOffset, + prefs()->SetInteger(prefs::kSyncDemographicsBirthYearOffset, birth_year_offset); base::Optional<UserDemographics> user_demographics = @@ -1316,15 +1309,15 @@ // disabled. We keep the demographic prefs available in this test to make // sure that they are not provided when sync is disabled (we want // base::nullopt in any case). - prefs()->SetInteger(prefs::kSyncDemographicsBirthYear, - kOldEnoughForDemographicsUserBirthYear); - prefs()->SetInteger( - prefs::kSyncDemographicsGender, - static_cast<int>(metrics::UserDemographicsProto_Gender_GENDER_FEMALE)); - ASSERT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYear)); - ASSERT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsGender)); + SetDemographics(kOldEnoughForDemographicsUserBirthYear, + metrics::UserDemographicsProto_Gender_GENDER_FEMALE); - ASSERT_FALSE(service()->GetUserDemographics(GetNowTime()).has_value()); + // Verify that demographic prefs exist (i.e., the test is set up). + ASSERT_TRUE(HasBirthYearDemographic(prefs())); + ASSERT_TRUE(HasGenderDemographic(prefs())); + + // Verify that we don't get demographics when sync is off. + EXPECT_FALSE(service()->GetUserDemographics(GetNowTime()).has_value()); } // Test whether sync service does not provide user demographics and does not @@ -1344,18 +1337,17 @@ metrics::UserDemographicsProto_Gender_GENDER_FEMALE; // Set demographic prefs that are normally fetched from server when syncing. - prefs()->SetInteger(prefs::kSyncDemographicsBirthYear, - user_demographics_birth_year); - prefs()->SetInteger(prefs::kSyncDemographicsGender, - static_cast<int>(user_demographics_gender)); + SetDemographics(user_demographics_birth_year, user_demographics_gender); + // Set birth year noise offset that is usually set when calling // SyncPrefs::GetUserDemographics. - prefs()->SetInteger(prefs::kSyncDemographicsBirthYearNoiseOffset, + prefs()->SetInteger(prefs::kSyncDemographicsBirthYearOffset, static_cast<int>(birth_year_offset)); - ASSERT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYear)); - ASSERT_TRUE( - prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYearNoiseOffset)); - ASSERT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsGender)); + + // Verify that demographic prefs exist (i.e., the test is set up). + ASSERT_TRUE(HasBirthYearDemographic(prefs())); + ASSERT_TRUE(HasGenderDemographic(prefs())); + ASSERT_TRUE(HasBirthYearOffset(prefs())); // Temporarily disable sync without turning it off. service()->GetUserSettings()->SetSyncRequested(false); @@ -1370,10 +1362,9 @@ EXPECT_FALSE(user_demographics.has_value()); // Verify that demographic prefs are not cleared. - EXPECT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYear)); - EXPECT_TRUE( - prefs()->HasPrefPath(prefs::kSyncDemographicsBirthYearNoiseOffset)); - EXPECT_TRUE(prefs()->HasPrefPath(prefs::kSyncDemographicsGender)); + EXPECT_TRUE(HasBirthYearDemographic(prefs())); + EXPECT_TRUE(HasGenderDemographic(prefs())); + EXPECT_TRUE(HasBirthYearOffset(prefs())); } } // namespace
diff --git a/components/sync/driver/resources/chrome_sync.js b/components/sync/driver/resources/chrome_sync.js index ffc727d8..4ad2a35 100644 --- a/components/sync/driver/resources/chrome_sync.js +++ b/components/sync/driver/resources/chrome_sync.js
@@ -12,85 +12,82 @@ * A simple timer to measure elapsed time. * @constructor */ - function Timer() { + class Timer { + constructor() { + /** + * The time that this Timer was created. + * @type {number} + * @private + * @const + */ + this.start_ = Date.now(); + } + /** - * The time that this Timer was created. - * @type {number} - * @private - * @const + * @return {number} The elapsed seconds since this Timer was created. */ - this.start_ = Date.now(); + getElapsedSeconds() { + return (Date.now() - this.start_) / 1000; + } } /** - * @return {number} The elapsed seconds since this Timer was created. - */ - Timer.prototype.getElapsedSeconds = function() { - return (Date.now() - this.start_) / 1000; - }; - - /** @return {!Timer} An object which measures elapsed time. */ - const makeTimer = function() { - return new Timer; - }; - - /** * @param {string} name The name of the event type. * @param {!Object} details A collection of event-specific details. */ - const dispatchEvent = function(name, details) { + function dispatchEvent(name, details) { const e = new Event(name); e.details = details; chrome.sync.events.dispatchEvent(e); - }; + } /** * Registers to receive a stream of events through * chrome.sync.dispatchEvent(). */ - const registerForEvents = function() { + function registerForEvents() { chrome.send('registerForEvents'); - }; + } /** * Registers to receive a stream of status counter update events * chrome.sync.dispatchEvent(). */ - const registerForPerTypeCounters = function() { + function registerForPerTypeCounters() { chrome.send('registerForPerTypeCounters'); - }; + } /** * Asks the browser to refresh our snapshot of sync state. Should result * in an onAboutInfoUpdated event being emitted. */ - const requestUpdatedAboutInfo = function() { + function requestUpdatedAboutInfo() { chrome.send('requestUpdatedAboutInfo'); - }; + } /** * Asks the browser to send us the list of registered types. Should result * in an onReceivedListOfTypes event being emitted. */ - const requestListOfTypes = function() { + function requestListOfTypes() { chrome.send('requestListOfTypes'); - }; + } /** * Asks the browser to send us the initial state of the "include specifics" * flag. Should result in an onReceivedIncludeSpecificsInitialState event * being emitted. */ - const requestIncludeSpecificsInitialState = function() { + function requestIncludeSpecificsInitialState() { chrome.send('requestIncludeSpecificsInitialState'); - }; + } /** * Asks the browser if we should show the User Events tab or not. */ - const requestUserEventsVisibility = function() { + function requestUserEventsVisibility() { chrome.send('requestUserEventsVisibility'); - }; + } /** * Updates the logic sending events to the protocol logic if they should @@ -99,9 +96,9 @@ * @param {boolean} includeSpecifics Whether protocol events include * specifics. */ - const setIncludeSpecifics = function(includeSpecifics) { + function setIncludeSpecifics(includeSpecifics) { chrome.send('setIncludeSpecifics', [includeSpecifics]); - }; + } /** * Sends data to construct a user event that should be committed. @@ -109,37 +106,37 @@ * @param {string} eventTimeUsec Timestamp for the new event. * @param {string} navigationId Timestamp of linked sessions navigation. */ - const writeUserEvent = function(eventTimeUsec, navigationId) { + function writeUserEvent(eventTimeUsec, navigationId) { chrome.send('writeUserEvent', [eventTimeUsec, navigationId]); - }; + } /** * Triggers a RequestStart call on the SyncService. */ - const requestStart = function() { + function requestStart() { chrome.send('requestStart'); - }; + } /** * Triggers a RequestStop(KEEP_DATA) call on the SyncService. */ - const requestStopKeepData = function() { + function requestStopKeepData() { chrome.send('requestStopKeepData'); - }; + } /** * Triggers a RequestStop(CLEAR_DATA) call on the SyncService. */ - const requestStopClearData = function() { + function requestStopClearData() { chrome.send('requestStopClearData'); - }; + } /** * Triggers a GetUpdates call for all enabled datatypes. */ - const triggerRefresh = function() { + function triggerRefresh() { chrome.send('triggerRefresh'); - }; + } /** * Counter to uniquely identify requests while they're in progress. @@ -160,11 +157,11 @@ * * @param {function(!Object)} callback The function to call with the response. */ - const getAllNodes = function(callback) { + function getAllNodes(callback) { requestId++; requestCallbacks[requestId] = callback; chrome.send('getAllNodes', [requestId]); - }; + } /** * Called from C++ with the response to a getAllNodes request. @@ -172,13 +169,13 @@ * @param {number} id The requestId passed in with the request. * @param {Object} response The response to the request. */ - const getAllNodesCallback = function(id, response) { + function getAllNodesCallback(id, response) { requestCallbacks[id](response); delete requestCallbacks[id]; - }; + } return { - makeTimer: makeTimer, + Timer: Timer, dispatchEvent: dispatchEvent, // TODO(crbug.com/854268,crbug.com/976249): Use new cr.EventTarget() when // the native EventTarget constructor is implemented on iOS (not the case as
diff --git a/components/sync/driver/resources/sync_node_browser.js b/components/sync/driver/resources/sync_node_browser.js index d772d80..dc8e51e 100644 --- a/components/sync/driver/resources/sync_node_browser.js +++ b/components/sync/driver/resources/sync_node_browser.js
@@ -12,9 +12,9 @@ * * @param {!Object} node The node to check. */ - const isTypeRootNode = function(node) { + function isTypeRootNode(node) { return node.PARENT_ID == 'r' && node.UNIQUE_SERVER_TAG != ''; - }; + } /** * A helper function to determine if a node is a child of the given parent. @@ -22,13 +22,13 @@ * @param {!Object} parent node. * @param {!Object} node The node to check. */ - const isChildOf = function(parentNode, node) { + function isChildOf(parentNode, node) { if (node.PARENT_ID != '') { return node.PARENT_ID == parentNode.ID; } else { return node.modelType == parentNode.modelType; } - }; + } /** * A helper function to sort sync nodes. @@ -39,7 +39,7 @@ * If this proves to be slow and expensive, we should experiment with moving * this functionality to C++ instead. */ - const nodeComparator = function(nodeA, nodeB) { + function nodeComparator(nodeA, nodeB) { if (nodeA.hasOwnProperty('positionIndex') && nodeB.hasOwnProperty('positionIndex')) { return nodeA.positionIndex - nodeB.positionIndex; @@ -48,7 +48,7 @@ } else { return nodeA.METAHANDLE - nodeB.METAHANDLE; } - }; + } /** * Updates the node detail view with the details for the given node. @@ -76,7 +76,7 @@ * chrome.sync.getAllNodes(). * @extends {cr.ui.TreeItem} */ - const SyncNodeTreeItem = function(node) { + function SyncNodeTreeItem(node) { const treeItem = new cr.ui.TreeItem(); treeItem.__proto__ = SyncNodeTreeItem.prototype; @@ -93,7 +93,7 @@ treeItem.classList.add('leaf'); } return treeItem; - }; + } SyncNodeTreeItem.prototype = { __proto__: cr.ui.TreeItem.prototype,
diff --git a/components/sync/driver/resources/sync_search.js b/components/sync/driver/resources/sync_search.js index 3e04ca3..226e49c 100644 --- a/components/sync/driver/resources/sync_search.js +++ b/components/sync/driver/resources/sync_search.js
@@ -7,16 +7,16 @@ cr.define('chrome.sync', function() { let currSearchId = 0; - const setQueryString = function(queryControl, query) { + function setQueryString(queryControl, query) { queryControl.value = query; - }; + } - const createDoQueryFunction = function(queryControl, submitControl, query) { + function createDoQueryFunction(queryControl, submitControl, query) { return function() { setQueryString(queryControl, query); submitControl.click(); }; - }; + } /** * Decorates the quick search controls @@ -27,7 +27,7 @@ * @param {!HTMLInputElement} queryControl The <input> object of * type=search where user's query is typed. */ - const decorateQuickQueryControls = function( + function decorateQuickQueryControls( quickLinkArray, submitControl, queryControl) { for (let index = 0; index < quickLinkArray.length; ++index) { const quickQuery = quickLinkArray[index].getAttribute('data-query'); @@ -35,7 +35,7 @@ createDoQueryFunction(queryControl, submitControl, quickQuery); quickLinkArray[index].addEventListener('click', quickQueryFunction); } - }; + } /** * Runs a search with the given query. @@ -44,7 +44,7 @@ * @param {!Function} callback The callback called with the search results. * not called if doSearch() is called again while the search is running. */ - const doSearch = function(query, callback) { + function doSearch(query, callback) { const searchId = ++currSearchId; try { const regex = new RegExp(query); @@ -70,7 +70,7 @@ // be caught and handled here. callback([], err); } - }; + } /** * Decorates the various search controls. @@ -90,7 +90,7 @@ resultsControl, detailsControl) { const resultsDataModel = new cr.ui.ArrayDataModel([]); - const searchFunction = function() { + function searchFunction() { const query = queryControl.value; statusControl.textContent = ''; resultsDataModel.splice(0, resultsDataModel.length); @@ -99,7 +99,7 @@ } statusControl.textContent = 'Searching for ' + query + '...'; queryControl.removeAttribute('error'); - const timer = chrome.sync.makeTimer(); + const timer = new chrome.sync.Timer(); doSearch(query, function(nodes, error) { if (error) { statusControl.textContent = 'Error: ' + error; @@ -121,7 +121,7 @@ resultsControl.redraw(); } }); - }; + } submitControl.addEventListener('click', searchFunction); // Decorate search box.
diff --git a/components/sync/driver/resources/types.js b/components/sync/driver/resources/types.js index 94a359842..5bb6e55 100644 --- a/components/sync/driver/resources/types.js +++ b/components/sync/driver/resources/types.js
@@ -11,7 +11,7 @@ * * Makes use of typeCountersMap, which is defined in the containing scope. */ - const refreshTypeCountersDisplay = function() { + function refreshTypeCountersDisplay() { const typeCountersArray = []; // Transform our map into an array to make jstemplate happy. @@ -25,7 +25,7 @@ jstProcess( new JsEvalContext({ rows: typeCountersArray }), $('type-counters-table')); - }; + } /** * Helps to initialize the table by picking up where initTypeCounters() left @@ -34,7 +34,7 @@ * * @param {!Object} e An event containing the list of known sync types. */ - const onReceivedListOfTypes = function(e) { + function onReceivedListOfTypes(e) { const types = e.details.types; types.map(function(type) { if (!typeCountersMap.hasOwnProperty(type)) { @@ -45,14 +45,14 @@ 'onReceivedListOfTypes', onReceivedListOfTypes); refreshTypeCountersDisplay(); - }; + } /** * Callback for receipt of updated per-type counters. * * @param {!Object} e An event containing an updated counter. */ - const onCountersUpdated = function(e) { + function onCountersUpdated(e) { const details = e.details; const modelType = details.modelType; @@ -64,12 +64,12 @@ } } refreshTypeCountersDisplay(); - }; + } /** * Initializes state and callbacks for the per-type counters and status UI. */ - const initTypeCounters = function() { + function initTypeCounters() { chrome.sync.events.addEventListener( 'onCountersUpdated', onCountersUpdated); @@ -79,11 +79,11 @@ chrome.sync.requestListOfTypes(); chrome.sync.registerForPerTypeCounters(); - }; + } - const onLoad = function() { + function onLoad() { initTypeCounters(); - }; + } return { onLoad: onLoad
diff --git a/components/url_formatter/spoof_checks/idn_spoof_checker.cc b/components/url_formatter/spoof_checks/idn_spoof_checker.cc index a23e36b..aea26994ea 100644 --- a/components/url_formatter/spoof_checks/idn_spoof_checker.cc +++ b/components/url_formatter/spoof_checks/idn_spoof_checker.cc
@@ -305,7 +305,7 @@ reinterpret_cast<icu::RegexMatcher*>(DangerousPatternTLS().Get()); if (!dangerous_pattern) { // The parentheses in the below strings belong to the raw string sequence - // R("..."). They are NOT part of the regular expression. Each sub + // R"(...)". They are NOT part of the regular expression. Each sub // regex is OR'ed with the | operator. dangerous_pattern = new icu::RegexMatcher( icu::UnicodeString( @@ -362,6 +362,9 @@ // Disallow dotless i (U+0131) followed by a combining mark. R"(\u0131[\u0300-\u0339]|)" + // Disallow combining Kana voiced sound marks. + R"(\u3099|\u309A|)" + // Disallow U+0307 (dot above) after 'i', 'j', 'l' or dotless i // (U+0131). Dotless j (U+0237) is not in the allowed set to begin // with.
diff --git a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc index 7c9f7f3..cb7ba5cc 100644 --- a/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc +++ b/components/url_formatter/spoof_checks/idn_spoof_checker_unittest.cc
@@ -1059,6 +1059,10 @@ // This is allowed because the ideographs are not immediately next to // non-CJK. {"xn--oiqsace.com", L"丶乀乁丿.com", true}, + + // Kana voiced sound marks are not allowed. + {"xn--google-1m4e.com", L"google\x3099.com", false}, + {"xn--google-8m4e.com", L"google\x309A.com", false}, }; namespace test {
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_android.cc b/content/browser/accessibility/browser_accessibility_state_impl_android.cc index a97a68c..1a7c52bb 100644 --- a/content/browser/accessibility/browser_accessibility_state_impl_android.cc +++ b/content/browser/accessibility/browser_accessibility_state_impl_android.cc
@@ -5,6 +5,7 @@ #include "content/browser/accessibility/browser_accessibility_state_impl.h" #include "base/android/jni_android.h" +#include "base/metrics/histogram_macros.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/android/content_jni_headers/BrowserAccessibilityState_jni.h" #include "content/public/browser/browser_thread.h" @@ -33,6 +34,12 @@ JNIEnv* env = AttachCurrentThread(); Java_BrowserAccessibilityState_recordAccessibilityHistograms(env); + + // Screen reader metric. + ui::AXMode mode = + BrowserAccessibilityStateImpl::GetInstance()->GetAccessibilityMode(); + UMA_HISTOGRAM_BOOLEAN("Accessibility.Android.ScreenReader", + mode.has_mode(ui::AXMode::kScreenReader)); } // static
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_mac.mm b/content/browser/accessibility/browser_accessibility_state_impl_mac.mm index 8fee871..92601ed 100644 --- a/content/browser/accessibility/browser_accessibility_state_impl_mac.mm +++ b/content/browser/accessibility/browser_accessibility_state_impl_mac.mm
@@ -85,6 +85,12 @@ } void BrowserAccessibilityStateImpl:: - UpdatePlatformSpecificHistogramsOnOtherThread() {} + UpdatePlatformSpecificHistogramsOnOtherThread() { + // Screen reader metric. + ui::AXMode mode = + BrowserAccessibilityStateImpl::GetInstance()->GetAccessibilityMode(); + UMA_HISTOGRAM_BOOLEAN("Accessibility.Mac.ScreenReader", + mode.has_mode(ui::AXMode::kScreenReader)); +} } // namespace content
diff --git a/content/browser/accessibility/browser_accessibility_state_impl_win.cc b/content/browser/accessibility/browser_accessibility_state_impl_win.cc index c311f31..0fd8916 100644 --- a/content/browser/accessibility/browser_accessibility_state_impl_win.cc +++ b/content/browser/accessibility/browser_accessibility_state_impl_win.cc
@@ -105,10 +105,19 @@ UMA_HISTOGRAM_BOOLEAN("Accessibility.WinAudioDescription", !!audio_description.Enabled); + // This screen reader flag is nearly meaningless, it is set very often + // when there is no screen reader, and is not set for Narrator. BOOL win_screen_reader = FALSE; SystemParametersInfo(SPI_GETSCREENREADER, 0, &win_screen_reader, 0); UMA_HISTOGRAM_BOOLEAN("Accessibility.WinScreenReader", !!win_screen_reader); + // Better all-encompassing screen reader metric. + // See also specific screen reader metrics below, e.g. WinJAWS, WinNVDA. + ui::AXMode mode = + BrowserAccessibilityStateImpl::GetInstance()->GetAccessibilityMode(); + UMA_HISTOGRAM_BOOLEAN("Accessibility.WinScreenReader2", + mode.has_mode(ui::AXMode::kScreenReader)); + STICKYKEYS sticky_keys = {0}; sticky_keys.cbSize = sizeof(STICKYKEYS); SystemParametersInfo(SPI_GETSTICKYKEYS, 0, &sticky_keys, 0); @@ -153,7 +162,8 @@ nvda = true; if (base::LowerCaseEqualsASCII(module_name, "stsaw32.dll")) satogo = true; - if (base::LowerCaseEqualsASCII(module_name, "zslhook.dll")) + if (base::LowerCaseEqualsASCII(module_name, "zslhook.dll") || + base::LowerCaseEqualsASCII(module_name, "zslhook64.dll")) zoomtext = true; }
diff --git a/content/browser/appcache/appcache_host.cc b/content/browser/appcache/appcache_host.cc index fee97c9..4304b436 100644 --- a/content/browser/appcache/appcache_host.cc +++ b/content/browser/appcache/appcache_host.cc
@@ -633,7 +633,9 @@ AppCacheSubresourceURLFactory::CreateURLLoaderFactory(GetWeakPtr(), &factory_ptr); - frontend()->SetSubresourceFactory(std::move(factory_ptr)); + // We may not have bound |factory_ptr| if the storage partition has shut down. + if (factory_ptr) + frontend()->SetSubresourceFactory(std::move(factory_ptr)); } void AppCacheHost::SetAppCacheSubresourceFactory(
diff --git a/content/browser/appcache/appcache_quota_client.cc b/content/browser/appcache/appcache_quota_client.cc index 2742e29..f692c13 100644 --- a/content/browser/appcache/appcache_quota_client.cc +++ b/content/browser/appcache/appcache_quota_client.cc
@@ -11,12 +11,16 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/task/post_task.h" #include "content/browser/appcache/appcache_service_impl.h" +#include "content/browser/loader/navigation_url_loader_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "third_party/blink/public/mojom/quota/quota_types.mojom.h" using blink::mojom::StorageType; using storage::QuotaClient; +namespace content { namespace { blink::mojom::QuotaStatusCode NetErrorCodeToQuotaStatus(int code) { if (code == net::OK) @@ -32,14 +36,24 @@ queue->pop_front(); std::move(request).Run(); } + +void RunDeleteOnIO(const base::Location& from_here, + net::CompletionRepeatingCallback callback, + int result) { + if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { + std::move(callback).Run(result); + return; + } + + base::PostTaskWithTraits(from_here, {BrowserThread::IO}, + base::BindOnce(std::move(callback), result)); +} } // namespace -namespace content { - -AppCacheQuotaClient::AppCacheQuotaClient(AppCacheServiceImpl* service) - : service_(service), - appcache_is_ready_(false), - quota_manager_is_destroyed_(false) { +AppCacheQuotaClient::AppCacheQuotaClient( + base::WeakPtr<AppCacheServiceImpl> service) + : service_(std::move(service)) { + DETACH_FROM_SEQUENCE(sequence_checker_); } AppCacheQuotaClient::~AppCacheQuotaClient() { @@ -53,6 +67,7 @@ } void AppCacheQuotaClient::OnQuotaManagerDestroyed() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DeletePendingRequests(); if (!current_delete_request_callback_.is_null()) { current_delete_request_callback_.Reset(); @@ -60,17 +75,18 @@ } quota_manager_is_destroyed_ = true; - if (!service_) + if (service_is_destroyed_) delete this; } void AppCacheQuotaClient::GetOriginUsage(const url::Origin& origin, StorageType type, GetUsageCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); DCHECK(!quota_manager_is_destroyed_); - if (!service_) { + if (service_is_destroyed_) { std::move(callback).Run(0); return; } @@ -87,23 +103,37 @@ return; } - const std::map<url::Origin, int64_t>& map = GetUsageMap(); - auto it = map.find(origin); - if (it == map.end()) { - std::move(callback).Run(0); - return; - } - std::move(callback).Run(it->second); + base::PostTaskAndReplyWithResult( + FROM_HERE, + {NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()}, + base::BindOnce( + [](base::WeakPtr<AppCacheServiceImpl> service, + const url::Origin& origin) -> int64_t { + if (!service) + return 0; + + const std::map<url::Origin, int64_t>& map = + service->storage()->usage_map(); + auto it = map.find(origin); + if (it == map.end()) + return 0; + + return it->second; + }, + service_, origin), + std::move(callback)); } void AppCacheQuotaClient::GetOriginsForType(StorageType type, GetOriginsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); GetOriginsHelper(type, std::string(), std::move(callback)); } void AppCacheQuotaClient::GetOriginsForHost(StorageType type, const std::string& host, GetOriginsCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!callback.is_null()); if (host.empty()) { std::move(callback).Run(std::set<url::Origin>()); @@ -115,9 +145,10 @@ void AppCacheQuotaClient::DeleteOriginData(const url::Origin& origin, StorageType type, DeletionCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!quota_manager_is_destroyed_); - if (!service_) { + if (service_is_destroyed_) { std::move(callback).Run(blink::mojom::QuotaStatusCode::kErrorAbort); return; } @@ -135,16 +166,20 @@ return; } - service_->DeleteAppCachesForOrigin(origin, - GetServiceDeleteCallback()->callback()); + NavigationURLLoaderImpl::RunOrPostTaskOnLoaderThread( + FROM_HERE, + base::BindOnce(&AppCacheServiceImpl::DeleteAppCachesForOrigin, service_, + origin, + base::BindOnce(&RunDeleteOnIO, FROM_HERE, + GetServiceDeleteCallback()->callback()))); } bool AppCacheQuotaClient::DoesSupport(StorageType type) const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return type == StorageType::kTemporary; } void AppCacheQuotaClient::DidDeleteAppCachesForOrigin(int rv) { - DCHECK(service_); if (quota_manager_is_destroyed_) return; @@ -164,7 +199,7 @@ DCHECK(!callback.is_null()); DCHECK(!quota_manager_is_destroyed_); - if (!service_) { + if (service_is_destroyed_) { std::move(callback).Run(std::set<url::Origin>()); return; } @@ -181,12 +216,24 @@ return; } - std::set<url::Origin> origins; - for (const auto& pair : GetUsageMap()) { - if (opt_host.empty() || pair.first.host() == opt_host) - origins.insert(pair.first); - } - std::move(callback).Run(origins); + base::PostTaskAndReplyWithResult( + FROM_HERE, + {NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()}, + base::BindOnce( + [](base::WeakPtr<AppCacheServiceImpl> service, + const std::string& opt_host) { + std::set<url::Origin> origins; + if (!service) + return origins; + + for (const auto& pair : service->storage()->usage_map()) { + if (opt_host.empty() || pair.first.host() == opt_host) + origins.insert(pair.first); + } + return origins; + }, + service_, opt_host), + std::move(callback)); } void AppCacheQuotaClient::ProcessPendingRequests() { @@ -203,11 +250,6 @@ pending_serial_requests_.clear(); } -const std::map<url::Origin, int64_t>& AppCacheQuotaClient::GetUsageMap() const { - DCHECK(service_); - return service_->storage()->usage_map(); -} - net::CancelableCompletionRepeatingCallback* AppCacheQuotaClient::GetServiceDeleteCallback() { // Lazily created due to base::CancelableCallback's threading restrictions, @@ -223,6 +265,7 @@ } void AppCacheQuotaClient::NotifyAppCacheReady() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Can reoccur during reinitialization. if (!appcache_is_ready_) { appcache_is_ready_ = true; @@ -231,7 +274,9 @@ } void AppCacheQuotaClient::NotifyAppCacheDestroyed() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); service_ = nullptr; + service_is_destroyed_ = true; while (!pending_batch_requests_.empty()) RunFront(&pending_batch_requests_);
diff --git a/content/browser/appcache/appcache_quota_client.h b/content/browser/appcache/appcache_quota_client.h index 39790d44..18580dd 100644 --- a/content/browser/appcache/appcache_quota_client.h +++ b/content/browser/appcache/appcache_quota_client.h
@@ -12,6 +12,7 @@ #include "base/containers/circular_deque.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/sequence_checker.h" #include "content/browser/appcache/appcache_storage.h" #include "content/common/content_export.h" #include "net/base/completion_repeating_callback.h" @@ -58,7 +59,7 @@ friend class AppCacheStorageImpl; // for NotifyAppCacheIsReady CONTENT_EXPORT - explicit AppCacheQuotaClient(AppCacheServiceImpl* service); + explicit AppCacheQuotaClient(base::WeakPtr<AppCacheServiceImpl> service); void DidDeleteAppCachesForOrigin(int rv); void GetOriginsHelper(blink::mojom::StorageType type, @@ -66,7 +67,6 @@ GetOriginsCallback callback); void ProcessPendingRequests(); void DeletePendingRequests(); - const std::map<url::Origin, int64_t>& GetUsageMap() const; net::CancelableCompletionRepeatingCallback* GetServiceDeleteCallback(); // For use by appcache internals during initialization and shutdown. @@ -84,9 +84,11 @@ std::unique_ptr<net::CancelableCompletionRepeatingCallback> service_delete_callback_; - AppCacheServiceImpl* service_; - bool appcache_is_ready_; - bool quota_manager_is_destroyed_; + base::WeakPtr<AppCacheServiceImpl> service_; + bool appcache_is_ready_ = false; + bool quota_manager_is_destroyed_ = false; + bool service_is_destroyed_ = false; + SEQUENCE_CHECKER(sequence_checker_); DISALLOW_COPY_AND_ASSIGN(AppCacheQuotaClient); };
diff --git a/content/browser/appcache/appcache_quota_client_unittest.cc b/content/browser/appcache/appcache_quota_client_unittest.cc index 79de6c660..67bae98 100644 --- a/content/browser/appcache/appcache_quota_client_unittest.cc +++ b/content/browser/appcache/appcache_quota_client_unittest.cc
@@ -9,9 +9,9 @@ #include "base/bind.h" #include "base/run_loop.h" -#include "base/test/scoped_task_environment.h" #include "content/browser/appcache/appcache_quota_client.h" #include "content/browser/appcache/mock_appcache_service.h" +#include "content/public/test/test_browser_thread_bundle.h" #include "net/base/net_errors.h" #include "testing/gtest/include/gtest/gtest.h" @@ -115,7 +115,7 @@ AppCacheQuotaClient* CreateClient() { // The bare operator new is used here because AppCacheQuotaClient deletes // itself when the QuotaManager goes out of scope. - return new AppCacheQuotaClient(&mock_service_); + return new AppCacheQuotaClient(mock_service_.AsWeakPtr()); } void Call_NotifyAppCacheReady(AppCacheQuotaClient* client) { @@ -146,7 +146,7 @@ delete_status_ = status; } - base::test::ScopedTaskEnvironment scoped_task_environment_; + TestBrowserThreadBundle thread_bundle_; int64_t usage_; std::set<url::Origin> origins_; blink::mojom::QuotaStatusCode delete_status_; @@ -319,11 +319,10 @@ // Pending requests should get serviced when the appcache is ready. Call_NotifyAppCacheReady(client); + base::RunLoop().RunUntilIdle(); EXPECT_EQ(2, num_get_origin_usage_completions_); EXPECT_EQ(4, num_get_origins_completions_); - EXPECT_EQ(0, num_delete_origins_completions_); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(3, num_delete_origins_completions_); // deletes are really async + EXPECT_EQ(3, num_delete_origins_completions_); // They should be serviced in order requested. EXPECT_EQ(10, usage_);
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc index 523cc245..4255f70 100644 --- a/content/browser/appcache/appcache_request_handler_unittest.cc +++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -36,6 +36,7 @@ #include "content/browser/appcache/mock_appcache_policy.h" #include "content/browser/appcache/mock_appcache_service.h" #include "content/public/browser/browser_task_traits.h" +#include "content/public/common/content_features.h" #include "content/public/test/test_browser_thread_bundle.h" #include "mojo/public/cpp/bindings/pending_remote.h" #include "net/base/net_errors.h" @@ -196,10 +197,14 @@ AppCacheRequestHandlerTest() : host_(nullptr), request_(nullptr), request_handler_type_(GetParam()) { AppCacheRequestHandler::SetRunningInTests(true); - if (request_handler_type_ == URLLOADER) - feature_list_.InitAndEnableFeature(network::features::kNetworkService); - else + if (request_handler_type_ == URLLOADER) { + // TODO(http://crbug.com/824840): Enable NavigationLoaderOnUI for these + // tests. + feature_list_.InitWithFeatures({network::features::kNetworkService}, + {features::kNavigationLoaderOnUI}); + } else { feature_list_.InitAndDisableFeature(network::features::kNetworkService); + } } ~AppCacheRequestHandlerTest() {
diff --git a/content/browser/appcache/appcache_service_impl.cc b/content/browser/appcache/appcache_service_impl.cc index 9f432ef..dcfc1a49 100644 --- a/content/browser/appcache/appcache_service_impl.cc +++ b/content/browser/appcache/appcache_service_impl.cc
@@ -29,6 +29,7 @@ #include "content/browser/appcache/appcache_response.h" #include "content/browser/appcache/appcache_storage_impl.h" #include "content/browser/loader/navigation_url_loader_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "net/base/io_buffer.h" #include "storage/browser/quota/special_storage_policy.h" #include "third_party/blink/public/mojom/appcache/appcache_info.mojom.h" @@ -387,7 +388,7 @@ // The operator new is used here because this AppCacheQuotaClient instance // deletes itself after both the QuotaManager and the AppCacheService are // destroyed. - quota_client_ = new AppCacheQuotaClient(this); + quota_client_ = new AppCacheQuotaClient(AsWeakPtr()); quota_manager_proxy_->RegisterClient(quota_client_); } } @@ -400,8 +401,16 @@ for (auto& helper : pending_helpers_) helper.first->Cancel(); pending_helpers_.clear(); - if (quota_client_) - quota_client_->NotifyAppCacheDestroyed(); + if (quota_client_) { + if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { + quota_client_->NotifyAppCacheDestroyed(); + } else { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&AppCacheQuotaClient::NotifyAppCacheDestroyed, + base::Unretained(quota_client_))); + } + } // Destroy storage_ first; ~AppCacheStorageImpl accesses other data members // (special_storage_policy_). @@ -409,6 +418,8 @@ } void AppCacheServiceImpl::Initialize(const base::FilePath& cache_directory) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); DCHECK(!storage_.get()); cache_directory_ = cache_directory; auto storage = std::make_unique<AppCacheStorageImpl>(this); @@ -417,6 +428,8 @@ } void AppCacheServiceImpl::ScheduleReinitialize() { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); if (reinit_timer_.IsRunning()) return; @@ -444,6 +457,8 @@ } void AppCacheServiceImpl::Reinitialize() { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); AppCacheHistograms::CountReinitAttempt(!last_reinit_time_.is_null()); last_reinit_time_ = base::Time::Now(); @@ -459,6 +474,8 @@ void AppCacheServiceImpl::GetAllAppCacheInfo(AppCacheInfoCollection* collection, OnceCompletionCallback callback) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); DCHECK(collection); GetInfoHelper* helper = new GetInfoHelper(this, collection, std::move(callback)); @@ -468,6 +485,8 @@ void AppCacheServiceImpl::DeleteAppCacheGroup( const GURL& manifest_url, net::CompletionOnceCallback callback) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); DeleteHelper* helper = new DeleteHelper(this, manifest_url, std::move(callback)); helper->Start(); @@ -476,6 +495,8 @@ void AppCacheServiceImpl::DeleteAppCachesForOrigin( const url::Origin& origin, net::CompletionOnceCallback callback) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); DeleteOriginHelper* helper = new DeleteOriginHelper(this, origin, std::move(callback)); helper->Start(); @@ -484,6 +505,8 @@ void AppCacheServiceImpl::CheckAppCacheResponse(const GURL& manifest_url, int64_t cache_id, int64_t response_id) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); CheckResponseHelper* helper = new CheckResponseHelper( this, manifest_url, cache_id, response_id); helper->Start(); @@ -491,27 +514,37 @@ void AppCacheServiceImpl::set_special_storage_policy( storage::SpecialStoragePolicy* policy) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); special_storage_policy_ = policy; } void AppCacheServiceImpl::RegisterBackend( AppCacheBackendImpl* backend_impl) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); DCHECK(backends_.find(backend_impl->process_id()) == backends_.end()); backends_.insert({backend_impl->process_id(), backend_impl}); } void AppCacheServiceImpl::UnregisterBackend( AppCacheBackendImpl* backend_impl) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); backends_.erase(backend_impl->process_id()); } AppCacheHost* AppCacheServiceImpl::GetHost( const base::UnguessableToken& host_id) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); auto it = hosts_.find(host_id); return (it != hosts_.end()) ? (it->second.get()) : nullptr; } bool AppCacheServiceImpl::EraseHost(const base::UnguessableToken& host_id) { + DCHECK_CURRENTLY_ON( + NavigationURLLoaderImpl::GetLoaderRequestControllerThreadID()); return (hosts_.erase(host_id) != 0); }
diff --git a/content/browser/appcache/appcache_service_unittest.cc b/content/browser/appcache/appcache_service_unittest.cc index 9d57dc5..57c4ccc1d 100644 --- a/content/browser/appcache/appcache_service_unittest.cc +++ b/content/browser/appcache/appcache_service_unittest.cc
@@ -14,11 +14,11 @@ #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" -#include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "content/browser/appcache/appcache_response.h" #include "content/browser/appcache/appcache_service_impl.h" #include "content/browser/appcache/mock_appcache_storage.h" +#include "content/public/test/test_browser_thread_bundle.h" #include "net/base/completion_once_callback.h" #include "net/base/io_buffer.h" #include "net/http/http_response_headers.h" @@ -190,7 +190,7 @@ const url::Origin kOrigin; const GURL kManifestUrl; - base::test::ScopedTaskEnvironment scoped_task_environment_; + TestBrowserThreadBundle thread_bundle_; std::unique_ptr<AppCacheServiceImpl> service_; int delete_result_; int delete_completion_count_;
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc index f881195..f8587cc 100644 --- a/content/browser/appcache/appcache_storage_impl.cc +++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -20,6 +20,7 @@ #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/strings/string_util.h" +#include "base/task/post_task.h" #include "base/threading/sequenced_task_runner_handle.h" #include "content/browser/appcache/appcache.h" #include "content/browser/appcache/appcache_database.h" @@ -29,6 +30,7 @@ #include "content/browser/appcache/appcache_quota_client.h" #include "content/browser/appcache/appcache_response.h" #include "content/browser/appcache/appcache_service_impl.h" +#include "content/public/browser/browser_task_traits.h" #include "net/base/cache_type.h" #include "net/base/net_errors.h" #include "sql/database.h" @@ -305,8 +307,17 @@ kDelay); } - if (storage_->service()->quota_client()) - storage_->service()->quota_client()->NotifyAppCacheReady(); + if (storage_->service()->quota_client()) { + if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { + storage_->service()->quota_client()->NotifyAppCacheReady(); + } else { + base::PostTaskWithTraits( + FROM_HERE, {BrowserThread::IO}, + base::BindOnce( + &AppCacheQuotaClient::NotifyAppCacheReady, + base::Unretained(storage_->service()->quota_client()))); + } + } } // DisableDatabaseTask -------
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc index 1e2d927e..d25aa23f3 100644 --- a/content/browser/appcache/appcache_storage_impl_unittest.cc +++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -38,6 +38,7 @@ #include "content/browser/appcache/appcache_url_loader_request.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/public/browser/browser_task_traits.h" +#include "content/public/common/content_features.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread_bundle.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -289,6 +290,10 @@ head.mime_type = "text/html"; mock_url_loader_factory_.AddResponse(GetMockUrl("empty.html"), head, "", status); + // TODO(http://crbug.com/824840): Enable NavigationLoaderOnUI for these + // tests. + feature_list_.InitWithFeatures({network::features::kNetworkService}, + {features::kNavigationLoaderOnUI}); } template <class Method> @@ -1565,10 +1570,6 @@ } void Reinitialize(ReinitTestCase test_case) { - // These tests use the network service code path when simulating requests - // to app cache. - feature_list_.InitAndEnableFeature(network::features::kNetworkService); - // Unlike all of the other tests, this one actually read/write files. ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc index e48c457f..ecd6770 100644 --- a/content/browser/appcache/appcache_update_job_unittest.cc +++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -21,6 +21,7 @@ #include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "base/task/post_task.h" +#include "base/test/scoped_feature_list.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "content/browser/appcache/appcache_group.h" @@ -31,6 +32,7 @@ #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/url_loader_factory_getter.h" #include "content/public/browser/browser_task_traits.h" +#include "content/public/common/content_features.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread_bundle.h" #include "mojo/public/cpp/bindings/remote.h" @@ -704,6 +706,9 @@ tested_manifest_path_override_(nullptr), thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD), process_id_(123) { + // TODO(http://crbug.com/824840): Enable NavigationLoaderOnUI for these + // tests. + feature_list_.InitAndDisableFeature(features::kNavigationLoaderOnUI); base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&IOThread::Init, base::Unretained(io_thread_.get()))); @@ -3830,6 +3835,8 @@ MANIFEST_WITH_INTERCEPT }; + base::test::ScopedFeatureList feature_list_; + // base::test::ScopedTaskEnvironment scoped_task_environment_; std::unique_ptr<IOThread> io_thread_;
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc index b12cde95..baf22af 100644 --- a/content/browser/background_sync/background_sync_manager.cc +++ b/content/browser/background_sync/background_sync_manager.cc
@@ -379,24 +379,28 @@ options.min_interval == kMinIntervalForOneShotSync); if (GetBackgroundSyncType(options) == BackgroundSyncType::ONE_SHOT) { + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, base::BindOnce( &BackgroundSyncManager::RegisterCheckIfHasMainFrame, weak_ptr_factory_.GetWeakPtr(), sw_registration_id, std::move(options), - op_scheduler_.WrapCallbackToRunNext(std::move(callback)))); + op_scheduler_.WrapCallbackToRunNext(id, std::move(callback)))); } else { // Periodic Background Sync events already have a pre-defined cadence which // the user agent decides. Don't block registration if there's no top level // frame at the time of registration. + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, base::BindOnce( &BackgroundSyncManager::RegisterImpl, weak_ptr_factory_.GetWeakPtr(), sw_registration_id, std::move(options), - op_scheduler_.WrapCallbackToRunNext(std::move(callback)))); + op_scheduler_.WrapCallbackToRunNext(id, std::move(callback)))); } } @@ -413,11 +417,14 @@ return; } + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, - base::BindOnce(&BackgroundSyncManager::UnregisterPeriodicSyncImpl, - weak_ptr_factory_.GetWeakPtr(), sw_registration_id, tag, - op_scheduler_.WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &BackgroundSyncManager::UnregisterPeriodicSyncImpl, + weak_ptr_factory_.GetWeakPtr(), sw_registration_id, tag, + op_scheduler_.WrapCallbackToRunNext(id, std::move(callback)))); } void BackgroundSyncManager::DidResolveRegistration( @@ -426,11 +433,13 @@ if (disabled_) return; + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, base::BindOnce(&BackgroundSyncManager::DidResolveRegistrationImpl, weak_ptr_factory_.GetWeakPtr(), - std::move(registration_info))); + std::move(registration_info), id)); } void BackgroundSyncManager::GetOneShotSyncRegistrations( @@ -462,12 +471,14 @@ return; } + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, - base::BindOnce(&BackgroundSyncManager::GetRegistrationsImpl, - weak_ptr_factory_.GetWeakPtr(), sync_type, - sw_registration_id, - op_scheduler_.WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &BackgroundSyncManager::GetRegistrationsImpl, + weak_ptr_factory_.GetWeakPtr(), sync_type, sw_registration_id, + op_scheduler_.WrapCallbackToRunNext(id, std::move(callback)))); } void BackgroundSyncManager::OnRegistrationDeleted(int64_t sw_registration_id, @@ -477,11 +488,13 @@ // Operations already in the queue will either fail when they write to storage // or return stale results based on registrations loaded in memory. This is // inconsequential since the service worker is gone. + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, base::BindOnce(&BackgroundSyncManager::OnRegistrationDeletedImpl, weak_ptr_factory_.GetWeakPtr(), sw_registration_id, - MakeEmptyCompletion())); + MakeEmptyCompletion(id))); } void BackgroundSyncManager::OnStorageWiped() { @@ -490,19 +503,23 @@ // Operations already in the queue will either fail when they write to storage // or return stale results based on registrations loaded in memory. This is // inconsequential since the service workers are gone. + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, base::BindOnce(&BackgroundSyncManager::OnStorageWipedImpl, - weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion())); + weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion(id))); } void BackgroundSyncManager::SetMaxSyncAttemptsForTesting(int max_attempts) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, base::BindOnce(&BackgroundSyncManager::SetMaxSyncAttemptsImpl, weak_ptr_factory_.GetWeakPtr(), max_attempts, - MakeEmptyCompletion())); + MakeEmptyCompletion(id))); } void BackgroundSyncManager::EmulateDispatchSyncEvent( @@ -570,10 +587,12 @@ DCHECK(!op_scheduler_.ScheduledOperations()); DCHECK(!disabled_); + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, base::BindOnce(&BackgroundSyncManager::InitImpl, - weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion())); + weak_ptr_factory_.GetWeakPtr(), MakeEmptyCompletion(id))); } void BackgroundSyncManager::InitImpl(base::OnceClosure callback) { @@ -1107,7 +1126,8 @@ } void BackgroundSyncManager::DidResolveRegistrationImpl( - blink::mojom::BackgroundSyncRegistrationInfoPtr registration_info) { + blink::mojom::BackgroundSyncRegistrationInfoPtr registration_info, + CacheStorageSchedulerId id) { DCHECK_CURRENTLY_ON(BrowserThread::IO); BackgroundSyncRegistration* registration = @@ -1116,7 +1136,7 @@ // There might not be a registration if the client ack's a registration that // was a duplicate in the first place and was already firing and finished by // the time the client acknowledged the second registration. - op_scheduler_.CompleteOperationAndRunNext(); + op_scheduler_.CompleteOperationAndRunNext(id); return; } @@ -1127,16 +1147,17 @@ service_worker_context_, std::move(*registration_info)), base::BindOnce( &BackgroundSyncManager::ResolveRegistrationDidCreateKeepAlive, - weak_ptr_factory_.GetWeakPtr())); + weak_ptr_factory_.GetWeakPtr(), id)); } void BackgroundSyncManager::ResolveRegistrationDidCreateKeepAlive( + CacheStorageSchedulerId id, std::unique_ptr<BackgroundSyncEventKeepAlive> keepalive) { DCHECK_CURRENTLY_ON(BrowserThread::IO); FireReadyEvents(BackgroundSyncType::ONE_SHOT, base::DoNothing::Once(), std::move(keepalive)); - op_scheduler_.CompleteOperationAndRunNext(); + op_scheduler_.CompleteOperationAndRunNext(id); } void BackgroundSyncManager::RemoveActiveRegistration( @@ -1518,11 +1539,13 @@ if (disabled_) return; + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, base::BindOnce(&BackgroundSyncManager::ReviveOriginImpl, weak_ptr_factory_.GetWeakPtr(), std::move(origin), - MakeEmptyCompletion())); + MakeEmptyCompletion(id))); } void BackgroundSyncManager::ReviveOriginImpl(url::Origin origin, @@ -1657,12 +1680,15 @@ std::unique_ptr<BackgroundSyncEventKeepAlive> keepalive) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, - base::BindOnce(&BackgroundSyncManager::FireReadyEventsImpl, - weak_ptr_factory_.GetWeakPtr(), sync_type, - op_scheduler_.WrapCallbackToRunNext(std::move(callback)), - std::move(keepalive))); + base::BindOnce( + &BackgroundSyncManager::FireReadyEventsImpl, + weak_ptr_factory_.GetWeakPtr(), sync_type, + op_scheduler_.WrapCallbackToRunNext(id, std::move(callback)), + std::move(keepalive))); } void BackgroundSyncManager::FireReadyEventsImpl( @@ -1850,13 +1876,15 @@ registration_info->sync_type, status_code == blink::ServiceWorkerStatusCode::kOk)); + auto id = op_scheduler_.CreateId(); op_scheduler_.ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kBackgroundSync, - base::BindOnce(&BackgroundSyncManager::EventCompleteImpl, - weak_ptr_factory_.GetWeakPtr(), - std::move(registration_info), std::move(keepalive), - status_code, origin, - op_scheduler_.WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &BackgroundSyncManager::EventCompleteImpl, + weak_ptr_factory_.GetWeakPtr(), std::move(registration_info), + std::move(keepalive), status_code, origin, + op_scheduler_.WrapCallbackToRunNext(id, std::move(callback)))); } void BackgroundSyncManager::EventCompleteImpl( @@ -2084,9 +2112,10 @@ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback)); } -base::OnceClosure BackgroundSyncManager::MakeEmptyCompletion() { +base::OnceClosure BackgroundSyncManager::MakeEmptyCompletion( + CacheStorageSchedulerId id) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - return op_scheduler_.WrapCallbackToRunNext(base::DoNothing::Once()); + return op_scheduler_.WrapCallbackToRunNext(id, base::DoNothing::Once()); } blink::ServiceWorkerStatusCode BackgroundSyncManager::CanEmulateSyncEvent(
diff --git a/content/browser/background_sync/background_sync_manager.h b/content/browser/background_sync/background_sync_manager.h index 19f67f5..e3e2a85b 100644 --- a/content/browser/background_sync/background_sync_manager.h +++ b/content/browser/background_sync/background_sync_manager.h
@@ -310,8 +310,10 @@ // DidResolveRegistration callbacks void DidResolveRegistrationImpl( - blink::mojom::BackgroundSyncRegistrationInfoPtr registration_info); + blink::mojom::BackgroundSyncRegistrationInfoPtr registration_info, + CacheStorageSchedulerId id); void ResolveRegistrationDidCreateKeepAlive( + CacheStorageSchedulerId id, std::unique_ptr<BackgroundSyncEventKeepAlive> keepalive); // GetRegistrations callbacks @@ -411,7 +413,7 @@ blink::ServiceWorkerStatusCode status); void DidReceiveDelaysForSuspendedRegistrations(base::OnceClosure callback); - base::OnceClosure MakeEmptyCompletion(); + base::OnceClosure MakeEmptyCompletion(CacheStorageSchedulerId id); blink::ServiceWorkerStatusCode CanEmulateSyncEvent( scoped_refptr<ServiceWorkerVersion> active_version);
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc index ac8dd73a..5fbd75f6 100644 --- a/content/browser/browser_context.cc +++ b/content/browser/browser_context.cc
@@ -531,6 +531,14 @@ return; browser_context->was_notify_will_be_destroyed_called_ = true; + // Stop the ServiceManagerConnection from handling any new incoming requests + // before we tear anything down. This prevents races at shutdown. + BrowserContextServiceManagerConnectionHolder* connection_holder = + static_cast<BrowserContextServiceManagerConnectionHolder*>( + browser_context->GetUserData(kServiceManagerConnection)); + if (connection_holder) + connection_holder->service_manager_connection()->Stop(); + // Subclasses of BrowserContext may expect there to be no more // RenderProcessHosts using them by the time this function returns. We // therefore explicitly tear down embedded Content Service instances now to @@ -542,9 +550,6 @@ // because it's possible for someone to call // |GetServiceManagerConnectionFor()| between now and actual BrowserContext // destruction. - BrowserContextServiceManagerConnectionHolder* connection_holder = - static_cast<BrowserContextServiceManagerConnectionHolder*>( - browser_context->GetUserData(kServiceManagerConnection)); if (connection_holder) connection_holder->DestroyRunningServices();
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc index 2e2d4aa..59db93d 100644 --- a/content/browser/cache_storage/cache_storage_manager_unittest.cc +++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -1594,7 +1594,7 @@ EXPECT_FALSE(Delete(origin1_, "tmp")); // Init storage. CacheStorageHandle cache_storage = CacheStorageForOrigin(origin1_); auto* impl = LegacyCacheStorage::From(cache_storage); - impl->StartAsyncOperationForTesting(); + auto id = impl->StartAsyncOperationForTesting(); base::RunLoop open_loop; cache_storage.value()->OpenCache( @@ -1605,7 +1605,7 @@ base::RunLoop().RunUntilIdle(); EXPECT_FALSE(callback_cache_handle_.value()); - impl->CompleteAsyncOperationForTesting(); + impl->CompleteAsyncOperationForTesting(id); open_loop.Run(); EXPECT_TRUE(callback_cache_handle_.value()); }
diff --git a/content/browser/cache_storage/cache_storage_operation.cc b/content/browser/cache_storage/cache_storage_operation.cc index d9084936..99cd3b5 100644 --- a/content/browser/cache_storage/cache_storage_operation.cc +++ b/content/browser/cache_storage/cache_storage_operation.cc
@@ -14,12 +14,16 @@ CacheStorageOperation::CacheStorageOperation( base::OnceClosure closure, + CacheStorageSchedulerId id, CacheStorageSchedulerClient client_type, + CacheStorageSchedulerMode mode, CacheStorageSchedulerOp op_type, scoped_refptr<base::SequencedTaskRunner> task_runner) : closure_(std::move(closure)), creation_ticks_(base::TimeTicks::Now()), + id_(id), client_type_(client_type), + mode_(mode), op_type_(op_type), task_runner_(std::move(task_runner)) {}
diff --git a/content/browser/cache_storage/cache_storage_operation.h b/content/browser/cache_storage/cache_storage_operation.h index 84a66637..91e07fe6 100644 --- a/content/browser/cache_storage/cache_storage_operation.h +++ b/content/browser/cache_storage/cache_storage_operation.h
@@ -21,7 +21,9 @@ class CONTENT_EXPORT CacheStorageOperation { public: CacheStorageOperation(base::OnceClosure closure, + CacheStorageSchedulerId id, CacheStorageSchedulerClient client_type, + CacheStorageSchedulerMode mode, CacheStorageSchedulerOp op_type, scoped_refptr<base::SequencedTaskRunner> task_runner); @@ -31,6 +33,8 @@ void Run(); base::TimeTicks creation_ticks() const { return creation_ticks_; } + CacheStorageSchedulerId id() const { return id_; } + CacheStorageSchedulerMode mode() const { return mode_; } CacheStorageSchedulerOp op_type() const { return op_type_; } base::WeakPtr<CacheStorageOperation> AsWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); @@ -51,7 +55,9 @@ // If the operation took a long time to run. bool was_slow_ = false; + const CacheStorageSchedulerId id_; const CacheStorageSchedulerClient client_type_; + const CacheStorageSchedulerMode mode_; const CacheStorageSchedulerOp op_type_; scoped_refptr<base::SequencedTaskRunner> task_runner_; base::WeakPtrFactory<CacheStorageOperation> weak_ptr_factory_{this};
diff --git a/content/browser/cache_storage/cache_storage_operation_unittest.cc b/content/browser/cache_storage/cache_storage_operation_unittest.cc index b82da9b..b02f6cff 100644 --- a/content/browser/cache_storage/cache_storage_operation_unittest.cc +++ b/content/browser/cache_storage/cache_storage_operation_unittest.cc
@@ -39,7 +39,8 @@ : mock_task_runner_(new base::TestMockTimeTaskRunner()) { operation_ = std::make_unique<CacheStorageOperation>( base::BindOnce(&TestTask::Run, base::Unretained(&task_)), - CacheStorageSchedulerClient::kStorage, CacheStorageSchedulerOp::kTest, + /* id = */ 0, CacheStorageSchedulerClient::kStorage, + CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kTest, mock_task_runner_); }
diff --git a/content/browser/cache_storage/cache_storage_scheduler.cc b/content/browser/cache_storage/cache_storage_scheduler.cc index 9ea8838d..e7fc43d 100644 --- a/content/browser/cache_storage/cache_storage_scheduler.cc +++ b/content/browser/cache_storage/cache_storage_scheduler.cc
@@ -7,62 +7,151 @@ #include <string> #include "base/bind.h" +#include "base/feature_list.h" #include "base/location.h" #include "base/logging.h" +#include "base/metrics/field_trial_params.h" #include "base/metrics/histogram_macros.h" #include "base/sequenced_task_runner.h" #include "content/browser/cache_storage/cache_storage_histogram_utils.h" #include "content/browser/cache_storage/cache_storage_operation.h" +#include "content/public/common/content_features.h" namespace content { +namespace { + +const base::FeatureParam<int> kCacheStorageMaxSharedOps{ + &features::kCacheStorageParallelOps, "max_shared_ops", 1}; + +} // namespace + CacheStorageScheduler::CacheStorageScheduler( CacheStorageSchedulerClient client_type, scoped_refptr<base::SequencedTaskRunner> task_runner) : task_runner_(std::move(task_runner)), client_type_(client_type) {} -CacheStorageScheduler::~CacheStorageScheduler() {} +CacheStorageScheduler::~CacheStorageScheduler() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} -void CacheStorageScheduler::ScheduleOperation(CacheStorageSchedulerOp op_type, +CacheStorageSchedulerId CacheStorageScheduler::CreateId() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return next_id_++; +} + +void CacheStorageScheduler::ScheduleOperation(CacheStorageSchedulerId id, + CacheStorageSchedulerMode mode, + CacheStorageSchedulerOp op_type, base::OnceClosure closure) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); RecordCacheStorageSchedulerUMA(CacheStorageSchedulerUMA::kQueueLength, client_type_, op_type, pending_operations_.size()); pending_operations_.push_back(std::make_unique<CacheStorageOperation>( - std::move(closure), client_type_, op_type, task_runner_)); - RunOperationIfIdle(); + std::move(closure), id, client_type_, mode, op_type, task_runner_)); + MaybeRunOperation(); } -void CacheStorageScheduler::CompleteOperationAndRunNext() { - DCHECK(running_operation_); - running_operation_.reset(); +void CacheStorageScheduler::CompleteOperationAndRunNext( + CacheStorageSchedulerId id) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto it = running_operations_.find(id); + DCHECK(it != running_operations_.end()); + DCHECK_EQ(it->second->id(), id); - RunOperationIfIdle(); + if (it->second->mode() == CacheStorageSchedulerMode::kShared) { + DCHECK_EQ(num_running_exclusive_, 0); + DCHECK_GT(num_running_shared_, 0); + num_running_shared_ -= 1; + if (num_running_shared_ == 0) { + UMA_HISTOGRAM_COUNTS_1000("ServiceWorkerCache.PeakParallelSharedOps", + peak_parallel_shared_); + peak_parallel_shared_ = 0; + } + } else { + DCHECK_EQ(num_running_shared_, 0); + DCHECK_EQ(num_running_exclusive_, 1); + num_running_exclusive_ -= 1; + } + + running_operations_.erase(it); + + MaybeRunOperation(); } bool CacheStorageScheduler::ScheduledOperations() const { - return running_operation_ || !pending_operations_.empty(); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return !running_operations_.empty() || !pending_operations_.empty(); +} + +bool CacheStorageScheduler::IsRunningExclusiveOperation() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + return num_running_exclusive_ > 0; } void CacheStorageScheduler::DispatchOperationTask(base::OnceClosure task) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); task_runner_->PostTask(FROM_HERE, std::move(task)); } -void CacheStorageScheduler::RunOperationIfIdle() { - if (!running_operation_ && !pending_operations_.empty()) { - // TODO(jkarlin): Run multiple operations in parallel where allowed. - running_operation_ = std::move(pending_operations_.front()); - pending_operations_.pop_front(); - - RecordCacheStorageSchedulerUMA( - CacheStorageSchedulerUMA::kQueueDuration, client_type_, - running_operation_->op_type(), - base::TimeTicks::Now() - running_operation_->creation_ticks()); - - DispatchOperationTask(base::BindOnce(&CacheStorageOperation::Run, - running_operation_->AsWeakPtr())); +void CacheStorageScheduler::MaybeRunOperation() { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + // If there are no operations, then we can't run anything. + if (pending_operations_.empty()) { + DoneStartingAvailableOperations(); + return; } + + auto* next_operation = pending_operations_.front().get(); + + // Determine if we can run the next operation based on its mode + // and the current state of executing operations. We allow multiple + // kShared operations to run in parallel, but a kExclusive operation + // must not overlap with any other operation. + if (next_operation->mode() == CacheStorageSchedulerMode::kShared) { + if (num_running_exclusive_ > 0 || + num_running_shared_ >= kCacheStorageMaxSharedOps.Get()) { + DoneStartingAvailableOperations(); + return; + } + } else if (num_running_shared_ > 0 || num_running_exclusive_ > 0) { + DCHECK_EQ(next_operation->mode(), CacheStorageSchedulerMode::kExclusive); + DoneStartingAvailableOperations(); + return; + } + + running_operations_.emplace(next_operation->id(), + std::move(pending_operations_.front())); + pending_operations_.pop_front(); + + RecordCacheStorageSchedulerUMA( + CacheStorageSchedulerUMA::kQueueDuration, client_type_, + next_operation->op_type(), + base::TimeTicks::Now() - next_operation->creation_ticks()); + + if (next_operation->mode() == CacheStorageSchedulerMode::kShared) { + DCHECK_EQ(num_running_exclusive_, 0); + num_running_shared_ += 1; + peak_parallel_shared_ = + std::max(num_running_shared_, peak_parallel_shared_); + } else { + DCHECK_EQ(num_running_exclusive_, 0); + DCHECK_EQ(num_running_shared_, 0); + num_running_exclusive_ += 1; + } + + DispatchOperationTask( + base::BindOnce(&CacheStorageOperation::Run, next_operation->AsWeakPtr())); + + // If we just executed a kShared operation, then we may be able to schedule + // additional kShared parallel operations. Recurse to process the next + // pending operation. + if (next_operation->mode() == CacheStorageSchedulerMode::kShared) + MaybeRunOperation(); + else + DoneStartingAvailableOperations(); } } // namespace content
diff --git a/content/browser/cache_storage/cache_storage_scheduler.h b/content/browser/cache_storage/cache_storage_scheduler.h index 09bbb71f..6bd9a57 100644 --- a/content/browser/cache_storage/cache_storage_scheduler.h +++ b/content/browser/cache_storage/cache_storage_scheduler.h
@@ -6,6 +6,7 @@ #define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_SCHEDULER_H_ #include <list> +#include <map> #include "base/bind.h" #include "base/callback.h" @@ -19,7 +20,6 @@ class CacheStorageOperation; -// TODO(jkarlin): Support readers and writers so operations can run in parallel. // TODO(jkarlin): Support operation identification so that ops can be checked in // DCHECKs. @@ -33,35 +33,56 @@ scoped_refptr<base::SequencedTaskRunner> task_runner); virtual ~CacheStorageScheduler(); - // Adds the operation to the tail of the queue and starts it if the scheduler - // is idle. - void ScheduleOperation(CacheStorageSchedulerOp op_type, + // Create a scheduler-unique identifier for an operation to be scheduled. + // This value must be passed to the ScheduleOperation(), + // CompleteOperationAndRunNext(), and WrapCallbackToRunNext() methods. + CacheStorageSchedulerId CreateId(); + + // Adds the operation to the tail of the queue and starts it if possible. + // A unique identifier must be provided via the CreateId() method. The + // mode determines whether the operation should run exclusively by itself + // or can safely run in parallel with other shared operations. + void ScheduleOperation(CacheStorageSchedulerId id, + CacheStorageSchedulerMode mode, + CacheStorageSchedulerOp op_type, base::OnceClosure closure); - // Call this after each operation completes. It cleans up the current - // operation and starts the next. - void CompleteOperationAndRunNext(); + // Call this after each operation completes. It cleans up the operation + // associated with the given id. If may also start the next set of + // operations. + void CompleteOperationAndRunNext(CacheStorageSchedulerId id); // Returns true if there are any running or pending operations. bool ScheduledOperations() const; + // Returns true if the scheduler is currently running an exclusive operation. + bool IsRunningExclusiveOperation() const; + // Wraps |callback| to also call CompleteOperationAndRunNext. template <typename... Args> base::OnceCallback<void(Args...)> WrapCallbackToRunNext( + CacheStorageSchedulerId id, base::OnceCallback<void(Args...)> callback) { return base::BindOnce(&CacheStorageScheduler::RunNextContinuation<Args...>, - weak_ptr_factory_.GetWeakPtr(), std::move(callback)); + weak_ptr_factory_.GetWeakPtr(), id, + std::move(callback)); } protected: // virtual for testing virtual void DispatchOperationTask(base::OnceClosure task); + // virtual for testing + virtual void DoneStartingAvailableOperations() {} + private: - void RunOperationIfIdle(); + // Maybe start running the next operation depending on the current + // set of running operations and the mode of the next operation. + void MaybeRunOperation(); template <typename... Args> - void RunNextContinuation(base::OnceCallback<void(Args...)> callback, + void RunNextContinuation(CacheStorageSchedulerId id, + base::OnceCallback<void(Args...)> callback, Args... args) { // Grab a weak ptr to guard against the scheduler being deleted during the // callback. @@ -70,14 +91,26 @@ std::move(callback).Run(std::forward<Args>(args)...); if (scheduler) - CompleteOperationAndRunNext(); + CompleteOperationAndRunNext(id); } scoped_refptr<base::SequencedTaskRunner> task_runner_; std::list<std::unique_ptr<CacheStorageOperation>> pending_operations_; - std::unique_ptr<CacheStorageOperation> running_operation_; + std::map<CacheStorageSchedulerId, std::unique_ptr<CacheStorageOperation>> + running_operations_; const CacheStorageSchedulerClient client_type_; + CacheStorageSchedulerId next_id_ = 0; + // Number of shared/exclusive operations currently running. + int num_running_shared_ = 0; + int num_running_exclusive_ = 0; + + // The peak number of parallel shared operations that ran at once. Measured + // between the last time the sheduler started running shared operations and + // when the number of running shared operations drops to zero. + int peak_parallel_shared_ = 0; + + SEQUENCE_CHECKER(sequence_checker_); base::WeakPtrFactory<CacheStorageScheduler> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(CacheStorageScheduler);
diff --git a/content/browser/cache_storage/cache_storage_scheduler_types.h b/content/browser/cache_storage/cache_storage_scheduler_types.h index 6d562f2d..45f9245 100644 --- a/content/browser/cache_storage/cache_storage_scheduler_types.h +++ b/content/browser/cache_storage/cache_storage_scheduler_types.h
@@ -5,8 +5,12 @@ #ifndef CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_SCHEDULER_TYPES_H_ #define CONTENT_BROWSER_CACHE_STORAGE_CACHE_STORAGE_SCHEDULER_TYPES_H_ +#include <stdint.h> + namespace content { +using CacheStorageSchedulerId = int64_t; + // Define the types of clients that might own a scheduler. This enum is used // to populate histogram names and must be kept in sync with the function // in cache_storage_histogram_utils.cc. Please keep this list sorted. It is @@ -18,6 +22,11 @@ kStorage = 2, }; +enum class CacheStorageSchedulerMode { + kExclusive, + kShared, +}; + // Define the different types of operations that can be scheduled. This enum // is used to populate histogram names and must be kept in sync with the // function in cache_storage_histogram_utils.cc. Please keep this list sorted.
diff --git a/content/browser/cache_storage/cache_storage_scheduler_unittest.cc b/content/browser/cache_storage/cache_storage_scheduler_unittest.cc index 3afaf4c9..042f61f8 100644 --- a/content/browser/cache_storage/cache_storage_scheduler_unittest.cc +++ b/content/browser/cache_storage/cache_storage_scheduler_unittest.cc
@@ -7,7 +7,9 @@ #include "base/bind.h" #include "base/callback.h" #include "base/run_loop.h" +#include "base/test/scoped_feature_list.h" #include "base/threading/thread_task_runner_handle.h" +#include "content/public/common/content_features.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,70 +19,470 @@ class TestTask { public: TestTask(CacheStorageScheduler* scheduler) - : scheduler_(scheduler), callback_count_(0) {} + : scheduler_(scheduler), + id_(scheduler_->CreateId()), + callback_count_(0) {} - virtual void Run() { callback_count_++; } - void Done() { scheduler_->CompleteOperationAndRunNext(); } + virtual void Run() { + callback_count_++; + run_loop_.Quit(); + } + void Done() { scheduler_->CompleteOperationAndRunNext(id_); } int callback_count() const { return callback_count_; } + CacheStorageSchedulerId id() const { return id_; } + base::RunLoop& run_loop() { return run_loop_; } protected: CacheStorageScheduler* scheduler_; + const CacheStorageSchedulerId id_; + base::RunLoop run_loop_; int callback_count_; }; +class TestScheduler : public CacheStorageScheduler { + public: + TestScheduler() + : CacheStorageScheduler(CacheStorageSchedulerClient::kStorage, + base::ThreadTaskRunnerHandle::Get()) {} + + void SetDoneStartingClosure(base::OnceClosure done_closure) { + CHECK(!done_closure_); + done_closure_ = std::move(done_closure); + } + + protected: + void DoneStartingAvailableOperations() override { + if (done_closure_) { + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(done_closure_)); + } + CacheStorageScheduler::DoneStartingAvailableOperations(); + } + + base::OnceClosure done_closure_; +}; + class CacheStorageSchedulerTest : public testing::Test { protected: CacheStorageSchedulerTest() : browser_thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), - scheduler_(CacheStorageSchedulerClient::kStorage, - base::ThreadTaskRunnerHandle::Get()), - task1_(TestTask(&scheduler_)), - task2_(TestTask(&scheduler_)) {} + task1_(&scheduler_), + task2_(&scheduler_), + task3_(&scheduler_) {} TestBrowserThreadBundle browser_thread_bundle_; - CacheStorageScheduler scheduler_; + TestScheduler scheduler_; TestTask task1_; TestTask task2_; + TestTask task3_; }; TEST_F(CacheStorageSchedulerTest, ScheduleOne) { + base::RunLoop done_loop; + scheduler_.SetDoneStartingClosure(done_loop.QuitClosure()); scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kTest, base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); - base::RunLoop().RunUntilIdle(); + task1_.run_loop().Run(); + done_loop.Run(); EXPECT_EQ(1, task1_.callback_count()); } -TEST_F(CacheStorageSchedulerTest, ScheduleTwo) { +TEST_F(CacheStorageSchedulerTest, ScheduledOperations) { + base::RunLoop done_loop; + scheduler_.SetDoneStartingClosure(done_loop.QuitClosure()); scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kTest, base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + task1_.run_loop().Run(); + done_loop.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + EXPECT_TRUE(scheduler_.IsRunningExclusiveOperation()); + task1_.Done(); + EXPECT_FALSE(scheduler_.ScheduledOperations()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); +} + +TEST_F(CacheStorageSchedulerTest, ScheduleTwoExclusive) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kCacheStorageParallelOps, {{"max_shared_ops", "3"}}); + scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kExclusive, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); + base::RunLoop done_loop1; + scheduler_.SetDoneStartingClosure(done_loop1.QuitClosure()); + scheduler_.ScheduleOperation( + task2_.id(), CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kTest, base::BindOnce(&TestTask::Run, base::Unretained(&task2_))); - base::RunLoop().RunUntilIdle(); + + // Should only run the first exclusive op. + task1_.run_loop().Run(); + done_loop1.Run(); EXPECT_EQ(1, task1_.callback_count()); EXPECT_EQ(0, task2_.callback_count()); + EXPECT_TRUE(scheduler_.IsRunningExclusiveOperation()); + base::RunLoop done_loop2; + scheduler_.SetDoneStartingClosure(done_loop2.QuitClosure()); + + // Should run the second exclusive op after the first completes. task1_.Done(); EXPECT_TRUE(scheduler_.ScheduledOperations()); - base::RunLoop().RunUntilIdle(); + task2_.run_loop().Run(); + done_loop2.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_TRUE(scheduler_.IsRunningExclusiveOperation()); +} + +TEST_F(CacheStorageSchedulerTest, ScheduleTwoShared) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kCacheStorageParallelOps, {{"max_shared_ops", "3"}}); + + scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); + base::RunLoop done_loop1; + scheduler_.SetDoneStartingClosure(done_loop1.QuitClosure()); + scheduler_.ScheduleOperation( + task2_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task2_))); + + // Should run both shared ops in paralle. + task1_.run_loop().Run(); + task2_.run_loop().Run(); + done_loop1.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop2; + scheduler_.SetDoneStartingClosure(done_loop2.QuitClosure()); + + // Completing the first op should trigger a check for new ops + // which will not be present here. + task1_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + done_loop2.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop3; + scheduler_.SetDoneStartingClosure(done_loop3.QuitClosure()); + + // Completing the second op should result in the scheduler + // becoming idle. + task2_.Done(); + EXPECT_FALSE(scheduler_.ScheduledOperations()); + done_loop3.Run(); EXPECT_EQ(1, task1_.callback_count()); EXPECT_EQ(1, task2_.callback_count()); } -TEST_F(CacheStorageSchedulerTest, ScheduledOperations) { +TEST_F(CacheStorageSchedulerTest, ScheduleOneExclusiveOneShared) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kCacheStorageParallelOps, {{"max_shared_ops", "3"}}); + scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kTest, base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); - EXPECT_TRUE(scheduler_.ScheduledOperations()); - base::RunLoop().RunUntilIdle(); + base::RunLoop done_loop1; + scheduler_.SetDoneStartingClosure(done_loop1.QuitClosure()); + scheduler_.ScheduleOperation( + task2_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task2_))); + + // Should only run the first exclusive op. + task1_.run_loop().Run(); + done_loop1.Run(); EXPECT_EQ(1, task1_.callback_count()); - EXPECT_TRUE(scheduler_.ScheduledOperations()); + EXPECT_EQ(0, task2_.callback_count()); + EXPECT_TRUE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop2; + scheduler_.SetDoneStartingClosure(done_loop2.QuitClosure()); + + // Should run the second shared op after the first is completed. task1_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + task2_.run_loop().Run(); + done_loop2.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + task2_.Done(); EXPECT_FALSE(scheduler_.ScheduledOperations()); } +TEST_F(CacheStorageSchedulerTest, ScheduleOneSharedOneExclusive) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kCacheStorageParallelOps, {{"max_shared_ops", "3"}}); + + scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); + base::RunLoop done_loop1; + scheduler_.SetDoneStartingClosure(done_loop1.QuitClosure()); + scheduler_.ScheduleOperation( + task2_.id(), CacheStorageSchedulerMode::kExclusive, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task2_))); + + // Should only run the first shared op. + task1_.run_loop().Run(); + done_loop1.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(0, task2_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop2; + scheduler_.SetDoneStartingClosure(done_loop2.QuitClosure()); + + // Should run the second exclusive op after the first completes. + task1_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + task2_.run_loop().Run(); + done_loop2.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_TRUE(scheduler_.IsRunningExclusiveOperation()); + + task2_.Done(); + EXPECT_FALSE(scheduler_.ScheduledOperations()); +} + +TEST_F(CacheStorageSchedulerTest, ScheduleTwoSharedOneExclusive) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kCacheStorageParallelOps, {{"max_shared_ops", "3"}}); + + scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); + scheduler_.ScheduleOperation( + task2_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task2_))); + base::RunLoop done_loop1; + scheduler_.SetDoneStartingClosure(done_loop1.QuitClosure()); + scheduler_.ScheduleOperation( + task3_.id(), CacheStorageSchedulerMode::kExclusive, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task3_))); + + // Should run the two shared ops in parallel. + task1_.run_loop().Run(); + task2_.run_loop().Run(); + done_loop1.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_EQ(0, task3_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop2; + scheduler_.SetDoneStartingClosure(done_loop2.QuitClosure()); + + // Completing the first shared op should not allow the exclusive op + // to run yet. + task1_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + done_loop2.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_EQ(0, task3_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop3; + scheduler_.SetDoneStartingClosure(done_loop3.QuitClosure()); + + // The third exclusive op should run after both the preceding shared ops + // complete. + task2_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + task3_.run_loop().Run(); + done_loop3.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_EQ(1, task3_.callback_count()); + EXPECT_TRUE(scheduler_.IsRunningExclusiveOperation()); + + task3_.Done(); + EXPECT_FALSE(scheduler_.ScheduledOperations()); +} + +TEST_F(CacheStorageSchedulerTest, ScheduleOneExclusiveTwoShared) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kCacheStorageParallelOps, {{"max_shared_ops", "3"}}); + + scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kExclusive, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); + scheduler_.ScheduleOperation( + task2_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task2_))); + base::RunLoop done_loop1; + scheduler_.SetDoneStartingClosure(done_loop1.QuitClosure()); + scheduler_.ScheduleOperation( + task3_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task3_))); + + // Should only run the first exclusive op. + task1_.run_loop().Run(); + done_loop1.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(0, task2_.callback_count()); + EXPECT_EQ(0, task3_.callback_count()); + EXPECT_TRUE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop2; + scheduler_.SetDoneStartingClosure(done_loop2.QuitClosure()); + + // Should run both the shared ops in parallel after the first exclusive + // op is completed. + task1_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + task2_.run_loop().Run(); + task3_.run_loop().Run(); + done_loop2.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_EQ(1, task3_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop3; + scheduler_.SetDoneStartingClosure(done_loop3.QuitClosure()); + + task2_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + done_loop3.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_EQ(1, task3_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + task3_.Done(); + EXPECT_FALSE(scheduler_.ScheduledOperations()); +} + +TEST_F(CacheStorageSchedulerTest, ScheduleOneSharedOneExclusiveOneShared) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kCacheStorageParallelOps, {{"max_shared_ops", "3"}}); + + scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); + scheduler_.ScheduleOperation( + task2_.id(), CacheStorageSchedulerMode::kExclusive, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task2_))); + base::RunLoop done_loop1; + scheduler_.SetDoneStartingClosure(done_loop1.QuitClosure()); + scheduler_.ScheduleOperation( + task3_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task3_))); + + // Should only run the first shared op. + task1_.run_loop().Run(); + done_loop1.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(0, task2_.callback_count()); + EXPECT_EQ(0, task3_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop2; + scheduler_.SetDoneStartingClosure(done_loop2.QuitClosure()); + + // Should run the exclusive op after the first op is completed. + task1_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + task2_.run_loop().Run(); + done_loop2.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_EQ(0, task3_.callback_count()); + EXPECT_TRUE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop3; + scheduler_.SetDoneStartingClosure(done_loop3.QuitClosure()); + + // Should run the last shared op after the preceding exclusive op + // is completed. + task2_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + task3_.run_loop().Run(); + done_loop3.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_EQ(1, task3_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + task3_.Done(); + EXPECT_FALSE(scheduler_.ScheduledOperations()); +} + +TEST_F(CacheStorageSchedulerTest, ScheduleTwoSharedNotParallel) { + // Disable parallelism + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndEnableFeatureWithParameters( + features::kCacheStorageParallelOps, {{"max_shared_ops", "1"}}); + + scheduler_.ScheduleOperation( + task1_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task1_))); + base::RunLoop done_loop1; + scheduler_.SetDoneStartingClosure(done_loop1.QuitClosure()); + scheduler_.ScheduleOperation( + task2_.id(), CacheStorageSchedulerMode::kShared, + CacheStorageSchedulerOp::kTest, + base::BindOnce(&TestTask::Run, base::Unretained(&task2_))); + + // Should only run one shared op since the max shared is set to 1. + task1_.run_loop().Run(); + done_loop1.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(0, task2_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); + + base::RunLoop done_loop2; + scheduler_.SetDoneStartingClosure(done_loop2.QuitClosure()); + + // Should run the next shared op after the first completes. + task1_.Done(); + EXPECT_TRUE(scheduler_.ScheduledOperations()); + task2_.run_loop().Run(); + done_loop2.Run(); + EXPECT_EQ(1, task1_.callback_count()); + EXPECT_EQ(1, task2_.callback_count()); + EXPECT_FALSE(scheduler_.IsRunningExclusiveOperation()); +} + } // namespace cache_storage_scheduler_unittest } // namespace content
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage.cc b/content/browser/cache_storage/legacy/legacy_cache_storage.cc index b30684d..a064cef4 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage.cc +++ b/content/browser/cache_storage/legacy/legacy_cache_storage.cc
@@ -619,11 +619,13 @@ // operations to better support use by internal code that may // start a single operation without explicitly maintaining a // handle. + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kOpen, - base::BindOnce(&LegacyCacheStorage::OpenCacheImpl, - weak_factory_.GetWeakPtr(), cache_name, trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kOpen, + base::BindOnce( + &LegacyCacheStorage::OpenCacheImpl, weak_factory_.GetWeakPtr(), + cache_name, trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::HasCache(const std::string& cache_name, @@ -638,11 +640,13 @@ CacheStorageQuotaClient::GetIDFromOwner(owner_), origin_, StorageType::kTemporary); + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kHas, - base::BindOnce(&LegacyCacheStorage::HasCacheImpl, - weak_factory_.GetWeakPtr(), cache_name, trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kHas, + base::BindOnce( + &LegacyCacheStorage::HasCacheImpl, weak_factory_.GetWeakPtr(), + cache_name, trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::DoomCache(const std::string& cache_name, @@ -657,11 +661,14 @@ CacheStorageQuotaClient::GetIDFromOwner(owner_), origin_, StorageType::kTemporary); + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kDelete, - base::BindOnce(&LegacyCacheStorage::DoomCacheImpl, - weak_factory_.GetWeakPtr(), cache_name, trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &LegacyCacheStorage::DoomCacheImpl, weak_factory_.GetWeakPtr(), + cache_name, trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::EnumerateCaches(int64_t trace_id, @@ -675,11 +682,13 @@ CacheStorageQuotaClient::GetIDFromOwner(owner_), origin_, StorageType::kTemporary); + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kKeys, - base::BindOnce(&LegacyCacheStorage::EnumerateCachesImpl, - weak_factory_.GetWeakPtr(), trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kKeys, + base::BindOnce( + &LegacyCacheStorage::EnumerateCachesImpl, weak_factory_.GetWeakPtr(), + trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::MatchCache( @@ -697,12 +706,13 @@ CacheStorageQuotaClient::GetIDFromOwner(owner_), origin_, StorageType::kTemporary); + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kMatch, - base::BindOnce(&LegacyCacheStorage::MatchCacheImpl, - weak_factory_.GetWeakPtr(), cache_name, std::move(request), - std::move(match_options), trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatch, + base::BindOnce( + &LegacyCacheStorage::MatchCacheImpl, weak_factory_.GetWeakPtr(), + cache_name, std::move(request), std::move(match_options), trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::MatchAllCaches( @@ -719,12 +729,14 @@ CacheStorageQuotaClient::GetIDFromOwner(owner_), origin_, StorageType::kTemporary); + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatchAll, - base::BindOnce(&LegacyCacheStorage::MatchAllCachesImpl, - weak_factory_.GetWeakPtr(), std::move(request), - std::move(match_options), trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &LegacyCacheStorage::MatchAllCachesImpl, weak_factory_.GetWeakPtr(), + std::move(request), std::move(match_options), trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::WriteToCache( @@ -742,12 +754,16 @@ CacheStorageQuotaClient::GetIDFromOwner(owner_), origin_, StorageType::kTemporary); + // Note, this is a shared operation since it only reads CacheStorage data. + // The CacheStorageCache is responsible for making its put operation + // exclusive. + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kPut, - base::BindOnce(&LegacyCacheStorage::WriteToCacheImpl, - weak_factory_.GetWeakPtr(), cache_name, std::move(request), - std::move(response), trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kPut, + base::BindOnce( + &LegacyCacheStorage::WriteToCacheImpl, weak_factory_.GetWeakPtr(), + cache_name, std::move(request), std::move(response), trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::GetSizeThenCloseAllCaches(SizeCallback callback) { @@ -756,11 +772,17 @@ if (!initialized_) LazyInit(); + // Note, this is a shared operation since it only reads CacheStorage data. + // The CacheStorageCache is responsible for making its close operation + // exclusive. + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kSizeThenClose, - base::BindOnce(&LegacyCacheStorage::GetSizeThenCloseAllCachesImpl, - weak_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &LegacyCacheStorage::GetSizeThenCloseAllCachesImpl, + weak_factory_.GetWeakPtr(), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::Size(LegacyCacheStorage::SizeCallback callback) { @@ -769,10 +791,12 @@ if (!initialized_) LazyInit(); + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kSize, - base::BindOnce(&LegacyCacheStorage::SizeImpl, weak_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kSize, + base::BindOnce( + &LegacyCacheStorage::SizeImpl, weak_factory_.GetWeakPtr(), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::ResetManager() { @@ -798,16 +822,19 @@ void LegacyCacheStorage::WriteIndex(base::OnceCallback<void(bool)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kWriteIndex, - base::BindOnce(&LegacyCacheStorage::WriteIndexImpl, - weak_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &LegacyCacheStorage::WriteIndexImpl, weak_factory_.GetWeakPtr(), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorage::WriteIndexImpl( base::OnceCallback<void(bool)> callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(scheduler_->IsRunningExclusiveOperation()); cache_loader_->WriteIndex(*cache_index_, std::move(callback)); } @@ -871,13 +898,17 @@ cache_map_it->second.reset(); } -void LegacyCacheStorage::StartAsyncOperationForTesting() { - scheduler_->ScheduleOperation(CacheStorageSchedulerOp::kTest, +CacheStorageSchedulerId LegacyCacheStorage::StartAsyncOperationForTesting() { + auto id = scheduler_->CreateId(); + scheduler_->ScheduleOperation(id, CacheStorageSchedulerMode::kExclusive, + CacheStorageSchedulerOp::kTest, base::DoNothing()); + return id; } -void LegacyCacheStorage::CompleteAsyncOperationForTesting() { - scheduler_->CompleteOperationAndRunNext(); +void LegacyCacheStorage::CompleteAsyncOperationForTesting( + CacheStorageSchedulerId id) { + scheduler_->CompleteOperationAndRunNext(id); } // Init is run lazily so that it is called on the proper MessageLoop. @@ -891,7 +922,9 @@ DCHECK(!scheduler_->ScheduledOperations()); initializing_ = true; + init_id_ = scheduler_->CreateId(); scheduler_->ScheduleOperation( + init_id_, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kInit, base::BindOnce(&LegacyCacheStorage::LazyInitImpl, weak_factory_.GetWeakPtr())); @@ -907,6 +940,7 @@ // 3. Once each load is complete, update the map variables. // 4. Call the list of waiting callbacks. + DCHECK(scheduler_->IsRunningExclusiveOperation()); cache_loader_->LoadIndex(base::BindOnce( &LegacyCacheStorage::LazyInitDidLoadIndex, weak_factory_.GetWeakPtr())); } @@ -926,7 +960,7 @@ initializing_ = false; initialized_ = true; - scheduler_->CompleteOperationAndRunNext(); + scheduler_->CompleteOperationAndRunNext(init_id_); } void LegacyCacheStorage::OpenCacheImpl(const std::string& cache_name, @@ -943,6 +977,7 @@ return; } + DCHECK(scheduler_->IsRunningExclusiveOperation()); cache_loader_->PrepareNewCacheDestination( cache_name, base::BindOnce(&LegacyCacheStorage::CreateCacheDidCreateCache, weak_factory_.GetWeakPtr(), cache_name, @@ -1034,6 +1069,7 @@ return; } + DCHECK(scheduler_->IsRunningExclusiveOperation()); LegacyCacheStorageCache::From(cache_handle)->SetObserver(nullptr); cache_index_->DoomCache(cache_name); cache_loader_->WriteIndex(
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage.h b/content/browser/cache_storage/legacy/legacy_cache_storage.h index f0985a7..14ae5b6 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage.h +++ b/content/browser/cache_storage/legacy/legacy_cache_storage.h
@@ -17,6 +17,7 @@ #include "base/memory/weak_ptr.h" #include "content/browser/cache_storage/cache_storage.h" #include "content/browser/cache_storage/cache_storage_cache_observer.h" +#include "content/browser/cache_storage/cache_storage_scheduler_types.h" #include "content/browser/cache_storage/legacy/legacy_cache_storage_cache.h" namespace base { @@ -119,8 +120,8 @@ // The functions below are for tests to verify that the operations run // serially. - void StartAsyncOperationForTesting(); - void CompleteAsyncOperationForTesting(); + CacheStorageSchedulerId StartAsyncOperationForTesting(); + void CompleteAsyncOperationForTesting(CacheStorageSchedulerId id); // Removes the manager reference. Called before this storage is deleted by the // manager, since it is removed from manager's storage map before deleting. @@ -295,6 +296,8 @@ // The owner that this CacheStorage is associated with. CacheStorageOwner owner_; + CacheStorageSchedulerId init_id_ = -1; + // The manager that owns this cache storage. Only set to null by // RemoveManager() when this cache storage is being deleted. LegacyCacheStorageManager* cache_storage_manager_;
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc index 5eb3460a1..7e2a5d6 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc +++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -540,12 +540,13 @@ return; } + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kMatch, - base::BindOnce(&LegacyCacheStorageCache::MatchImpl, - weak_ptr_factory_.GetWeakPtr(), std::move(request), - std::move(match_options), trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatch, + base::BindOnce( + &LegacyCacheStorageCache::MatchImpl, weak_ptr_factory_.GetWeakPtr(), + std::move(request), std::move(match_options), trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorageCache::MatchAll( @@ -560,12 +561,15 @@ return; } + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatchAll, - base::BindOnce(&LegacyCacheStorageCache::MatchAllImpl, - weak_ptr_factory_.GetWeakPtr(), std::move(request), - std::move(match_options), trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &LegacyCacheStorageCache::MatchAllImpl, + weak_ptr_factory_.GetWeakPtr(), std::move(request), + std::move(match_options), trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorageCache::WriteSideData(ErrorCallback callback, @@ -825,23 +829,26 @@ return; } + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kKeys, - base::BindOnce(&LegacyCacheStorageCache::KeysImpl, - weak_ptr_factory_.GetWeakPtr(), std::move(request), - std::move(options), trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kKeys, + base::BindOnce( + &LegacyCacheStorageCache::KeysImpl, weak_ptr_factory_.GetWeakPtr(), + std::move(request), std::move(options), trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorageCache::Close(base::OnceClosure callback) { DCHECK_NE(BACKEND_CLOSED, backend_state_) << "Was LegacyCacheStorageCache::Close() called twice?"; + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kClose, - base::BindOnce(&LegacyCacheStorageCache::CloseImpl, - weak_ptr_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &LegacyCacheStorageCache::CloseImpl, weak_ptr_factory_.GetWeakPtr(), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorageCache::Size(SizeCallback callback) { @@ -852,11 +859,12 @@ return; } + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kSize, - base::BindOnce(&LegacyCacheStorageCache::SizeImpl, - weak_ptr_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kSize, + base::BindOnce( + &LegacyCacheStorageCache::SizeImpl, weak_ptr_factory_.GetWeakPtr(), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorageCache::GetSizeThenClose(SizeCallback callback) { @@ -866,14 +874,16 @@ return; } + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kSizeThenClose, base::BindOnce( &LegacyCacheStorageCache::SizeImpl, weak_ptr_factory_.GetWeakPtr(), base::BindOnce( &LegacyCacheStorageCache::GetSizeThenCloseDidGetSize, weak_ptr_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(std::move(callback))))); + scheduler_->WrapCallbackToRunNext(id, std::move(callback))))); } void LegacyCacheStorageCache::SetObserver(CacheStorageCacheObserver* observer) { @@ -1358,11 +1368,13 @@ return; } + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kWriteSideData, base::BindOnce(&LegacyCacheStorageCache::WriteSideDataImpl, weak_ptr_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(std::move(callback)), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)), url, expected_response_time, trace_id, buffer, buf_len)); } @@ -1477,6 +1489,7 @@ weak_ptr_factory_.GetWeakPtr(), std::move(callback), std::move(entry), buf_len, std::move(response), side_data_size_before_write, trace_id)); + DCHECK(scheduler_->IsRunningExclusiveOperation()); int rv = temp_entry_ptr->WriteData( INDEX_SIDE_DATA, 0 /* offset */, buffer.get(), buf_len, write_side_data_callback, true /* truncate */); @@ -1560,11 +1573,12 @@ auto put_context = cache_entry_handler_->CreatePutContext( std::move(request), std::move(response), trace_id); + auto id = scheduler_->CreateId(); put_context->callback = - scheduler_->WrapCallbackToRunNext(std::move(callback)); + scheduler_->WrapCallbackToRunNext(id, std::move(callback)); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kPut, + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kPut, base::BindOnce(&LegacyCacheStorageCache::PutImpl, weak_ptr_factory_.GetWeakPtr(), std::move(put_context))); } @@ -1645,6 +1659,7 @@ weak_ptr_factory_.GetWeakPtr(), std::move(scoped_entry_ptr), std::move(put_context))); + DCHECK(scheduler_->IsRunningExclusiveOperation()); int rv = backend_ptr->CreateEntry(request_.url.spec(), net::HIGHEST, entry_ptr, create_entry_callback); @@ -1729,6 +1744,7 @@ weak_ptr_factory_.GetWeakPtr(), std::move(put_context), buffer->size())); + DCHECK(scheduler_->IsRunningExclusiveOperation()); rv = temp_entry_ptr->WriteData(INDEX_HEADERS, 0 /* offset */, buffer.get(), buffer->size(), write_headers_callback, true /* truncate */); @@ -1977,12 +1993,15 @@ return; } + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kGetAllMatched, - base::BindOnce(&LegacyCacheStorageCache::GetAllMatchedEntriesImpl, - weak_ptr_factory_.GetWeakPtr(), std::move(request), - std::move(options), trace_id, - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &LegacyCacheStorageCache::GetAllMatchedEntriesImpl, + weak_ptr_factory_.GetWeakPtr(), std::move(request), + std::move(options), trace_id, + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorageCache::GetAllMatchedEntriesImpl( @@ -2060,12 +2079,14 @@ request->referrer = operation->request->referrer.Clone(); request->headers = operation->request->headers; + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kDelete, - base::BindOnce(&LegacyCacheStorageCache::DeleteImpl, - weak_ptr_factory_.GetWeakPtr(), std::move(request), - std::move(operation->match_options), - scheduler_->WrapCallbackToRunNext(std::move(callback)))); + base::BindOnce( + &LegacyCacheStorageCache::DeleteImpl, weak_ptr_factory_.GetWeakPtr(), + std::move(request), std::move(operation->match_options), + scheduler_->WrapCallbackToRunNext(id, std::move(callback)))); } void LegacyCacheStorageCache::DeleteImpl( @@ -2104,6 +2125,8 @@ return; } + DCHECK(scheduler_->IsRunningExclusiveOperation()); + for (auto& result : *query_cache_results) { disk_cache::ScopedEntryPtr entry = std::move(result.entry); if (ShouldPadResourceSize(*result.response)) { @@ -2171,6 +2194,7 @@ void LegacyCacheStorageCache::CloseImpl(base::OnceClosure callback) { DCHECK_EQ(BACKEND_OPEN, backend_state_); + DCHECK(scheduler_->IsRunningExclusiveOperation()); backend_.reset(); post_backend_closed_callback_ = std::move(callback); } @@ -2229,6 +2253,7 @@ weak_ptr_factory_.GetWeakPtr(), std::move(callback), std::move(backend_ptr))); + DCHECK(scheduler_->IsRunningExclusiveOperation()); int rv = disk_cache::CreateCacheBackend( cache_type, net::CACHE_BACKEND_SIMPLE, path_, max_bytes, false, /* force */ @@ -2261,15 +2286,16 @@ DCHECK(!scheduler_->ScheduledOperations()); initializing_ = true; + auto id = scheduler_->CreateId(); scheduler_->ScheduleOperation( - CacheStorageSchedulerOp::kInit, + id, CacheStorageSchedulerMode::kExclusive, CacheStorageSchedulerOp::kInit, base::BindOnce( &LegacyCacheStorageCache::CreateBackend, weak_ptr_factory_.GetWeakPtr(), base::BindOnce( &LegacyCacheStorageCache::InitDidCreateBackend, weak_ptr_factory_.GetWeakPtr(), - scheduler_->WrapCallbackToRunNext(base::DoNothing::Once())))); + scheduler_->WrapCallbackToRunNext(id, base::DoNothing::Once())))); } void LegacyCacheStorageCache::InitDidCreateBackend(
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc index 2d6b24c..537640fe 100644 --- a/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc +++ b/content/browser/cache_storage/legacy/legacy_cache_storage_manager.cc
@@ -167,7 +167,16 @@ auto origin_path = LegacyCacheStorageManager::ConstructOriginPath( root_path, origin, owner); if (path != origin_path) { - RecordIndexValidationResult(IndexResult::kPathMismatch); + CacheStorageOwner other_owner = owner == CacheStorageOwner::kCacheAPI + ? CacheStorageOwner::kBackgroundFetch + : CacheStorageOwner::kCacheAPI; + auto other_owner_path = LegacyCacheStorageManager::ConstructOriginPath( + root_path, origin, other_owner); + // Some of the paths in the |root_path| directory are for a different + // |owner|. That is valid and expected, but if the path doesn't match + // the calculated path for either |owner|, then it is invalid. + if (path != other_owner_path) + RecordIndexValidationResult(IndexResult::kPathMismatch); continue; }
diff --git a/content/browser/content_index/content_index_context_impl.cc b/content/browser/content_index/content_index_context_impl.cc index ffdff6a..65353e61 100644 --- a/content/browser/content_index/content_index_context_impl.cc +++ b/content/browser/content_index/content_index_context_impl.cc
@@ -133,13 +133,27 @@ blink::ServiceWorkerStatusCode start_worker_status) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + // Don't allow DB operations while the `contentdelete` event is firing. + // This is to prevent re-registering the deleted content within the event. + content_index_database_.BlockOrigin(service_worker->script_origin()); + int request_id = service_worker->StartRequest( - ServiceWorkerMetrics::EventType::CONTENT_DELETE, base::DoNothing()); + ServiceWorkerMetrics::EventType::CONTENT_DELETE, + base::BindOnce(&ContentIndexContextImpl::DidDispatchEvent, this, + service_worker->script_origin())); service_worker->endpoint()->DispatchContentDeleteEvent( description_id, service_worker->CreateSimpleEventCallback(request_id)); } +void ContentIndexContextImpl::DidDispatchEvent( + const url::Origin& origin, + blink::ServiceWorkerStatusCode service_worker_status) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + content_index_database_.UnblockOrigin(origin); +} + void ContentIndexContextImpl::Shutdown() { DCHECK_CURRENTLY_ON(BrowserThread::UI); content_index_database_.Shutdown();
diff --git a/content/browser/content_index/content_index_context_impl.h b/content/browser/content_index/content_index_context_impl.h index c746e65..6cc780b3 100644 --- a/content/browser/content_index/content_index_context_impl.h +++ b/content/browser/content_index/content_index_context_impl.h
@@ -69,6 +69,9 @@ const std::string& description_id, blink::ServiceWorkerStatusCode start_worker_status); + void DidDispatchEvent(const url::Origin& origin, + blink::ServiceWorkerStatusCode service_worker_status); + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_; ContentIndexDatabase content_index_database_;
diff --git a/content/browser/content_index/content_index_database.cc b/content/browser/content_index/content_index_database.cc index b125d300..cdbcb57 100644 --- a/content/browser/content_index/content_index_database.cc +++ b/content/browser/content_index/content_index_database.cc
@@ -119,6 +119,12 @@ const SkBitmap& icon, const GURL& launch_url, blink::mojom::ContentIndexService::AddCallback callback) { + if (blocked_origins_.count(origin)) { + // TODO(crbug.com/973844): Does this need a more specific error? + std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR); + return; + } + SerializeIcon(icon, base::BindOnce(&ContentIndexDatabase::DidSerializeIcon, weak_ptr_factory_io_.GetWeakPtr(), service_worker_registration_id, origin, @@ -356,6 +362,19 @@ EntryFromSerializedProto(service_worker_registration_id, data.front())); } +void ContentIndexDatabase::BlockOrigin(const url::Origin& origin) { + blocked_origins_[origin]++; +} + +void ContentIndexDatabase::UnblockOrigin(const url::Origin& origin) { + DCHECK(blocked_origins_.count(origin)); + auto it = blocked_origins_.find(origin); + if (it->second == 1) + blocked_origins_.erase(it); + else + it->second--; +} + void ContentIndexDatabase::Shutdown() { DCHECK_CURRENTLY_ON(BrowserThread::UI);
diff --git a/content/browser/content_index/content_index_database.h b/content/browser/content_index/content_index_database.h index f7da3a1..2cfb68d 100644 --- a/content/browser/content_index/content_index_database.h +++ b/content/browser/content_index/content_index_database.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_BROWSER_CONTENT_INDEX_CONTENT_INDEX_DATABASE_H_ #define CONTENT_BROWSER_CONTENT_INDEX_CONTENT_INDEX_DATABASE_H_ +#include "base/containers/flat_map.h" #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "content/browser/service_worker/service_worker_context_wrapper.h" @@ -62,6 +63,10 @@ const std::string& description_id, ContentIndexContext::GetEntryCallback callback); + // Block/Unblock DB operations for |origin|. + void BlockOrigin(const url::Origin& origin); + void UnblockOrigin(const url::Origin& origin); + // Called when the storage partition is shutting down. void Shutdown(); @@ -110,6 +115,9 @@ // Lives on the UI thread. ContentIndexProvider* provider_; + // A map from origins to how many times it's been blocked. + base::flat_map<url::Origin, int> blocked_origins_; + scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_; base::WeakPtrFactory<ContentIndexDatabase> weak_ptr_factory_io_; base::WeakPtrFactory<ContentIndexDatabase> weak_ptr_factory_ui_;
diff --git a/content/browser/content_index/content_index_database_unittest.cc b/content/browser/content_index/content_index_database_unittest.cc index 9615abc8..4a7734b 100644 --- a/content/browser/content_index/content_index_database_unittest.cc +++ b/content/browser/content_index/content_index_database_unittest.cc
@@ -409,4 +409,32 @@ } } +TEST_F(ContentIndexDatabaseTest, BlockedOriginsCannotRegisterContent) { + // Initially adding is fine. + EXPECT_EQ(AddEntry(CreateDescription("id1")), + blink::mojom::ContentIndexError::NONE); + + // Two delete events were dispatched. + database()->BlockOrigin(origin()); + database()->BlockOrigin(origin()); + + // Content can't be registered while the origin is blocked. + EXPECT_EQ(AddEntry(CreateDescription("id2")), + blink::mojom::ContentIndexError::STORAGE_ERROR); + + // First event dispatch completed. + database()->UnblockOrigin(origin()); + + // Content still can't be registered. + EXPECT_EQ(AddEntry(CreateDescription("id3")), + blink::mojom::ContentIndexError::STORAGE_ERROR); + + // Last event dispatch completed. + database()->UnblockOrigin(origin()); + + // Registering is OK now. + EXPECT_EQ(AddEntry(CreateDescription("id4")), + blink::mojom::ContentIndexError::NONE); +} + } // namespace content
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index b999311..b4f1b8b 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc
@@ -1121,7 +1121,8 @@ // Download manager is only initialized if both history db and in progress // cache are initialized. - if (!history_db_initialized_ || !in_progress_cache_initialized_) + bool history_loaded = history_db_initialized_ || IsOffTheRecord(); + if (!history_loaded || !in_progress_cache_initialized_) return; #if defined(OS_ANDROID) @@ -1381,8 +1382,8 @@ } url_loader_factory_getter = base::MakeRefCounted<FileSystemDownloadURLLoaderFactoryGetter>( - params->url(), rfh, /*is_navigation=*/false, - storage_partition->GetFileSystemContext(), storage_domain); + params->url(), rfh, storage_partition->GetFileSystemContext(), + storage_domain); } else if (params->url().SchemeIs(url::kDataScheme)) { url_loader_factory_getter = CreateDownloadURLLoaderFactoryGetterFromURLLoaderFactory(
diff --git a/content/browser/download/file_system_download_url_loader_factory_getter.cc b/content/browser/download/file_system_download_url_loader_factory_getter.cc index 3c4780e..13da85d0 100644 --- a/content/browser/download/file_system_download_url_loader_factory_getter.cc +++ b/content/browser/download/file_system_download_url_loader_factory_getter.cc
@@ -9,6 +9,8 @@ #include "components/download/public/common/download_task_runner.h" #include "content/browser/fileapi/file_system_url_loader_factory.h" #include "content/browser/url_loader_factory_getter.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "services/network/public/cpp/wrapper_shared_url_loader_factory.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" @@ -19,11 +21,9 @@ FileSystemDownloadURLLoaderFactoryGetter( const GURL& url, RenderFrameHost* rfh, - bool is_navigation, scoped_refptr<storage::FileSystemContext> file_system_context, const std::string& storage_domain) : rfh_(rfh), - is_navigation_(is_navigation), file_system_context_(file_system_context), storage_domain_(storage_domain) { DCHECK(url.SchemeIs(url::kFileSystemScheme)); @@ -38,7 +38,8 @@ DCHECK(download::GetIOTaskRunner()->BelongsToCurrentThread()); std::unique_ptr<network::mojom::URLLoaderFactory> factory = - CreateFileSystemURLLoaderFactory(rfh_, is_navigation_, + CreateFileSystemURLLoaderFactory(rfh_->GetProcess()->GetID(), + rfh_->GetFrameTreeNodeId(), file_system_context_, storage_domain_); network::mojom::URLLoaderFactoryPtrInfo url_loader_factory_ptr_info;
diff --git a/content/browser/download/file_system_download_url_loader_factory_getter.h b/content/browser/download/file_system_download_url_loader_factory_getter.h index 422a6e9ab..fae54d0a 100644 --- a/content/browser/download/file_system_download_url_loader_factory_getter.h +++ b/content/browser/download/file_system_download_url_loader_factory_getter.h
@@ -26,7 +26,6 @@ FileSystemDownloadURLLoaderFactoryGetter( const GURL& url, RenderFrameHost* rfh, - bool is_navigation, scoped_refptr<storage::FileSystemContext> file_system_context, const std::string& storage_domain); @@ -38,7 +37,6 @@ private: RenderFrameHost* rfh_; - const bool is_navigation_; scoped_refptr<storage::FileSystemContext> file_system_context_; const std::string storage_domain_;
diff --git a/content/browser/download/save_file_manager.cc b/content/browser/download/save_file_manager.cc index 8b76dbb..fa5bc07 100644 --- a/content/browser/download/save_file_manager.cc +++ b/content/browser/download/save_file_manager.cc
@@ -279,7 +279,7 @@ &partition_name, &in_memory); } url_loader_factory = CreateFileSystemURLLoaderFactory( - rfh, /*is_navigation=*/false, + rfh->GetProcess()->GetID(), rfh->GetFrameTreeNodeId(), storage_partition->GetFileSystemContext(), storage_domain); factory = url_loader_factory.get(); } else if (rfh && url.SchemeIs(content::kChromeUIScheme)) {
diff --git a/content/browser/fileapi/file_system_url_loader_factory.cc b/content/browser/fileapi/file_system_url_loader_factory.cc index 063d74c88..c6537709 100644 --- a/content/browser/fileapi/file_system_url_loader_factory.cc +++ b/content/browser/fileapi/file_system_url_loader_factory.cc
@@ -650,19 +650,12 @@ std::unique_ptr<network::mojom::URLLoaderFactory> CreateFileSystemURLLoaderFactory( - RenderFrameHost* render_frame_host, - bool is_navigation, + int render_process_host_id, + int frame_tree_node_id, scoped_refptr<FileSystemContext> file_system_context, const std::string& storage_domain) { - // Get the RPH ID for security checks for non-navigation resource requests. - int render_process_host_id = is_navigation - ? ChildProcessHost::kInvalidUniqueID - : render_frame_host->GetProcess()->GetID(); - - FactoryParams params = {render_process_host_id, - render_frame_host->GetFrameTreeNodeId(), + FactoryParams params = {render_process_host_id, frame_tree_node_id, file_system_context, storage_domain}; - return std::make_unique<FileSystemURLLoaderFactory>( std::move(params), base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}));
diff --git a/content/browser/fileapi/file_system_url_loader_factory.h b/content/browser/fileapi/file_system_url_loader_factory.h index 2cfda1e1..c00d9594 100644 --- a/content/browser/fileapi/file_system_url_loader_factory.h +++ b/content/browser/fileapi/file_system_url_loader_factory.h
@@ -19,10 +19,30 @@ // Create a URLLoaderFactory to serve filesystem: requests from the given // |file_system_context| and |storage_domain|. +// +// |render_process_host_id| is the ID of the RenderProcessHost where the +// requests are issued. +// - For a factory created for a browser-initiated navigation request: +// ChildProcessHost::kInvalidUniqueID (there is no process yet). +// - For a factory created to pass to the renderer for subresource requests from +// the frame: that renderer process's ID. +// - For a factory created for a browser-initiated worker main script request: +// the ID of the process the worker will run in. +// TODO(https://crbug.com/986188): We should specify kInvalidUniqueID for this +// worker main script case like the browser-initiated navigation case. +// - For a factory created to pass to the renderer for subresource requests from +// the worker: that renderer process's ID. +// +// |frame_tree_node_id| is the ID of the FrameTreeNode where the requests are +// associated. +// - For a factory created for a browser-initiated navigation request, or for a +// factory created for subresource requests from the frame: that frame's ID. +// - For a factory created for workers (which don't have frames): +// RenderFrameHost::kNoFrameTreeNodeId. CONTENT_EXPORT std::unique_ptr<network::mojom::URLLoaderFactory> CreateFileSystemURLLoaderFactory( - RenderFrameHost* render_frame_host, - bool is_navigation, + int render_process_host_id, + int frame_tree_node_id, scoped_refptr<storage::FileSystemContext> file_system_context, const std::string& storage_domain);
diff --git a/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc b/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc index c8ea0b4..b431248 100644 --- a/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc +++ b/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
@@ -473,7 +473,8 @@ const std::string storage_domain = url.GetOrigin().host(); auto factory = content::CreateFileSystemURLLoaderFactory( - render_frame_host(), /*is_navigation=*/false, file_system_context, + render_frame_host()->GetProcess()->GetID(), + render_frame_host()->GetFrameTreeNodeId(), file_system_context, storage_domain); auto client = std::make_unique<network::TestURLLoaderClient>();
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc index 0cd7025..b798e7a3 100644 --- a/content/browser/frame_host/navigation_handle_impl.cc +++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -44,13 +44,6 @@ // Overrideable via SetCommitTimeoutForTesting. base::TimeDelta g_commit_timeout = kDefaultCommitTimeout; -// Use this to get a new unique ID for a NavigationHandle during construction. -// The returned ID is guaranteed to be nonzero (zero is the "no ID" indicator). -int64_t CreateUniqueHandleID() { - static int64_t unique_id_counter = 0; - return ++unique_id_counter; -} - } // namespace NavigationHandleImpl::NavigationHandleImpl( @@ -60,7 +53,6 @@ : navigation_request_(navigation_request), request_headers_(std::move(request_headers)), pending_nav_entry_id_(pending_nav_entry_id), - navigation_id_(CreateUniqueHandleID()), reload_type_(ReloadType::NONE), restore_type_(RestoreType::NONE) { const GURL& url = navigation_request_->common_params().url; @@ -125,7 +117,7 @@ } int64_t NavigationHandleImpl::GetNavigationId() { - return navigation_id_; + return navigation_request_->navigation_handle_id(); } const GURL& NavigationHandleImpl::GetURL() { @@ -401,7 +393,7 @@ } const net::ProxyServer& NavigationHandleImpl::GetProxyServer() { - return proxy_server_; + return navigation_request_->proxy_server(); } void NavigationHandleImpl::InitServiceWorkerHandle(
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h index d95a3f4..2770c97 100644 --- a/content/browser/frame_host/navigation_handle_impl.h +++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -194,10 +194,6 @@ return navigation_request_->common_params().source_location; } - void set_proxy_server(const net::ProxyServer& proxy_server) { - proxy_server_ = proxy_server; - } - std::vector<std::string> TakeRemovedRequestHeaders() { return std::move(removed_request_headers_); } @@ -272,18 +268,12 @@ // corresponding provider is created in the renderer. std::unique_ptr<ServiceWorkerNavigationHandle> service_worker_handle_; - // The unique id to identify this to navigation with. - int64_t navigation_id_; - // Stores the reload type, or NONE if it's not a reload. ReloadType reload_type_; // Stores the restore type, or NONE it it's not a restore. RestoreType restore_type_; - // Which proxy server was used for this navigation, if any. - net::ProxyServer proxy_server_; - // Allows to override response_headers_ in tests. // TODO(clamy): Clean this up once the architecture of unit tests is better. scoped_refptr<net::HttpResponseHeaders> response_headers_for_testing_;
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 22ab203..f8d5c526 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -450,6 +450,13 @@ NOTREACHED() << "Invalid page transition: " << transition; } +// Use this to get a new unique ID for a NavigationHandle during construction. +// The returned ID is guaranteed to be nonzero (zero is the "no ID" indicator). +int64_t CreateUniqueHandleID() { + static int64_t unique_id_counter = 0; + return ++unique_id_counter; +} + } // namespace // static @@ -989,6 +996,7 @@ } handle_state_ = NavigationRequest::INITIAL; + navigation_handle_id_ = CreateUniqueHandleID(); std::unique_ptr<NavigationHandleImpl> navigation_handle = base::WrapUnique( new NavigationHandleImpl(this, nav_entry_id_, std::move(headers))); @@ -1388,7 +1396,7 @@ } // This must be set before DetermineCommittedPreviews is called. - navigation_handle_->set_proxy_server(response_head->head.proxy_server); + proxy_server_ = response_head->head.proxy_server; // Update the previews state of the request. common_params_.previews_state = @@ -2418,6 +2426,18 @@ rfh, blink::mojom::WebFeature::kOpenerNavigationDownloadCrossOrigin); } + // Log UseCounters for download in sandbox. + if (download_policy.IsType(NavigationDownloadType::kSandbox)) { + GetContentClient()->browser()->LogWebFeatureForCurrentPage( + rfh, blink::mojom::WebFeature::kDownloadInSandbox); + } + + // Log UseCounters for download without user activation. + if (download_policy.IsType(NavigationDownloadType::kNoGesture)) { + GetContentClient()->browser()->LogWebFeatureForCurrentPage( + rfh, blink::mojom::WebFeature::kDownloadWithoutUserGesture); + } + // Log UseCounters for download in sandbox without user activation. if (download_policy.IsType(NavigationDownloadType::kSandboxNoGesture)) { GetContentClient()->browser()->LogWebFeatureForCurrentPage( @@ -2430,10 +2450,10 @@ rfh, blink::mojom::WebFeature::kDownloadInAdFrameWithoutUserGesture); } - // Log UseCounters for download in ad frame with user activation. - if (download_policy.IsType(NavigationDownloadType::kAdFrameGesture)) { + // Log UseCounters for download in ad frame. + if (download_policy.IsType(NavigationDownloadType::kAdFrame)) { GetContentClient()->browser()->LogWebFeatureForCurrentPage( - rfh, blink::mojom::WebFeature::kDownloadInAdFrameWithUserGesture); + rfh, blink::mojom::WebFeature::kDownloadInAdFrame); } }
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h index f5aa353..67c95139 100644 --- a/content/browser/frame_host/navigation_request.h +++ b/content/browser/frame_host/navigation_request.h
@@ -29,6 +29,7 @@ #include "content/public/browser/render_process_host_observer.h" #include "content/public/common/previews_state.h" #include "mojo/public/cpp/system/data_pipe.h" +#include "net/base/proxy_server.h" #include "services/network/public/cpp/origin_policy.h" #if defined(OS_ANDROID) @@ -456,6 +457,10 @@ complete_callback_for_testing_ = std::move(callback); } + const net::ProxyServer& proxy_server() { return proxy_server_; } + + int64_t navigation_handle_id() { return navigation_handle_id_; } + private: // TODO(clamy): Transform NavigationHandleImplTest into NavigationRequestTest // once NavigationHandleImpl has become a wrapper around NavigationRequest. @@ -946,6 +951,12 @@ // load it from the corresponding entry. std::unique_ptr<BundledExchangesFactory> bundled_exchanges_factory_; + // Which proxy server was used for this navigation, if any. + net::ProxyServer proxy_server_; + + // The unique id to identify the NavigationHandle with. + int64_t navigation_handle_id_ = 0; + base::WeakPtrFactory<NavigationRequest> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(NavigationRequest);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index d570dbb..a9d30fa2e 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -5038,8 +5038,8 @@ non_network_url_loader_factories_.emplace( url::kFileSystemScheme, content::CreateFileSystemURLLoaderFactory( - this, /*is_navigation=*/false, partition->GetFileSystemContext(), - storage_domain)); + process_->GetID(), GetFrameTreeNodeId(), + partition->GetFileSystemContext(), storage_domain)); non_network_url_loader_factories_.emplace( url::kDataScheme, std::make_unique<DataURLLoaderFactory>());
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc index 6181257..4a971e5 100644 --- a/content/browser/isolated_origin_browsertest.cc +++ b/content/browser/isolated_origin_browsertest.cc
@@ -1469,6 +1469,112 @@ } } +namespace { +bool HasDefaultSiteInstance(RenderFrameHost* rfh) { + return static_cast<SiteInstanceImpl*>(rfh->GetSiteInstance()) + ->IsDefaultSiteInstance(); +} +} // namespace + +// Verify process assignment behavior for the case where a site that does not +// require isolation embeds a frame that does require isolation, which in turn +// embeds another site that does not require isolation. +// A (Does not require isolation) +// +-> B (requires isolation) +// +-> C (different site from A that does not require isolation.) +// +-> A (same site as top-level which also does not require isolation.) +IN_PROC_BROWSER_TEST_F(IsolatedOriginTest, AIsolatedCA) { + GURL main_url(embedded_test_server()->GetURL( + "www.foo.com", + "/cross_site_iframe_factory.html?a(isolated.foo.com(c(www.foo.com)))")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + RenderFrameHost* a = root->current_frame_host(); + RenderFrameHost* b = root->child_at(0)->current_frame_host(); + RenderFrameHost* c = root->child_at(0)->child_at(0)->current_frame_host(); + RenderFrameHost* d = + root->child_at(0)->child_at(0)->child_at(0)->current_frame_host(); + + // Sanity check that the test works with the right frame tree. + EXPECT_FALSE(IsIsolatedOrigin(a->GetLastCommittedOrigin())); + EXPECT_TRUE(IsIsolatedOrigin(b->GetLastCommittedOrigin())); + EXPECT_FALSE(IsIsolatedOrigin(c->GetLastCommittedOrigin())); + EXPECT_FALSE(IsIsolatedOrigin(d->GetLastCommittedOrigin())); + EXPECT_EQ("www.foo.com", a->GetLastCommittedURL().host()); + EXPECT_EQ("isolated.foo.com", b->GetLastCommittedURL().host()); + EXPECT_EQ("c.com", c->GetLastCommittedURL().host()); + EXPECT_EQ("www.foo.com", d->GetLastCommittedURL().host()); + + // Verify that the isolated site is indeed isolated. + EXPECT_NE(b->GetProcess()->GetID(), a->GetProcess()->GetID()); + EXPECT_NE(b->GetProcess()->GetID(), c->GetProcess()->GetID()); + EXPECT_NE(b->GetProcess()->GetID(), d->GetProcess()->GetID()); + + // Verify that same-origin a and d frames share a process. This is + // necessary for correctness - otherwise a and d wouldn't be able to + // synchronously script each other. + EXPECT_EQ(a->GetProcess()->GetID(), d->GetProcess()->GetID()); + + // Verify that same-origin a and d frames can script each other. + EXPECT_TRUE(ExecuteScript(a, "window.name = 'a';")); + EXPECT_TRUE(ExecuteScript(d, R"( + a = window.open('', 'a'); + a.cross_frame_property_test = 'hello from d'; )")); + EXPECT_EQ("hello from d", + EvalJs(a, "window.cross_frame_property_test").ExtractString()); + + // The test assertions below are not strictly necessary - they just document + // the current behavior. In particular, consolidating www.foo.com and c.com + // sites into the same process is not necessary for correctness. + if (AreAllSitesIsolatedForTesting()) { + // All sites are isolated so we expect foo.com, isolated.foo.com and c.com + // to all be in their own processes. + EXPECT_NE(a->GetProcess()->GetID(), b->GetProcess()->GetID()); + EXPECT_NE(a->GetProcess()->GetID(), c->GetProcess()->GetID()); + EXPECT_NE(b->GetProcess()->GetID(), c->GetProcess()->GetID()); + + EXPECT_NE(a->GetSiteInstance(), b->GetSiteInstance()); + EXPECT_NE(a->GetSiteInstance(), c->GetSiteInstance()); + EXPECT_EQ(a->GetSiteInstance(), d->GetSiteInstance()); + EXPECT_NE(b->GetSiteInstance(), c->GetSiteInstance()); + + EXPECT_FALSE(HasDefaultSiteInstance(a)); + EXPECT_FALSE(HasDefaultSiteInstance(b)); + EXPECT_FALSE(HasDefaultSiteInstance(c)); + } else if (AreDefaultSiteInstancesEnabled()) { + // All sites that are not isolated should be in the same default + // SiteInstance process. + EXPECT_NE(a->GetProcess()->GetID(), b->GetProcess()->GetID()); + EXPECT_EQ(a->GetProcess()->GetID(), c->GetProcess()->GetID()); + + EXPECT_NE(a->GetSiteInstance(), b->GetSiteInstance()); + EXPECT_EQ(a->GetSiteInstance(), c->GetSiteInstance()); + EXPECT_EQ(a->GetSiteInstance(), d->GetSiteInstance()); + EXPECT_NE(b->GetSiteInstance(), c->GetSiteInstance()); + + EXPECT_TRUE(HasDefaultSiteInstance(a)); + EXPECT_FALSE(HasDefaultSiteInstance(b)); + } else { + // Documenting current behavior where the top level document doesn't end + // up in a default SiteInstance even though it is not isolated and does not + // require a dedicated process. c.com does get placed in a default + // SiteInstance because we currently allow subframes that don't require + // isolation to share a process. This behavior should go away once we + // turn on default SiteInstances by default. + EXPECT_NE(a->GetProcess()->GetID(), b->GetProcess()->GetID()); + EXPECT_NE(a->GetProcess()->GetID(), c->GetProcess()->GetID()); + + EXPECT_NE(a->GetSiteInstance(), b->GetSiteInstance()); + EXPECT_NE(a->GetSiteInstance(), c->GetSiteInstance()); + EXPECT_EQ(a->GetSiteInstance(), d->GetSiteInstance()); + EXPECT_NE(b->GetSiteInstance(), c->GetSiteInstance()); + + EXPECT_FALSE(HasDefaultSiteInstance(a)); + EXPECT_FALSE(HasDefaultSiteInstance(b)); + EXPECT_TRUE(HasDefaultSiteInstance(c)); + } +} + class IsolatedOriginTestWithMojoBlobURLs : public IsolatedOriginTest { public: IsolatedOriginTestWithMojoBlobURLs() {
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc index 2f3c7e91..7dafa5c2 100644 --- a/content/browser/loader/navigation_url_loader_impl.cc +++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -935,13 +935,18 @@ browser_context_to_use = browser_context_; else resource_context_to_use = resource_context_; + // TODO(crbug.com/984460): Don't use WeakPtrs for callbacks. These + // WeakPtrs are to work around a case where ServiceWorkerNavigationLoader + // outlives the interceptor. We may want to reset fallback callback in + // ServiceWorkerNavigationLoader when the URLLoaderRequestController is + // going away. next_interceptor->MaybeCreateLoader( *resource_request_, browser_context_to_use, resource_context_to_use, base::BindOnce(&URLLoaderRequestController::MaybeStartLoader, - base::Unretained(this), next_interceptor), + weak_factory_.GetWeakPtr(), next_interceptor), base::BindOnce( &URLLoaderRequestController::FallbackToNonInterceptedRequest, - base::Unretained(this))); + weak_factory_.GetWeakPtr())); return; } @@ -1789,8 +1794,8 @@ const std::string storage_domain; non_network_url_loader_factories_[url::kFileSystemScheme] = - CreateFileSystemURLLoaderFactory(frame_tree_node->current_frame_host(), - /*is_navigation=*/true, + CreateFileSystemURLLoaderFactory(ChildProcessHost::kInvalidUniqueID, + frame_tree_node->frame_tree_node_id(), partition->GetFileSystemContext(), storage_domain); }
diff --git a/content/browser/media/cdm_file_impl.cc b/content/browser/media/cdm_file_impl.cc index 2390ccf..887215a 100644 --- a/content/browser/media/cdm_file_impl.cc +++ b/content/browser/media/cdm_file_impl.cc
@@ -20,6 +20,7 @@ #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "storage/browser/fileapi/file_stream_reader.h" +#include "storage/browser/fileapi/file_stream_writer.h" #include "storage/browser/fileapi/file_system_context.h" #include "storage/browser/fileapi/file_system_operation_context.h" #include "storage/browser/fileapi/file_system_url.h" @@ -116,30 +117,6 @@ return file_lock_map; } -// Write |data| to |file|. Returns kSuccess if everything works, kFailure -// otherwise. This method owns |file| and it will be closed at the end. -CdmFileImpl::Status WriteFile(base::File file, std::vector<uint8_t> data) { - // As the temporary file should have been newly created, it should be empty. - CHECK_EQ(0u, file.GetLength()) << "Temporary file is not empty."; - int bytes_to_write = base::checked_cast<int>(data.size()); - - TRACE_EVENT0("media", "CdmFileWriteFile"); - base::TimeTicks start = base::TimeTicks::Now(); - int bytes_written = - file.Write(0, reinterpret_cast<const char*>(data.data()), bytes_to_write); - base::TimeDelta write_time = base::TimeTicks::Now() - start; - if (bytes_written != bytes_to_write) { - DLOG(WARNING) << "Failed to write file. Requested " << bytes_to_write - << " bytes, wrote " << bytes_written; - return CdmFileImpl::Status::kFailure; - } - - // Only report writing time for successful writes. - UMA_HISTOGRAM_TIMES("Media.EME.CdmFileIO.WriteTime", write_time); - - return CdmFileImpl::Status::kSuccess; -} - // File stream operations need an IOBuffer to hold the data. This class stores // the data in a std::vector<uint8_t> to match what is used in the // mojom::CdmFile API. @@ -150,6 +127,11 @@ data_ = reinterpret_cast<char*>(buffer_.data()); } + // Create a buffer that contains |data|. + explicit CdmFileIOBuffer(const std::vector<uint8_t>& data) : buffer_(data) { + data_ = reinterpret_cast<char*>(buffer_.data()); + } + // Returns ownership of |buffer_| to the caller. std::vector<uint8_t>&& TakeData() { return std::move(buffer_); } @@ -292,6 +274,102 @@ DISALLOW_COPY_AND_ASSIGN(FileReader); }; +class CdmFileImpl::FileWriter { + public: + // Returns whether the write operation succeeded or not. + using WriteDoneCB = base::OnceCallback<void(bool)>; + + FileWriter() {} + + // Writes |buffer| as the contents of |file_url| and calls |callback| with + // whether the write succeeded or not. + void Write(scoped_refptr<storage::FileSystemContext> file_system_context, + const storage::FileSystemURL& file_url, + scoped_refptr<net::IOBuffer> buffer, + int bytes_to_write, + WriteDoneCB callback) { + DVLOG(3) << __func__ << " url: " << file_url.DebugString(); + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + callback_ = std::move(callback); + + // Create a writer on |temp_file_name_|. This temp file will be renamed + // after a successful write. + file_stream_writer_ = + file_system_context->CreateFileStreamWriter(file_url, 0); + base::TimeTicks start_time = base::TimeTicks::Now(); + auto result = file_stream_writer_->Write( + buffer.get(), bytes_to_write, + base::BindOnce(&FileWriter::OnWrite, weak_factory_.GetWeakPtr(), buffer, + start_time, bytes_to_write)); + DVLOG(3) << __func__ << " Write(): " << result; + + // If Write() is running asynchronously, simply return. + if (result == net::ERR_IO_PENDING) + return; + + // Write() was synchronous, so pass the result on. + OnWrite(std::move(buffer), start_time, bytes_to_write, result); + } + + private: + // Called when the file has been written. |result| will be the number of bytes + // written (if >= 0) or a net:: error on failure (if < 0). + void OnWrite(scoped_refptr<net::IOBuffer> buffer, + base::TimeTicks start_time, + int bytes_to_write, + int result) { + DVLOG(3) << __func__ << " Expected to write " << bytes_to_write + << " bytes, got " << result; + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + if (result != bytes_to_write) { + // Unable to write the file. + DLOG(WARNING) << "Failed to write file. Sent " << bytes_to_write + << " bytes, wrote " << result; + std::move(callback_).Run(false); + return; + } + + // Only report writing time for successful writes. + base::TimeDelta write_time = base::TimeTicks::Now() - start_time; + UMA_HISTOGRAM_TIMES("Media.EME.CdmFileIO.WriteTime", write_time); + + result = file_stream_writer_->Flush( + base::BindOnce(&FileWriter::OnFlush, weak_factory_.GetWeakPtr())); + DVLOG(3) << __func__ << " Flush(): " << result; + + // If Flush() is running asynchronously, simply return. + if (result == net::ERR_IO_PENDING) + return; + + // Flush() was synchronous, so pass the result on. + OnFlush(result); + } + + // Called when the file has been flushed. |result| is the net:: error code. + void OnFlush(int result) { + DVLOG(3) << __func__ << " Result: " << result; + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + // We are done with |file_stream_writer_|. + file_stream_writer_.reset(); + + DLOG_IF(WARNING, result != net::OK) + << "Failed to flush file, result: " << result; + std::move(callback_).Run(result == net::OK); + } + + // Called when the write operation is done. + WriteDoneCB callback_; + + // Used to write the stream. + std::unique_ptr<storage::FileStreamWriter> file_stream_writer_; + + base::WeakPtrFactory<FileWriter> weak_factory_{this}; + DISALLOW_COPY_AND_ASSIGN(FileWriter); +}; + // static bool CdmFileImpl::IsValidName(const std::string& name) { // File names must only contain letters (A-Za-z), digits(0-9), or "._-", @@ -335,11 +413,8 @@ if (read_callback_) std::move(read_callback_).Run(Status::kFailure, {}); - if (file_reader_) { - // |file_reader_| must be deleted on the IO thread. - base::CreateSequencedTaskRunner({BrowserThread::IO}) - ->DeleteSoon(FROM_HERE, std::move(file_reader_)); - } + if (write_callback_) + std::move(write_callback_).Run(Status::kFailure); if (file_locked_) ReleaseFileLock(file_name_); @@ -380,12 +455,10 @@ // the IO thread. Use of base::Unretained() is OK as the reader is owned by // |this|, and if |this| is destructed it will destroy the file reader on the // IO thread. - file_reader_ = std::make_unique<FileReader>(); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&FileReader::Read, base::Unretained(file_reader_.get()), - file_system_context_, CreateFileSystemURL(file_name_), - std::move(read_done_cb))); + file_reader_ = base::SequenceBound<FileReader>( + base::CreateSequencedTaskRunner({BrowserThread::IO})); + file_reader_.Post(FROM_HERE, &FileReader::Read, file_system_context_, + CreateFileSystemURL(file_name_), std::move(read_done_cb)); } void CdmFileImpl::ReadDone(bool success, std::vector<uint8_t> data) { @@ -397,7 +470,7 @@ DCHECK(read_callback_); // We are done with the reader, so destroy it. - file_reader_.reset(); + file_reader_.Reset(); if (!success) { // Unable to read the contents of the file. @@ -408,37 +481,13 @@ std::move(read_callback_).Run(Status::kSuccess, std::move(data)); } -void CdmFileImpl::OpenFile(const std::string& file_name, - uint32_t file_flags, - CreateOrOpenCallback callback) { - DVLOG(3) << __func__ << " file: " << file_name << ", flags: " << file_flags; - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(file_locked_); - - storage::FileSystemURL file_url = CreateFileSystemURL(file_name); - storage::AsyncFileUtil* file_util = file_system_context_->GetAsyncFileUtil( - storage::kFileSystemTypePluginPrivate); - auto operation_context = - std::make_unique<storage::FileSystemOperationContext>( - file_system_context_.get()); - operation_context->set_allowed_bytes_growth(storage::QuotaManager::kNoLimit); - DVLOG(3) << "Opening " << file_url.DebugString(); - - file_util->CreateOrOpen(std::move(operation_context), file_url, file_flags, - std::move(callback)); -} - void CdmFileImpl::Write(const std::vector<uint8_t>& data, WriteCallback callback) { DVLOG(3) << __func__ << " file: " << file_name_ << ", size: " << data.size(); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(file_locked_); - - // If there is no data to write, delete the file to save space. - if (data.empty()) { - DeleteFile(std::move(callback)); - return; - } + DCHECK(!write_callback_); + DCHECK(!file_writer_); // Files are limited in size, so fail if file too big. This should have been // checked by the caller, but we don't fully trust IPC. @@ -449,51 +498,83 @@ return; } - // Open the temporary file for writing. Specifying FLAG_CREATE_ALWAYS which - // will overwrite any existing file. - OpenFile( - temp_file_name_, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE, - base::BindOnce(&CdmFileImpl::OnTempFileOpenedForWriting, - weak_factory_.GetWeakPtr(), data, std::move(callback))); -} + // Save |callback| for later use. + write_callback_ = std::move(callback); -void CdmFileImpl::OnTempFileOpenedForWriting( - std::vector<uint8_t> data, - WriteCallback callback, - base::File file, - base::OnceClosure on_close_callback) { - DVLOG(3) << __func__ << " file: " << temp_file_name_ - << ", bytes_to_write: " << data.size(); - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(file_locked_); - - if (!file.IsValid()) { - DLOG(WARNING) << "Unable to open file " << temp_file_name_ << ", error: " - << base::File::ErrorToString(file.error_details()); - std::move(callback).Run(Status::kFailure); + // If there is no data to write, delete the file to save space. + // |write_callback_| will be called after the file is deleted. + if (data.empty()) { + DeleteFile(); return; } - // Writing to |file| must be done on a thread that allows blocking, so post a - // task to do the writing on a separate thread. When that completes we need to - // rename the file in order to replace any existing contents. - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, - {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, - base::BindOnce(&WriteFile, std::move(file), std::move(data)), - base::BindOnce(&CdmFileImpl::OnFileWritten, weak_factory_.GetWeakPtr(), - std::move(callback))); + // Copy |data| into a net::IOBuffer. + int bytes_to_write = base::checked_cast<int>(data.size()); + auto buffer = base::MakeRefCounted<CdmFileIOBuffer>(data); + + // FileStreamWriter only works on existing files. |temp_file_name_| should not + // exist, so create an empty one if necessary. + auto url = CreateFileSystemURL(temp_file_name_); + auto* file_util = file_system_context_->GetAsyncFileUtil( + storage::kFileSystemTypePluginPrivate); + auto operation_context = + std::make_unique<storage::FileSystemOperationContext>( + file_system_context_.get()); + operation_context->set_allowed_bytes_growth(storage::QuotaManager::kNoLimit); + file_util->EnsureFileExists( + std::move(operation_context), url, + base::Bind(&CdmFileImpl::OnEnsureFileExists, weak_factory_.GetWeakPtr(), + std::move(buffer), bytes_to_write)); } -void CdmFileImpl::OnFileWritten(WriteCallback callback, Status status) { - DVLOG(3) << __func__ << " file: " << temp_file_name_ - << ", status: " << status; +void CdmFileImpl::OnEnsureFileExists(scoped_refptr<net::IOBuffer> buffer, + int bytes_to_write, + base::File::Error result, + bool created) { + DVLOG(3) << __func__ << " file: " << file_name_ + << ", result: " << base::File::ErrorToString(result); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(file_locked_); + DCHECK(write_callback_); + DCHECK(!file_writer_); - if (status != Status::kSuccess) { - // Write failed, so fail. - std::move(callback).Run(status); + if (result != base::File::FILE_OK) { + // Unable to create the file. + DLOG(WARNING) << "Failed to create temporary file, result: " + << base::File::ErrorToString(result); + std::move(write_callback_).Run(Status::kFailure); + return; + } + + // As writing is done on the IO thread, when it's done WriteDone() needs to be + // called on this thread. + auto write_done_cb = media::BindToCurrentLoop( + base::BindOnce(&CdmFileImpl::WriteDone, weak_factory_.GetWeakPtr())); + + // Create the file writer that runs on the IO thread, and then call Write() + // on the IO thread to write |buffer| into the temporary file. Use of + // base::Unretained() is OK as |file_writer_| is owned by |this|, and if + // |this| is destructed it will destroy |file_writer_| on the IO thread. + file_writer_ = base::SequenceBound<FileWriter>( + base::CreateSequencedTaskRunner({BrowserThread::IO})); + file_writer_.Post(FROM_HERE, &FileWriter::Write, file_system_context_, + CreateFileSystemURL(temp_file_name_), std::move(buffer), + bytes_to_write, std::move(write_done_cb)); +} + +void CdmFileImpl::WriteDone(bool success) { + DVLOG(3) << __func__ << " file: " << file_name_ + << ", success: " << (success ? "yes" : "no"); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(file_locked_); + DCHECK(file_writer_); + DCHECK(write_callback_); + + // We are done with |file_writer_|. + file_writer_.Reset(); + + if (!success) { + std::move(write_callback_).Run(Status::kFailure); return; } @@ -510,32 +591,35 @@ file_util->MoveFileLocal( std::move(operation_context), src_file_url, dest_file_url, storage::FileSystemOperation::OPTION_NONE, - base::BindOnce(&CdmFileImpl::OnFileRenamed, weak_factory_.GetWeakPtr(), - std::move(callback))); + base::BindOnce(&CdmFileImpl::OnFileRenamed, weak_factory_.GetWeakPtr())); } -void CdmFileImpl::OnFileRenamed(WriteCallback callback, - base::File::Error move_result) { - DVLOG(3) << __func__; +void CdmFileImpl::OnFileRenamed(base::File::Error move_result) { + DVLOG(3) << __func__ << " file: " << file_name_ + << ", result: " << base::File::ErrorToString(move_result); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(file_locked_); + DCHECK(!file_writer_); + DCHECK(write_callback_); // Was the rename successful? if (move_result != base::File::FILE_OK) { DLOG(WARNING) << "Unable to rename file " << temp_file_name_ << " to " << file_name_ << ", error: " << base::File::ErrorToString(move_result); - std::move(callback).Run(Status::kFailure); + std::move(write_callback_).Run(Status::kFailure); return; } - std::move(callback).Run(Status::kSuccess); + std::move(write_callback_).Run(Status::kSuccess); } -void CdmFileImpl::DeleteFile(WriteCallback callback) { +void CdmFileImpl::DeleteFile() { DVLOG(3) << __func__; DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(file_locked_); + DCHECK(!file_writer_); + DCHECK(write_callback_); storage::FileSystemURL file_url = CreateFileSystemURL(file_name_); storage::AsyncFileUtil* file_util = file_system_context_->GetAsyncFileUtil( @@ -547,25 +631,26 @@ DVLOG(3) << "Deleting " << file_url.DebugString(); file_util->DeleteFile( std::move(operation_context), file_url, - base::BindOnce(&CdmFileImpl::OnFileDeleted, weak_factory_.GetWeakPtr(), - std::move(callback))); + base::BindOnce(&CdmFileImpl::OnFileDeleted, weak_factory_.GetWeakPtr())); } -void CdmFileImpl::OnFileDeleted(WriteCallback callback, - base::File::Error result) { - DVLOG(3) << __func__; +void CdmFileImpl::OnFileDeleted(base::File::Error result) { + DVLOG(3) << __func__ << " file: " << file_name_ + << ", result: " << base::File::ErrorToString(result); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(file_locked_); + DCHECK(!file_writer_); + DCHECK(write_callback_); if (result != base::File::FILE_OK && result != base::File::FILE_ERROR_NOT_FOUND) { DLOG(WARNING) << "Unable to delete file " << file_name_ << ", error: " << base::File::ErrorToString(result); - std::move(callback).Run(Status::kFailure); + std::move(write_callback_).Run(Status::kFailure); return; } - std::move(callback).Run(Status::kSuccess); + std::move(write_callback_).Run(Status::kSuccess); } storage::FileSystemURL CdmFileImpl::CreateFileSystemURL(
diff --git a/content/browser/media/cdm_file_impl.h b/content/browser/media/cdm_file_impl.h index 5eeb5f81..3bb43a7 100644 --- a/content/browser/media/cdm_file_impl.h +++ b/content/browser/media/cdm_file_impl.h
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/threading/sequence_bound.h" #include "base/threading/thread_checker.h" #include "media/mojo/interfaces/cdm_storage.mojom.h" #include "storage/browser/fileapi/async_file_util.h" @@ -51,33 +52,26 @@ private: class FileReader; - - using CreateOrOpenCallback = storage::AsyncFileUtil::CreateOrOpenCallback; - - // Open the file |file_name| using the flags provided in |file_flags|. - // |callback| is called with the result. - void OpenFile(const std::string& file_name, - uint32_t file_flags, - CreateOrOpenCallback callback); + class FileWriter; // Called when the file is read. If |success| is true, |data| is the contents // of the file read. void ReadDone(bool success, std::vector<uint8_t> data); - // Called when |temp_file_name_| has been opened for writing. Writes - // |data| to |file|, closes |file|, and then kicks off a rename of - // |temp_file_name_| to |file_name_|, effectively replacing the contents of - // the old file. - void OnTempFileOpenedForWriting(std::vector<uint8_t> data, - WriteCallback callback, - base::File file, - base::OnceClosure on_close_callback); - void OnFileWritten(WriteCallback callback, Status status); - void OnFileRenamed(WriteCallback callback, base::File::Error move_result); + // Called in sequence to write the file. |buffer| is the contents to be + // written to the file, |bytes_to_write| is the length. Uses |file_writer_|, + // which is cleared when no longer needed. |write_callback_| will always be + // called with the result. + void OnEnsureFileExists(scoped_refptr<net::IOBuffer> buffer, + int bytes_to_write, + base::File::Error result, + bool created); + void WriteDone(bool success); + void OnFileRenamed(base::File::Error move_result); // Deletes |file_name_| asynchronously. - void DeleteFile(WriteCallback callback); - void OnFileDeleted(WriteCallback callback, base::File::Error result); + void DeleteFile(); + void OnFileDeleted(base::File::Error result); // Returns the FileSystemURL for the specified |file_name|. storage::FileSystemURL CreateFileSystemURL(const std::string& file_name); @@ -107,7 +101,11 @@ // Used when reading the file. |file_reader_| lives on the IO thread. ReadCallback read_callback_; - std::unique_ptr<FileReader> file_reader_; + base::SequenceBound<FileReader> file_reader_; + + // Used when writing the file. |file_writer_| lives on the IO thread. + WriteCallback write_callback_; + base::SequenceBound<FileWriter> file_writer_; THREAD_CHECKER(thread_checker_); base::WeakPtrFactory<CdmFileImpl> weak_factory_{this};
diff --git a/content/browser/media/hardware_key_media_controller.h b/content/browser/media/hardware_key_media_controller.h index 2f0a491f..0aafea6 100644 --- a/content/browser/media/hardware_key_media_controller.h +++ b/content/browser/media/hardware_key_media_controller.h
@@ -40,6 +40,8 @@ override; void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override {} + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} // ui::MediaKeysListener::Delegate: void OnMediaKeysAccelerator(const ui::Accelerator& accelerator) override;
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc index 5c029100..372e80ef 100644 --- a/content/browser/media/media_web_contents_observer.cc +++ b/content/browser/media/media_web_contents_observer.cc
@@ -16,6 +16,7 @@ #include "ipc/ipc_message_macros.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "services/device/public/mojom/wake_lock_context.mojom.h" +#include "services/media_session/public/cpp/media_position.h" #include "third_party/blink/public/platform/web_fullscreen_video_status.h" #include "ui/gfx/geometry/size.h" @@ -139,6 +140,8 @@ OnMediaPlaying) IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnMutedStatusChanged, OnMediaMutedStatusChanged) + IPC_MESSAGE_HANDLER(MediaPlayerDelegateHostMsg_OnMediaPositionStateChanged, + OnMediaPositionStateChanged); IPC_MESSAGE_HANDLER( MediaPlayerDelegateHostMsg_OnMediaEffectivelyFullscreenChanged, OnMediaEffectivelyFullscreenChanged) @@ -333,6 +336,14 @@ web_contents_impl()->MediaMutedStatusChanged(id, muted); } +void MediaWebContentsObserver::OnMediaPositionStateChanged( + RenderFrameHost* render_frame_host, + int delegate_id, + const media_session::MediaPosition& position) { + const MediaPlayerId id(render_frame_host, delegate_id); + session_controllers_manager_.OnMediaPositionStateChanged(id, position); +} + void MediaWebContentsObserver::AddMediaPlayerEntry( const MediaPlayerId& id, ActiveMediaPlayerMap* player_map) {
diff --git a/content/browser/media/media_web_contents_observer.h b/content/browser/media/media_web_contents_observer.h index 5bdf7d61..cc9fbf4 100644 --- a/content/browser/media/media_web_contents_observer.h +++ b/content/browser/media/media_web_contents_observer.h
@@ -31,6 +31,10 @@ enum class MediaContentType; } // namespace media +namespace media_session { +struct MediaPosition; +} // namespace media_session + namespace gfx { class Size; } // namespace size @@ -126,6 +130,10 @@ void OnMediaMutedStatusChanged(RenderFrameHost* render_frame_host, int delegate_id, bool muted); + void OnMediaPositionStateChanged( + RenderFrameHost* render_frame_host, + int delegate_id, + const media_session::MediaPosition& position); // Clear |render_frame_host|'s tracking entry for its WakeLocks. void ClearWakeLocks(RenderFrameHost* render_frame_host);
diff --git a/content/browser/media/mpris_notifier.h b/content/browser/media/mpris_notifier.h index eebb851..8813ed1 100644 --- a/content/browser/media/mpris_notifier.h +++ b/content/browser/media/mpris_notifier.h
@@ -46,6 +46,8 @@ override {} void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override {} + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} void SetMprisServiceForTesting(mpris::MprisService* service) { service_ = service;
diff --git a/content/browser/media/now_playing_info_center_notifier.h b/content/browser/media/now_playing_info_center_notifier.h index 7a9d9ca..9eb9d7e 100644 --- a/content/browser/media/now_playing_info_center_notifier.h +++ b/content/browser/media/now_playing_info_center_notifier.h
@@ -45,6 +45,8 @@ override {} void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override {} + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} private: // Our connection to the underlying OS API for MPNowPlayingInfoCenter.
diff --git a/content/browser/media/session/media_session_android.h b/content/browser/media/session/media_session_android.h index 655a292..ad0d324 100644 --- a/content/browser/media/session/media_session_android.h +++ b/content/browser/media/session/media_session_android.h
@@ -45,6 +45,8 @@ const base::flat_map<media_session::mojom::MediaSessionImageType, std::vector<media_session::MediaImage>>& images) override; + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} // MediaSession method wrappers. void Resume(JNIEnv* env, const base::android::JavaParamRef<jobject>& j_obj);
diff --git a/content/browser/media/session/media_session_controller.cc b/content/browser/media/session/media_session_controller.cc index 92ca3a1..5e2b26c 100644 --- a/content/browser/media/session/media_session_controller.cc +++ b/content/browser/media/session/media_session_controller.cc
@@ -31,12 +31,16 @@ bool MediaSessionController::Initialize( bool has_audio, bool is_remote, - media::MediaContentType media_content_type) { + media::MediaContentType media_content_type, + media_session::MediaPosition* position) { // Store these as we will need them later. is_remote_ = is_remote; has_audio_ = has_audio; media_content_type_ = media_content_type; + if (position) + position_ = *position; + // Don't generate a new id if one has already been set. if (!has_session_) { // These objects are only created on the UI thread, so this is safe. @@ -144,4 +148,12 @@ } } +void MediaSessionController::OnMediaPositionStateChanged( + const media_session::MediaPosition& position) { + position_ = position; + + // TODO(https://crbug.com/985394): Notify MediaSessionImpl that the + // position state has changed. +} + } // namespace content
diff --git a/content/browser/media/session/media_session_controller.h b/content/browser/media/session/media_session_controller.h index a619c57..9415005 100644 --- a/content/browser/media/session/media_session_controller.h +++ b/content/browser/media/session/media_session_controller.h
@@ -6,12 +6,14 @@ #define CONTENT_BROWSER_MEDIA_SESSION_MEDIA_SESSION_CONTROLLER_H_ #include "base/compiler_specific.h" +#include "base/optional.h" #include "base/time/time.h" #include "content/browser/media/session/media_session_player_observer.h" #include "content/common/content_export.h" #include "content/public/browser/media_player_id.h" #include "content/public/browser/web_contents_observer.h" #include "media/base/media_content_type.h" +#include "services/media_session/public/cpp/media_position.h" namespace content { @@ -38,7 +40,8 @@ // the BrowserMediaPlayerManagers. Tracked by http://crbug.com/580626 bool Initialize(bool has_audio, bool is_remote, - media::MediaContentType media_content_type); + media::MediaContentType media_content_type, + media_session::MediaPosition* position); // Must be called when a pause occurs on the renderer side media player; keeps // the MediaSession instance in sync with renderer side behavior. @@ -54,10 +57,18 @@ // Test helpers. int get_player_id_for_testing() const { return player_id_; } + const base::Optional<media_session::MediaPosition>& get_position_for_testing() + const { + return position_; + } // Called when the WebContents is either muted or unmuted. void WebContentsMutedStateChanged(bool muted); + // Called when the media position state of the player has changed. + void OnMediaPositionStateChanged( + const media_session::MediaPosition& position); + private: const MediaPlayerId id_; @@ -67,6 +78,8 @@ // Non-owned pointer; lifetime is the same as |media_web_contents_observer_|. MediaSessionImpl* const media_session_; + base::Optional<media_session::MediaPosition> position_; + int player_id_ = 0; bool has_session_ = false; bool has_audio_ = false;
diff --git a/content/browser/media/session/media_session_controller_unittest.cc b/content/browser/media/session/media_session_controller_unittest.cc index 5653bf1..6585ce20 100644 --- a/content/browser/media/session/media_session_controller_unittest.cc +++ b/content/browser/media/session/media_session_controller_unittest.cc
@@ -153,29 +153,29 @@ }; TEST_F(MediaSessionControllerTest, NoAudioNoSession) { - ASSERT_TRUE(controller_->Initialize(false, false, - media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + false, false, media::MediaContentType::Persistent, nullptr)); EXPECT_FALSE(media_session()->IsActive()); EXPECT_FALSE(media_session()->IsControllable()); } TEST_F(MediaSessionControllerTest, IsRemoteNoSession) { - ASSERT_TRUE( - controller_->Initialize(true, true, media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + true, true, media::MediaContentType::Persistent, nullptr)); EXPECT_FALSE(media_session()->IsActive()); EXPECT_FALSE(media_session()->IsControllable()); } TEST_F(MediaSessionControllerTest, TransientNoControllableSession) { - ASSERT_TRUE( - controller_->Initialize(true, false, media::MediaContentType::Transient)); + ASSERT_TRUE(controller_->Initialize( + true, false, media::MediaContentType::Transient, nullptr)); EXPECT_TRUE(media_session()->IsActive()); EXPECT_FALSE(media_session()->IsControllable()); } TEST_F(MediaSessionControllerTest, BasicControls) { - ASSERT_TRUE(controller_->Initialize(true, false, - media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + true, false, media::MediaContentType::Persistent, nullptr)); EXPECT_TRUE(media_session()->IsActive()); EXPECT_TRUE(media_session()->IsControllable()); @@ -205,8 +205,8 @@ } TEST_F(MediaSessionControllerTest, VolumeMultiplier) { - ASSERT_TRUE(controller_->Initialize(true, false, - media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + true, false, media::MediaContentType::Persistent, nullptr)); EXPECT_TRUE(media_session()->IsActive()); EXPECT_TRUE(media_session()->IsControllable()); @@ -222,8 +222,8 @@ } TEST_F(MediaSessionControllerTest, ControllerSidePause) { - ASSERT_TRUE(controller_->Initialize(true, false, - media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + true, false, media::MediaContentType::Persistent, nullptr)); EXPECT_TRUE(media_session()->IsActive()); EXPECT_TRUE(media_session()->IsControllable()); @@ -233,28 +233,28 @@ EXPECT_TRUE(media_session()->IsControllable()); // Verify the next Initialize() call restores the session. - ASSERT_TRUE(controller_->Initialize(true, false, - media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + true, false, media::MediaContentType::Persistent, nullptr)); EXPECT_TRUE(media_session()->IsActive()); EXPECT_TRUE(media_session()->IsControllable()); } TEST_F(MediaSessionControllerTest, Reinitialize) { - ASSERT_TRUE(controller_->Initialize(false, false, - media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + false, false, media::MediaContentType::Persistent, nullptr)); EXPECT_FALSE(media_session()->IsActive()); EXPECT_FALSE(media_session()->IsControllable()); // Create a transient type session. - ASSERT_TRUE( - controller_->Initialize(true, false, media::MediaContentType::Transient)); + ASSERT_TRUE(controller_->Initialize( + true, false, media::MediaContentType::Transient, nullptr)); EXPECT_TRUE(media_session()->IsActive()); EXPECT_FALSE(media_session()->IsControllable()); const int current_player_id = controller_->get_player_id_for_testing(); // Reinitialize the session as a content type. - ASSERT_TRUE(controller_->Initialize(true, false, - media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + true, false, media::MediaContentType::Persistent, nullptr)); EXPECT_TRUE(media_session()->IsActive()); EXPECT_TRUE(media_session()->IsControllable()); // Player id should not change when there's an active session. @@ -272,18 +272,39 @@ // Attempt to switch to no audio player, which should do nothing. // TODO(dalecurtis): Delete this test once we're no longer using WMPA and // the BrowserMediaPlayerManagers. Tracked by http://crbug.com/580626 - ASSERT_TRUE(controller_->Initialize(false, false, - media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + false, false, media::MediaContentType::Persistent, nullptr)); EXPECT_TRUE(media_session()->IsActive()); EXPECT_TRUE(media_session()->IsControllable()); EXPECT_EQ(current_player_id, controller_->get_player_id_for_testing()); // Switch to a remote player, which should release the session. - ASSERT_TRUE( - controller_->Initialize(true, true, media::MediaContentType::Persistent)); + ASSERT_TRUE(controller_->Initialize( + true, true, media::MediaContentType::Persistent, nullptr)); EXPECT_FALSE(media_session()->IsActive()); EXPECT_FALSE(media_session()->IsControllable()); EXPECT_EQ(current_player_id, controller_->get_player_id_for_testing()); } +TEST_F(MediaSessionControllerTest, PositionState) { + { + media_session::MediaPosition expected_position(1.0, base::TimeDelta(), + base::TimeDelta()); + + ASSERT_TRUE(controller_->Initialize( + true, true, media::MediaContentType::Persistent, &expected_position)); + + EXPECT_EQ(expected_position, controller_->get_position_for_testing()); + } + + { + media_session::MediaPosition expected_position( + 0.0, base::TimeDelta::FromSeconds(10), base::TimeDelta()); + + controller_->OnMediaPositionStateChanged(expected_position); + + EXPECT_EQ(expected_position, controller_->get_position_for_testing()); + } +} + } // namespace content
diff --git a/content/browser/media/session/media_session_controllers_manager.cc b/content/browser/media/session/media_session_controllers_manager.cc index 5ab217ff..5d3edf8 100644 --- a/content/browser/media/session/media_session_controllers_manager.cc +++ b/content/browser/media/session/media_session_controllers_manager.cc
@@ -4,6 +4,7 @@ #include "content/browser/media/session/media_session_controllers_manager.h" +#include "base/stl_util.h" #include "content/browser/media/session/media_session_controller.h" #include "media/base/media_switches.h" #include "services/media_session/public/cpp/features.h" @@ -47,6 +48,13 @@ if (!IsMediaSessionEnabled()) return true; + // If we have previously received the position for this player then we should + // initialize the controller with it. + media_session::MediaPosition* position = nullptr; + auto position_it = position_map_.find(id); + if (position_it != position_map_.end()) + position = &position_it->second; + // Since we don't remove session instances on pause, there may be an existing // instance for this playback attempt. // @@ -55,8 +63,11 @@ // controller. A later playback attempt will create a new controller. auto it = controllers_map_.find(id); if (it != controllers_map_.end()) { - if (it->second->Initialize(has_audio, is_remote, media_content_type)) + if (it->second->Initialize(has_audio, is_remote, media_content_type, + position)) { return true; + } + controllers_map_.erase(it); return false; } @@ -64,8 +75,10 @@ std::unique_ptr<MediaSessionController> controller( new MediaSessionController(id, media_web_contents_observer_)); - if (!controller->Initialize(has_audio, is_remote, media_content_type)) + if (!controller->Initialize(has_audio, is_remote, media_content_type, + position)) { return false; + } controllers_map_[id] = std::move(controller); return true; @@ -88,6 +101,21 @@ controllers_map_.erase(id); } +void MediaSessionControllersManager::OnMediaPositionStateChanged( + const MediaPlayerId& id, + const media_session::MediaPosition& position) { + if (!IsMediaSessionEnabled()) + return; + + base::InsertOrAssign(position_map_, id, position); + + auto it = controllers_map_.find(id); + if (it == controllers_map_.end()) + return; + + it->second->OnMediaPositionStateChanged(position); +} + void MediaSessionControllersManager::WebContentsMutedStateChanged(bool muted) { if (!IsMediaSessionEnabled()) return;
diff --git a/content/browser/media/session/media_session_controllers_manager.h b/content/browser/media/session/media_session_controllers_manager.h index ed8aaac6..d294ace6 100644 --- a/content/browser/media/session/media_session_controllers_manager.h +++ b/content/browser/media/session/media_session_controllers_manager.h
@@ -18,6 +18,10 @@ enum class MediaContentType; } // namespace media +namespace media_session { +struct MediaPosition; +} // namespace media_session + namespace content { class MediaSessionController; @@ -30,6 +34,7 @@ public: using ControllersMap = std::map<MediaPlayerId, std::unique_ptr<MediaSessionController>>; + using PositionMap = std::map<MediaPlayerId, media_session::MediaPosition>; explicit MediaSessionControllersManager( MediaWebContentsObserver* media_web_contents_observer); @@ -53,6 +58,11 @@ // Called when the given player |id| has ended. void OnEnd(const MediaPlayerId& id); + // Called when the media position state for the player |id| has changed. + void OnMediaPositionStateChanged( + const MediaPlayerId& id, + const media_session::MediaPosition& position); + // Called when the WebContents was muted or unmuted. void WebContentsMutedStateChanged(bool muted); @@ -64,6 +74,10 @@ ControllersMap controllers_map_; + // Stores the last position for each player. This is because a controller + // may be created after we have already received the position state. + PositionMap position_map_; + DISALLOW_COPY_AND_ASSIGN(MediaSessionControllersManager); };
diff --git a/content/browser/media/session/media_session_controllers_manager_unittest.cc b/content/browser/media/session/media_session_controllers_manager_unittest.cc index 0dbd9e1..55b56d3 100644 --- a/content/browser/media/session/media_session_controllers_manager_unittest.cc +++ b/content/browser/media/session/media_session_controllers_manager_unittest.cc
@@ -96,6 +96,12 @@ return &manager_->controllers_map_; } + MediaSessionController* GetController(const MediaPlayerId& id) { + auto it = manager_->controllers_map_.find(id); + DCHECK(it != manager_->controllers_map_.end()); + return it->second.get(); + } + void TearDown() override { manager_.reset(); service_manager_context_.reset(); @@ -214,6 +220,94 @@ } } +TEST_P(MediaSessionControllersManagerTest, PositionState) { + // If not enabled, no adds will occur, as RequestPlay returns early. + if (!IsMediaSessionEnabled()) + return; + + { + media_session::MediaPosition expected_position(1.0, base::TimeDelta(), + base::TimeDelta()); + + manager_->OnMediaPositionStateChanged(media_player_id_, expected_position); + + EXPECT_TRUE(manager_->RequestPlay(media_player_id_, true, false, + media::MediaContentType::Transient)); + EXPECT_EQ(1U, GetControllersMap()->size()); + + // The controller should be created with the last received position for + // that player. + EXPECT_EQ(expected_position, + GetController(media_player_id_)->get_position_for_testing()); + } + + { + media_session::MediaPosition expected_position( + 0.0, base::TimeDelta::FromSeconds(10), base::TimeDelta()); + + manager_->OnMediaPositionStateChanged(media_player_id_, expected_position); + + // The controller should be updated with the new position. + EXPECT_EQ(expected_position, + GetController(media_player_id_)->get_position_for_testing()); + + // Destroy the current controller. + manager_->OnEnd(media_player_id_); + EXPECT_TRUE(GetControllersMap()->empty()); + + // Recreate the current controller. + EXPECT_TRUE(manager_->RequestPlay(media_player_id_, true, false, + media::MediaContentType::Transient)); + EXPECT_EQ(1U, GetControllersMap()->size()); + + // The controller should be created with the last received position for + // that player. + EXPECT_EQ(expected_position, + GetController(media_player_id_)->get_position_for_testing()); + } +} + +TEST_P(MediaSessionControllersManagerTest, MultiplePlayersWithPositionState) { + // If not enabled, no adds will occur, as RequestPlay returns early. + if (!IsMediaSessionEnabled()) + return; + + MediaPlayerId media_player_id_2 = + MediaPlayerId(contents()->GetMainFrame(), 2); + + media_session::MediaPosition expected_position1(1.0, base::TimeDelta(), + base::TimeDelta()); + media_session::MediaPosition expected_position2( + 0.0, base::TimeDelta::FromSeconds(10), base::TimeDelta()); + + manager_->OnMediaPositionStateChanged(media_player_id_, expected_position1); + manager_->OnMediaPositionStateChanged(media_player_id_2, expected_position2); + + EXPECT_TRUE(manager_->RequestPlay(media_player_id_, true, false, + media::MediaContentType::Transient)); + EXPECT_TRUE(manager_->RequestPlay(media_player_id_2, true, false, + media::MediaContentType::Transient)); + + EXPECT_EQ(2U, GetControllersMap()->size()); + + // The controllers should have been created with the correct positions. + EXPECT_EQ(expected_position1, + GetController(media_player_id_)->get_position_for_testing()); + EXPECT_EQ(expected_position2, + GetController(media_player_id_2)->get_position_for_testing()); + + media_session::MediaPosition new_position( + 0.0, base::TimeDelta::FromSeconds(20), base::TimeDelta()); + + manager_->OnMediaPositionStateChanged(media_player_id_, new_position); + + // The controller should be updated with the new position. + EXPECT_EQ(new_position, + GetController(media_player_id_)->get_position_for_testing()); + EXPECT_EQ(expected_position2, + GetController(media_player_id_2)->get_position_for_testing()); +} + // First bool is to indicate whether InternalMediaSession is enabled. // Second bool is to indicate whether AudioFocus is enabled. INSTANTIATE_TEST_SUITE_P(MediaSessionEnabledTestInstances,
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc index b64df45..3176e47 100644 --- a/content/browser/media/session/media_session_impl.cc +++ b/content/browser/media/session/media_session_impl.cc
@@ -847,6 +847,13 @@ std::vector<media_session::mojom::MediaSessionAction> actions( actions_.begin(), actions_.end()); media_session_observer->MediaSessionActionsChanged(actions); + + // TODO(crbug.com/985394): Use real position data here, this is mock data. + media_session::MediaPosition media_position( + 1 /* playback_rate */, base::TimeDelta::FromSeconds(600) /* duration */, + base::TimeDelta::FromSeconds(300) /* position */); + media_session_observer->MediaSessionPositionChanged(media_position); + observers_.Add(std::move(media_session_observer)); }
diff --git a/content/browser/media/session/media_session_impl_service_routing_unittest.cc b/content/browser/media/session/media_session_impl_service_routing_unittest.cc index 53f48e8..31504f5a 100644 --- a/content/browser/media/session/media_session_impl_service_routing_unittest.cc +++ b/content/browser/media/session/media_session_impl_service_routing_unittest.cc
@@ -274,6 +274,14 @@ ASSERT_EQ(services_[sub_frame_].get(), ComputeServiceForRouting()); } +TEST_F(MediaSessionImplServiceRoutingTest, NotifyMockPositionData) { + media_session::test::MockMediaSessionMojoObserver observer( + *GetMediaSession()); + + // Verify that the default/mock position data is received by the observer. + observer.WaitForNonEmptyPosition(); +} + TEST_F(MediaSessionImplServiceRoutingTest, DontNotifyMetadataAndActionsChangeWhenUncontrollable) { media_session::test::MockMediaSessionMojoObserver observer(
diff --git a/content/browser/media/system_media_controls_notifier.h b/content/browser/media/system_media_controls_notifier.h index e5cd260..c403ea9 100644 --- a/content/browser/media/system_media_controls_notifier.h +++ b/content/browser/media/system_media_controls_notifier.h
@@ -48,6 +48,8 @@ override {} void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override {} + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override {} // media_session::mojom::MediaControllerImageObserver implementation. void MediaControllerImageChanged(
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc index 4e8448e..6e06e063 100644 --- a/content/browser/navigation_browsertest.cc +++ b/content/browser/navigation_browsertest.cc
@@ -1726,8 +1726,10 @@ popup, "window.opener.location ='data:html/text;base64,'+btoa('payload');")); observer.WaitForFinished(); + + // Implies NavigationDownloadType::kOpenerCrossOrigin has 0 count. histograms.ExpectUniqueSample("Navigation.DownloadPolicy.LogPerPolicyApplied", - NavigationDownloadType::kDefaultAllow, 1); + NavigationDownloadType::kNoGesture, 1); } // A variation of the OpenerNavigation_DownloadPolicy test above, but uses a @@ -1779,7 +1781,7 @@ // boolean before the navigation turns into a download. Just expect metrics // when the network service is enabled. if (base::FeatureList::IsEnabled(network::features::kNetworkService)) { - histograms.ExpectUniqueSample( + histograms.ExpectBucketCount( "Navigation.DownloadPolicy.LogPerPolicyApplied", NavigationDownloadType::kOpenerCrossOrigin, 1); }
diff --git a/content/browser/renderer_host/OWNERS b/content/browser/renderer_host/OWNERS index 16fba62..e566b73 100644 --- a/content/browser/renderer_host/OWNERS +++ b/content/browser/renderer_host/OWNERS
@@ -31,7 +31,6 @@ # Embedded Frame Sinks (eg. Offscreen Canvas) per-file embedded_frame_sink*.*=xlai@chromium.org -per-file embedded_frame_sink*.*=xidachen@chromium.org per-file embedded_frame_sink*.*=junov@chromium.org per-file embedded_frame_sink*.*=kylechar@chromium.org
diff --git a/content/browser/renderer_host/render_widget_targeter.cc b/content/browser/renderer_host/render_widget_targeter.cc index 2e13ade..3024a12 100644 --- a/content/browser/renderer_host/render_widget_targeter.cc +++ b/content/browser/renderer_host/render_widget_targeter.cc
@@ -5,8 +5,6 @@ #include "content/browser/renderer_host/render_widget_targeter.h" #include "base/bind.h" -#include "base/debug/crash_logging.h" -#include "base/debug/dump_without_crashing.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" @@ -14,11 +12,8 @@ #include "components/viz/host/host_frame_sink_manager.h" #include "content/browser/compositor/surface_utils.h" #include "content/browser/renderer_host/input/one_shot_timeout_monitor.h" -#include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/browser/renderer_host/render_widget_host_view_base.h" -#include "content/browser/scoped_active_url.h" -#include "content/public/browser/render_frame_host.h" #include "content/public/browser/site_isolation_policy.h" #include "third_party/blink/public/platform/web_input_event.h" #include "ui/events/blink/blink_event_util.h" @@ -45,33 +40,6 @@ constexpr const char kTracingCategory[] = "input,latency"; -// This function helps with debugging the reasons of viz hit testing mismatch. -void DumpWithoutCrashing(RenderWidgetHostViewBase* root_view, - RenderWidgetHostViewBase* target, - const base::Optional<gfx::PointF>& target_location) { - RenderViewHostImpl* rvh = - RenderViewHostImpl::From(root_view->GetRenderWidgetHost()); - if (!rvh || !rvh->GetMainFrame()) - return; - ScopedActiveURL scoped_active_url(rvh); - - static auto* crash_key = base::debug::AllocateCrashKeyString( - "vizhittest-mismatch-v2-coordinate", base::debug::CrashKeySize::Size32); - const std::string global_coordinate = - target->TransformPointToRootCoordSpaceF(target_location.value()) - .ToString(); - base::debug::SetCrashKeyString(crash_key, global_coordinate); - - crash_key = base::debug::AllocateCrashKeyString( - "vizhittest-mismatch-v2-viewport-size", - base::debug::CrashKeySize::Size32); - const std::string viewport_size = - root_view->GetVisibleViewportSize().ToString(); - base::debug::SetCrashKeyString(crash_key, viewport_size); - - base::debug::DumpWithoutCrashing(); -} - } // namespace class TracingUmaTracker { @@ -88,11 +56,11 @@ TracingUmaTracker(TracingUmaTracker&& tracker) = default; void StopAndRecord() { - Stop(); + StopButNotRecord(); UmaHistogramTimes(metric_name_, base::TimeTicks::Now() - start_time_); } - void Stop() { + void StopButNotRecord() { TRACE_EVENT_ASYNC_END0( kTracingCategory, metric_name_, TRACE_ID_WITH_SCOPE("UmaTracker", TRACE_ID_LOCAL(id_))); @@ -192,7 +160,7 @@ void RenderWidgetTargeter::TargetingRequest::StopQueueingTimeTracker() { if (tracker) - tracker->Stop(); + tracker->StopAndRecord(); } bool RenderWidgetTargeter::TargetingRequest::IsWebInputEventRequest() const { @@ -432,7 +400,7 @@ const viz::FrameSinkId& frame_sink_id, const gfx::PointF& transformed_location) { if (is_verification_request) { - tracker.Stop(); + tracker.StopButNotRecord(); } else { tracker.StopAndRecord(); } @@ -545,7 +513,6 @@ // If the result did not change, it is likely that viz hit test finds // the wrong target. match_result = HitTestResultsMatch::kDoNotMatch; - DumpWithoutCrashing(request->GetRootView(), target, target_location); } else { // Hit test data changed, so the result is no longer reliable. match_result = HitTestResultsMatch::kHitTestResultChanged;
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc index fc8b53d..6f253f93 100644 --- a/content/browser/service_worker/embedded_worker_instance.cc +++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -780,7 +780,7 @@ blink::mojom::EmbeddedWorkerStartParamsPtr params) { DCHECK(context_); DCHECK(params->service_worker_request.is_pending()); - DCHECK(params->controller_request.is_pending()); + DCHECK(params->controller_receiver.is_valid()); DCHECK(!instance_host_binding_.is_bound()); instance_host_binding_.Bind(mojo::MakeRequest(¶ms->instance_host));
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc index 9357e7a..ee994583 100644 --- a/content/browser/service_worker/embedded_worker_instance_unittest.cc +++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -27,6 +27,8 @@ #include "content/public/common/child_process_host.h" #include "content/public/common/content_switches.h" #include "content/public/test/test_browser_thread_bundle.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -163,7 +165,7 @@ params->is_installed = false; params->service_worker_request = CreateServiceWorker(); - params->controller_request = CreateController(); + params->controller_receiver = CreateController(); params->installed_scripts_info = GetInstalledScriptsInfoPtr(); params->provider_info = CreateProviderInfo(std::move(version)); return params; @@ -183,9 +185,10 @@ return mojo::MakeRequest(&service_workers_.back()); } - blink::mojom::ControllerServiceWorkerRequest CreateController() { + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> + CreateController() { controllers_.emplace_back(); - return mojo::MakeRequest(&controllers_.back()); + return controllers_.back().BindNewPipeAndPassReceiver(); } void SetWorkerStatus(EmbeddedWorkerInstance* worker, @@ -208,7 +211,7 @@ // Mojo endpoints. std::vector<blink::mojom::ServiceWorkerPtr> service_workers_; - std::vector<blink::mojom::ControllerServiceWorkerPtr> controllers_; + std::vector<mojo::Remote<blink::mojom::ControllerServiceWorker>> controllers_; std::vector<blink::mojom::ServiceWorkerInstalledScriptsManagerPtr> installed_scripts_managers_; std::vector<blink::mojom::ServiceWorkerInstalledScriptsManagerHostRequest>
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc index 3db775f6..8a9e819 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -215,7 +215,6 @@ base::BindRepeating(&ServiceWorkerContextWrapper::OnRegistrationUpdated, base::Unretained(this)), base::DoNothing(), base::DoNothing()); - watcher_->Start(); } } @@ -227,6 +226,8 @@ URLLoaderFactoryGetter* loader_factory_getter) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(storage_partition_); + if (watcher_) + watcher_->Start(); is_incognito_ = user_data_directory.empty(); // The database task runner is BLOCK_SHUTDOWN in order to support @@ -251,7 +252,7 @@ storage_partition_ = nullptr; process_manager_->Shutdown(); - if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) { + if (watcher_) { watcher_->Stop(); watcher_ = nullptr; }
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc index 94a1d2e..78900e0 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.cc +++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -169,13 +169,17 @@ SubresourceLoaderParams params; auto controller_info = blink::mojom::ControllerServiceWorkerInfo::New(); controller_info->mode = provider_host_->GetControllerMode(); - // Note that |controller_info->endpoint| is null if the controller has no - // fetch event handler. In that case the renderer frame won't get the + // Note that |controller_info->remote_controller| is null if the controller + // has no fetch event handler. In that case the renderer frame won't get the // controller pointer upon the navigation commit, and subresource loading will // not be intercepted. (It might get intercepted later if the controller // changes due to skipWaiting() so SetController is sent.) - controller_info->endpoint = - provider_host_->GetControllerServiceWorkerPtr().PassInterface(); + mojo::Remote<blink::mojom::ControllerServiceWorker> remote = + provider_host_->GetRemoteControllerServiceWorker(); + if (remote.is_bound()) { + controller_info->remote_controller = remote.Unbind(); + } + controller_info->client_id = provider_host_->client_uuid(); if (provider_host_->fetch_request_window_id()) { controller_info->fetch_request_window_id =
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.h b/content/browser/service_worker/service_worker_controllee_request_handler.h index c6917ee..02bbd1bc 100644 --- a/content/browser/service_worker/service_worker_controllee_request_handler.h +++ b/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -54,7 +54,7 @@ ResourceContext* resource_context, LoaderCallback callback, FallbackCallback fallback_callback) override; - // Returns params with the ControllerServiceWorkerPtr if we have found + // Returns params with the ControllerServiceWorkerInfoPtr if we have found // a matching controller service worker for the |request| that is given // to MaybeCreateLoader(). Otherwise this returns base::nullopt. base::Optional<SubresourceLoaderParams> MaybeCreateSubresourceLoaderParams()
diff --git a/content/browser/service_worker/service_worker_navigation_loader_interceptor.h b/content/browser/service_worker/service_worker_navigation_loader_interceptor.h index 9fa5afa..a3b6bce 100644 --- a/content/browser/service_worker/service_worker_navigation_loader_interceptor.h +++ b/content/browser/service_worker/service_worker_navigation_loader_interceptor.h
@@ -63,7 +63,7 @@ ResourceContext* resource_context, LoaderCallback callback, FallbackCallback fallback_callback) override; - // Returns params with the ControllerServiceWorkerPtr if we have found + // Returns params with the ControllerServiceWorkerInfoPtr if we have found // a matching controller service worker for the |request| that is given // to MaybeCreateLoader(). Otherwise this returns base::nullopt. base::Optional<SubresourceLoaderParams> MaybeCreateSubresourceLoaderParams()
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc index 432083a..51d4f0d 100644 --- a/content/browser/service_worker/service_worker_provider_host.cc +++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -366,16 +366,17 @@ UpdateController(true /* notify_controllerchange */); } -blink::mojom::ControllerServiceWorkerPtr -ServiceWorkerProviderHost::GetControllerServiceWorkerPtr() { +mojo::Remote<blink::mojom::ControllerServiceWorker> +ServiceWorkerProviderHost::GetRemoteControllerServiceWorker() { DCHECK(controller_); if (controller_->fetch_handler_existence() == ServiceWorkerVersion::FetchHandlerExistence::DOES_NOT_EXIST) { - return nullptr; + return mojo::Remote<blink::mojom::ControllerServiceWorker>(); } - blink::mojom::ControllerServiceWorkerPtr controller_ptr; - controller_->controller()->Clone(mojo::MakeRequest(&controller_ptr)); - return controller_ptr; + mojo::Remote<blink::mojom::ControllerServiceWorker> remote_controller; + controller_->controller()->Clone( + remote_controller.BindNewPipeAndPassReceiver()); + return remote_controller; } void ServiceWorkerProviderHost::UpdateUrls(const GURL& url, @@ -778,7 +779,11 @@ controller_info->mode = GetControllerMode(); // Pass an endpoint for the client to talk to this controller. - controller_info->endpoint = GetControllerServiceWorkerPtr().PassInterface(); + mojo::Remote<blink::mojom::ControllerServiceWorker> remote = + GetRemoteControllerServiceWorker(); + if (remote.is_bound()) { + controller_info->remote_controller = remote.Unbind(); + } // Set the info for the JavaScript ServiceWorkerContainer#controller object. base::WeakPtr<ServiceWorkerObjectHost> object_host = @@ -1129,14 +1134,14 @@ } void ServiceWorkerProviderHost::StartControllerComplete( - blink::mojom::ControllerServiceWorkerRequest controller_request, + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> receiver, blink::ServiceWorkerStatusCode status) { if (status == blink::ServiceWorkerStatusCode::kOk) - controller_->controller()->Clone(std::move(controller_request)); + controller_->controller()->Clone(std::move(receiver)); } void ServiceWorkerProviderHost::EnsureControllerServiceWorker( - blink::mojom::ControllerServiceWorkerRequest controller_request, + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> receiver, blink::mojom::ControllerServiceWorkerPurpose purpose) { // TODO(kinuko): Log the reasons we drop the request. if (!IsContextAlive() || !controller_) @@ -1145,7 +1150,7 @@ controller_->RunAfterStartWorker( PurposeToEventType(purpose), base::BindOnce(&ServiceWorkerProviderHost::StartControllerComplete, - AsWeakPtr(), std::move(controller_request))); + AsWeakPtr(), std::move(receiver))); } void ServiceWorkerProviderHost::CloneContainerHost(
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h index 1507692..f95b687 100644 --- a/content/browser/service_worker/service_worker_provider_host.h +++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -27,6 +27,8 @@ #include "mojo/public/cpp/bindings/associated_binding.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/remote.h" #include "services/network/public/mojom/fetch_api.mojom.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_container.mojom.h" @@ -229,7 +231,10 @@ // // TODO(kinuko): revisit this if we start to use the ControllerServiceWorker // for posting messages. - blink::mojom::ControllerServiceWorkerPtr GetControllerServiceWorkerPtr(); + // TODO(hayato): Return PendingRemote, instead of Remote. Binding to Remote + // as late as possible is more idiomatic for new Mojo types. + mojo::Remote<blink::mojom::ControllerServiceWorker> + GetRemoteControllerServiceWorker(); // For service worker clients. Sets |url_| and |site_for_cookies_| and updates // the client uuid if it's a cross-origin transition. @@ -494,7 +499,7 @@ void GetRegistrationForReady( GetRegistrationForReadyCallback callback) override; void EnsureControllerServiceWorker( - blink::mojom::ControllerServiceWorkerRequest controller_request, + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> receiver, blink::mojom::ControllerServiceWorkerPurpose purpose) override; void CloneContainerHost(blink::mojom::ServiceWorkerContainerHostRequest container_host_request) override; @@ -525,7 +530,7 @@ // Callback for ServiceWorkerVersion::RunAfterStartWorker() void StartControllerComplete( - blink::mojom::ControllerServiceWorkerRequest controller_request, + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> receiver, blink::ServiceWorkerStatusCode status); bool IsValidGetRegistrationMessage(const GURL& client_url,
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc index 7235a21..c11b6b2 100644 --- a/content/browser/service_worker/service_worker_version.cc +++ b/content/browser/service_worker/service_worker_version.cc
@@ -798,10 +798,22 @@ SetStatus(REDUNDANT); if (running_status() == EmbeddedWorkerStatus::STARTING || running_status() == EmbeddedWorkerStatus::RUNNING) { - if (embedded_worker()->devtools_attached()) - stop_when_devtools_detached_ = true; - else + // |start_worker_status_| == kErrorExists means that this version was + // created for update but the script was identical to the incumbent version. + // In this case we should stop the worker immediately even when DevTools is + // attached. Otherwise the redundant worker stays as a selectable context + // in DevTools' console. + // TODO(bashi): Remove this workaround when byte-for-byte update check is + // shipped. + bool stop_immediately = + base::FeatureList::IsEnabled( + blink::features::kOffMainThreadServiceWorkerScriptFetch) && + start_worker_status_ == blink::ServiceWorkerStatusCode::kErrorExists; + if (stop_immediately || !embedded_worker()->devtools_attached()) { embedded_worker_->Stop(); + } else { + stop_when_devtools_detached_ = true; + } } } @@ -1622,11 +1634,10 @@ if (!pause_after_download()) InitializeGlobalScope(); - if (!controller_request_.is_pending()) { - DCHECK(!controller_ptr_.is_bound()); - controller_request_ = mojo::MakeRequest(&controller_ptr_); + if (!controller_receiver_.is_valid()) { + controller_receiver_ = remote_controller_.BindNewPipeAndPassReceiver(); } - params->controller_request = std::move(controller_request_); + params->controller_receiver = std::move(controller_receiver_); params->provider_info = std::move(provider_info); @@ -1984,8 +1995,8 @@ request_timeouts_.clear(); external_request_uuid_to_request_id_.clear(); service_worker_ptr_.reset(); - controller_ptr_.reset(); - DCHECK(!controller_request_.is_pending()); + remote_controller_.reset(); + DCHECK(!controller_receiver_.is_valid()); installed_scripts_sender_.reset(); binding_.Close(); pending_external_requests_.clear();
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h index 36863e7..bc5b68a68 100644 --- a/content/browser/service_worker/service_worker_version.h +++ b/content/browser/service_worker/service_worker_version.h
@@ -39,6 +39,8 @@ #include "content/common/content_export.h" #include "ipc/ipc_message.h" #include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/remote.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "third_party/blink/public/common/origin_trials/trial_token_validator.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" @@ -343,11 +345,11 @@ // not running is a bit sketchy, maybe this should queue a task to check // if the pending request is pending too long? https://crbug.com/797222 blink::mojom::ControllerServiceWorker* controller() { - if (!controller_ptr_.is_bound()) { - DCHECK(!controller_request_.is_pending()); - controller_request_ = mojo::MakeRequest(&controller_ptr_); + if (!remote_controller_.is_bound()) { + DCHECK(!controller_receiver_.is_valid()); + controller_receiver_ = remote_controller_.BindNewPipeAndPassReceiver(); } - return controller_ptr_.get(); + return remote_controller_.get(); } // Adds and removes the specified host as a controllee of this service worker. @@ -843,11 +845,12 @@ blink::mojom::ServiceWorkerPtr service_worker_ptr_; // Connection to the controller service worker. - // |controller_request_| is non-null only when the |controller_ptr_| is + // |controller_receiver_| is non-null only when the |remote_controller_| is // requested before the worker is started, it is passed to the worker (and // becomes null) once it's started. - blink::mojom::ControllerServiceWorkerPtr controller_ptr_; - blink::mojom::ControllerServiceWorkerRequest controller_request_; + mojo::Remote<blink::mojom::ControllerServiceWorker> remote_controller_; + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> + controller_receiver_; std::unique_ptr<ServiceWorkerInstalledScriptsSender> installed_scripts_sender_;
diff --git a/content/browser/shape_detection/OWNERS b/content/browser/shape_detection/OWNERS new file mode 100644 index 0000000..aee8252f --- /dev/null +++ b/content/browser/shape_detection/OWNERS
@@ -0,0 +1,4 @@ +file://third_party/blink/renderer/modules/shapedetection/OWNERS + +# COMPONENT: Blink>ShapeDetection +# TEAM: device-dev@chromium.org
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc index abcb777ca..a805b110 100644 --- a/content/browser/site_instance_impl.cc +++ b/content/browser/site_instance_impl.cc
@@ -410,6 +410,20 @@ browsing_instance_->GetSiteAndLockForURL( url, /* allow_default_instance */ true, &site_url, &origin_lock); + // If this is a default SiteInstance and the BrowsingInstance gives us a + // non-default site URL even when we explicitly allow the default SiteInstance + // to be considered, then |url| does not belong in the same process as this + // SiteInstance. This can happen when the + // kProcessSharingWithDefaultSiteInstances feature is not enabled and the + // site URL is explicitly set on a SiteInstance for a URL that would normally + // be directed to the default SiteInstance (e.g. a site not requiring a + // dedicated process). This situation typically happens when the top-level + // frame is a site that should be in the default SiteInstance and the + // SiteInstance associated with that frame is initially a SiteInstance with + // no site URL set. + if (IsDefaultSiteInstance() && site_url != GetSiteURL()) + return true; + // Note that HasProcess() may return true if process_ is null, in // process-per-site cases where there's an existing process available. // We want to use such a process in the IsSuitableHost check, so we
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc index d0e14f25..a3e2fc3c 100644 --- a/content/browser/site_per_process_hit_test_browsertest.cc +++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -11,6 +11,7 @@ #include "base/stl_util.h" #include "base/task/post_task.h" #include "base/test/bind_test_util.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "base/test/test_timeouts.h" #include "build/build_config.h" @@ -2931,6 +2932,47 @@ EXPECT_FALSE(child_frame_monitor.EventWasReceived()); } +IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest, + RecordTimeInQueueMetric) { + GURL main_url(embedded_test_server()->GetURL( + "/frame_tree/page_with_masked_iframe.html")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + FrameTreeNode* root = web_contents()->GetFrameTree()->root(); + ASSERT_EQ(1U, root->child_count()); + + FrameTreeNode* child_node = root->child_at(0); + + RenderWidgetHostInputEventRouter* router = + web_contents()->GetInputEventRouter(); + + WaitForHitTestDataOrChildSurfaceReady(child_node->current_frame_host()); + + router->GetRenderWidgetTargeterForTests() + ->set_async_hit_test_timeout_delay_for_testing(base::TimeDelta()); + + RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>( + root->current_frame_host()->GetRenderWidgetHost()->GetView()); + + blink::WebMouseEvent child_event( + blink::WebInputEvent::kMouseDown, blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::GetStaticTimeStampForTests()); + child_event.button = blink::WebPointerProperties::Button::kLeft; + SetWebEventPositions(&child_event, gfx::Point(75, 75), root_view); + child_event.click_count = 1; + + base::HistogramTester tester; + + InputEventAckWaiter waiter(root_view->GetRenderWidgetHost(), + blink::WebInputEvent::kMouseDown); + // Need at least two events to generate a queue. + router->RouteMouseEvent(root_view, &child_event, ui::LatencyInfo()); + router->RouteMouseEvent(root_view, &child_event, ui::LatencyInfo()); + waiter.Wait(); + + tester.ExpectTotalCount("Event.AsyncTargeting.TimeInQueue", 1); +} + // Tooltips aren't used on Android, so no need to compile/run this test in that // case. #if !defined(OS_ANDROID)
diff --git a/content/browser/sms/sms_browsertest.cc b/content/browser/sms/sms_browsertest.cc index 041a0d7..527628e 100644 --- a/content/browser/sms/sms_browsertest.cc +++ b/content/browser/sms/sms_browsertest.cc
@@ -146,74 +146,53 @@ ASSERT_FALSE(provider->HasObservers()); } -IN_PROC_BROWSER_TEST_F(SmsBrowserTest, ReceiveMultiple) { +IN_PROC_BROWSER_TEST_F(SmsBrowserTest, AtMostOnePendingSmsRequest) { GURL url = GetTestUrl(nullptr, "simple_page.html"); NavigateToURL(shell(), url); shell()->web_contents()->SetDelegate(&delegate_); - auto* dialog1 = new NiceMock<MockSmsDialog>(); - auto* dialog2 = new NiceMock<MockSmsDialog>(); + auto* dialog = new NiceMock<MockSmsDialog>(); - base::OnceClosure on_continue_callback1; - base::OnceClosure on_continue_callback2; + base::OnceClosure on_continue_callback; EXPECT_CALL(delegate_, CreateSmsDialog()) - .WillOnce(Return(ByMove(base::WrapUnique(dialog1)))) - .WillOnce(Return(ByMove(base::WrapUnique(dialog2)))); + .WillOnce(Return(ByMove(base::WrapUnique(dialog)))); - EXPECT_CALL(*dialog1, Open(_, _, _)) - .WillOnce(Invoke([&on_continue_callback1](content::RenderFrameHost*, - base::OnceClosure on_continue, - base::OnceClosure on_cancel) { - on_continue_callback1 = std::move(on_continue); + EXPECT_CALL(*dialog, Open(_, _, _)) + .WillOnce(Invoke([&on_continue_callback](content::RenderFrameHost*, + base::OnceClosure on_continue, + base::OnceClosure on_cancel) { + on_continue_callback = std::move(on_continue); })); - EXPECT_CALL(*dialog2, Open(_, _, _)) - .WillOnce(Invoke([&on_continue_callback2](content::RenderFrameHost*, - base::OnceClosure on_continue, - base::OnceClosure on_cancel) { - on_continue_callback2 = std::move(on_continue); - })); - - EXPECT_CALL(*dialog1, EnableContinueButton()) - .WillOnce(Invoke([&on_continue_callback1]() { - std::move(on_continue_callback1).Run(); - })); - EXPECT_CALL(*dialog2, EnableContinueButton()) - .WillOnce(Invoke([&on_continue_callback2]() { - std::move(on_continue_callback2).Run(); + EXPECT_CALL(*dialog, EnableContinueButton()) + .WillOnce(Invoke([&on_continue_callback]() { + std::move(on_continue_callback).Run(); })); auto* provider = new NiceMock<MockSmsProvider>(); BrowserMainLoop::GetInstance()->SetSmsProviderForTesting( base::WrapUnique(provider)); - // Test that SMS content can retrieve multiple messages. std::string script = R"( - (async () => { - let sms1 = navigator.sms.receive(); - let sms2 = navigator.sms.receive(); - - let msg1 = await sms1; - let msg2 = await sms2; - - return [msg1.content, msg2.content]; - }) (); + navigator.sms.receive().then(({content}) => { first = content; }); + navigator.sms.receive().catch(e => e.name); )"; - EXPECT_CALL(*provider, Retrieve()) - .WillOnce(Invoke([&provider, &url]() { - provider->NotifyReceive(url::Origin::Create(url), "hello1"); - })) - .WillOnce(Invoke([&provider, &url]() { - provider->NotifyReceive(url::Origin::Create(url), "hello2"); - })); + base::RunLoop loop; - base::ListValue result = EvalJs(shell(), script).ExtractList(); - ASSERT_EQ(2u, result.GetList().size()); - EXPECT_EQ("hello1", result.GetList()[0].GetString()); - EXPECT_EQ("hello2", result.GetList()[1].GetString()); + EXPECT_CALL(*provider, Retrieve()).WillOnce(Invoke([&loop]() { + loop.Quit(); + })); + + EXPECT_EQ("AbortError", EvalJs(shell(), script)); + + loop.Run(); + + provider->NotifyReceive(url::Origin::Create(url), "hello"); + + EXPECT_EQ("hello", EvalJs(shell(), "first")); ASSERT_FALSE(provider->HasObservers()); }
diff --git a/content/browser/tracing/background_tracing_config_impl.cc b/content/browser/tracing/background_tracing_config_impl.cc index de6804f..86601fb 100644 --- a/content/browser/tracing/background_tracing_config_impl.cc +++ b/content/browser/tracing/background_tracing_config_impl.cc
@@ -8,6 +8,7 @@ #include <utility> #include "base/macros.h" +#include "base/metrics/histogram_macros.h" #include "base/process/process_handle.h" #include "base/system/sys_info.h" #include "base/values.h" @@ -270,8 +271,11 @@ size_t BackgroundTracingConfigImpl::GetTraceUploadLimitKb() const { #if defined(OS_ANDROID) - if (net::NetworkChangeNotifier::IsConnectionCellular( - net::NetworkChangeNotifier::GetConnectionType())) { + auto type = net::NetworkChangeNotifier::GetConnectionType(); + UMA_HISTOGRAM_ENUMERATION( + "Tracing.Background.NetworkConnectionTypeWhenUploaded", type, + net::NetworkChangeNotifier::CONNECTION_LAST + 1); + if (net::NetworkChangeNotifier::IsConnectionCellular(type)) { return upload_limit_network_kb_; } #endif @@ -521,8 +525,11 @@ return low_ram_buffer_size_kb_; } #if defined(OS_ANDROID) - if (net::NetworkChangeNotifier::IsConnectionCellular( - net::NetworkChangeNotifier::GetConnectionType())) { + auto type = net::NetworkChangeNotifier::GetConnectionType(); + UMA_HISTOGRAM_ENUMERATION( + "Tracing.Background.NetworkConnectionTypeWhenStarted", type, + net::NetworkChangeNotifier::CONNECTION_LAST + 1); + if (net::NetworkChangeNotifier::IsConnectionCellular(type)) { return mobile_network_buffer_size_kb_; } #endif
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc index 0a50495..85b12bc8 100644 --- a/content/browser/utility_process_host.cc +++ b/content/browser/utility_process_host.cc
@@ -225,7 +225,7 @@ UtilityProcessHost::~UtilityProcessHost() { DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (client_) + if (client_ && !in_process_thread_) client_->OnProcessTerminatedNormally(); }
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index eca62cc..26e06cc 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -1200,14 +1200,14 @@ base::test::ScopedFeatureList feature_list; }; -// See: http://crbug.com/983931 -#if defined(OS_ANDROID) -#define MAYBE_SplitCache DISABLED_SplitCache -#else -#define MAYBE_SplitCache SplitCache -#endif -IN_PROC_BROWSER_TEST_P(WebContentsSplitCacheBrowserTestEnabled, - MAYBE_SplitCache) { +IN_PROC_BROWSER_TEST_P(WebContentsSplitCacheBrowserTestEnabled, SplitCache) { + // This test will fail if there is no network service, as we fill the + // network isolation key in network::URLLoader only when there is network + // service. If split cache is enabled but the network isolation key is + // empty, then resources won't be cached. + if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) + return; + // Load a cacheable resource for the first time, and it's not cached. EXPECT_FALSE(TestResourceLoad(GenURL("a.com", "/title1.html"), GURL())); @@ -1270,14 +1270,15 @@ EXPECT_FALSE(TestResourceLoad(blank_url, GURL())); } -// See: http://crbug.com/983931 -#if defined(OS_ANDROID) -#define MAYBE_SplitCache DISABLED_SplitCache -#else -#define MAYBE_SplitCache SplitCache -#endif IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheWithFrameOriginBrowserTest, - MAYBE_SplitCache) { + SplitCache) { + // This test will fail if there is no network service, as we fill the + // network isolation key in network::URLLoader only when there is network + // service. If split cache is enabled but the network isolation key is + // empty, then resources won't be cached. + if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) + return; + // Load a cacheable resource for the first time, and it's not cached. EXPECT_FALSE(TestResourceLoad(GenURL("a.com", "/title1.html"), GURL())); @@ -1350,14 +1351,15 @@ GenURL("c.com", "/title1.html"))); } -// See: http://crbug.com/983931 -#if defined(OS_ANDROID) -#define MAYBE_SplitCacheDedicatedWorkers DISABLED_SplitCacheDedicatedWorkers -#else -#define MAYBE_SplitCacheDedicatedWorkers SplitCacheDedicatedWorkers -#endif IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheWithFrameOriginBrowserTest, - MAYBE_SplitCacheDedicatedWorkers) { + SplitCacheDedicatedWorkers) { + // This test will fail if there is no network service, as we fill the + // network isolation key in network::URLLoader only when there is network + // service. If split cache is enabled but the network isolation key is + // empty, then resources won't be cached. + if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) + return; + // Load 3p.com/script from a.com's worker. The first time it's loaded from the // network and the second it's cached. EXPECT_FALSE(TestResourceLoadFromDedicatedWorker( @@ -1390,14 +1392,15 @@ GenURL("c.com", "/embedding_worker.js?c"))); } -// See: http://crbug.com/983931 -#if defined(OS_ANDROID) -#define MAYBE_NavigationResources DISABLED_NavigationResources -#else -#define MAYBE_NavigationResources NavigationResources -#endif IN_PROC_BROWSER_TEST_P(WebContentsSplitCacheBrowserTestEnabled, - MAYBE_NavigationResources) { + NavigationResources) { + // This test will fail if there is no network service, as we fill the + // network isolation key in network::URLLoader only when there is network + // service. If split cache is enabled but the network isolation key is + // empty, then resources won't be cached. + if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) + return; + // Navigate for the first time, and it's not cached. EXPECT_FALSE( NavigationResourceCached(GenURL("a.com", "/title1.html"), GURL(), false)); @@ -1429,14 +1432,15 @@ GenURL("a.com", "/title1.html"), false)); } -// See: http://crbug.com/983931 -#if defined(OS_ANDROID) -#define MAYBE_SubframeNavigationResources DISABLED_SubframeNavigationResources -#else -#define MAYBE_SubframeNavigationResources SubframeNavigationResources -#endif IN_PROC_BROWSER_TEST_F(WebContentsSplitCacheWithFrameOriginBrowserTest, - MAYBE_SubframeNavigationResources) { + SubframeNavigationResources) { + // This test will fail if there is no network service, as we fill the + // network isolation key in network::URLLoader only when there is network + // service. If split cache is enabled but the network isolation key is + // empty, then resources won't be cached. + if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) + return; + // Navigate for the first time, and it's not cached. NavigationResourceCached( GenURL("a.com", "/navigation_controller/page_with_iframe.html"), @@ -1466,15 +1470,15 @@ GenURL("d.com", "/title1.html"), true); } -// See: http://crbug.com/983931 -#if defined(OS_ANDROID) -#define MAYBE_SplitCacheDedicatedWorkers DISABLED_SplitCacheDedicatedWorkers -#else -#define MAYBE_SplitCacheDedicatedWorkers SplitCacheDedicatedWorkers -#endif - IN_PROC_BROWSER_TEST_P(WebContentsSplitCacheBrowserTestEnabled, - MAYBE_SplitCacheDedicatedWorkers) { + SplitCacheDedicatedWorkers) { + // This test will fail if there is no network service, as we fill the + // network isolation key in network::URLLoader only when there is network + // service. If split cache is enabled but the network isolation key is + // empty, then resources won't be cached. + if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) + return; + // Load 3p.com/script from a.com's worker. The first time it's loaded from the // network and the second it's cached. EXPECT_FALSE(TestResourceLoadFromDedicatedWorker(
diff --git a/content/browser/webauth/authenticator_common.cc b/content/browser/webauth/authenticator_common.cc index 41475e5..d511f80 100644 --- a/content/browser/webauth/authenticator_common.cc +++ b/content/browser/webauth/authenticator_common.cc
@@ -18,10 +18,9 @@ #include "base/rand_util.h" #include "base/strings/string_piece.h" #include "base/timer/timer.h" -#include "build/build_config.h" #include "content/browser/bad_message.h" -#include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/webauth/authenticator_environment_impl.h" +#include "content/browser/webauth/virtual_fido_discovery_factory.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/navigation_handle.h" @@ -59,14 +58,6 @@ #include "url/url_constants.h" #include "url/url_util.h" -#if defined(OS_MACOSX) -#include "device/fido/mac/authenticator.h" -#endif - -#if defined(OS_WIN) -#include "device/fido/win/authenticator.h" -#endif - namespace content { namespace client_data { @@ -565,12 +556,15 @@ } void AuthenticatorCommon::StartMakeCredentialRequest() { - request_ = std::make_unique<device::MakeCredentialRequestHandler>( - connector_, - AuthenticatorEnvironmentImpl::GetInstance()->GetFactory( + device::FidoDiscoveryFactory* discovery_factory = + AuthenticatorEnvironmentImpl::GetInstance()->GetDiscoveryFactoryOverride( static_cast<RenderFrameHostImpl*>(render_frame_host_) - ->frame_tree_node()), - GetTransports(caller_origin_, transports_), + ->frame_tree_node()); + if (!discovery_factory) + discovery_factory = request_delegate_->GetDiscoveryFactory(); + + request_ = std::make_unique<device::MakeCredentialRequestHandler>( + connector_, discovery_factory, GetTransports(caller_origin_, transports_), *ctap_make_credential_request_, *authenticator_selection_criteria_, base::BindOnce(&AuthenticatorCommon::OnRegisterResponse, weak_factory_.GetWeakPtr())); @@ -593,21 +587,19 @@ request_delegate_->SetMightCreateResidentCredential(true); } request_->set_observer(request_delegate_.get()); - - request_->SetPlatformAuthenticatorOrMarkUnavailable( - CreatePlatformAuthenticatorIfAvailable()); } void AuthenticatorCommon::StartGetAssertionRequest() { - auto opt_platform_authenticator_info = - CreatePlatformAuthenticatorIfAvailableAndCheckIfCredentialExists( - *ctap_get_assertion_request_); - request_ = std::make_unique<device::GetAssertionRequestHandler>( - connector_, - AuthenticatorEnvironmentImpl::GetInstance()->GetFactory( + device::FidoDiscoveryFactory* discovery_factory = + AuthenticatorEnvironmentImpl::GetInstance()->GetDiscoveryFactoryOverride( static_cast<RenderFrameHostImpl*>(render_frame_host_) - ->frame_tree_node()), - GetTransports(caller_origin_, transports_), *ctap_get_assertion_request_, + ->frame_tree_node()); + if (!discovery_factory) + discovery_factory = request_delegate_->GetDiscoveryFactory(); + + request_ = std::make_unique<device::GetAssertionRequestHandler>( + connector_, discovery_factory, GetTransports(caller_origin_, transports_), + *ctap_get_assertion_request_, base::BindOnce(&AuthenticatorCommon::OnSignResponse, weak_factory_.GetWeakPtr())); @@ -625,10 +617,8 @@ base::BindRepeating( &device::FidoRequestHandlerBase::InitiatePairingWithDevice, request_->GetWeakPtr()) /* ble_pairing_callback*/); - request_->set_observer(request_delegate_.get()); - request_->SetPlatformAuthenticatorOrMarkUnavailable( - std::move(opt_platform_authenticator_info)); + request_->set_observer(request_delegate_.get()); } bool AuthenticatorCommon::IsFocused() const { @@ -986,38 +976,12 @@ : maybe_request_delegate.get(); const bool result = - IsUserVerifyingPlatformAuthenticatorAvailableImpl(request_delegate_ptr); + request_delegate_ptr->IsUserVerifyingPlatformAuthenticatorAvailable(); base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), result)); } -bool AuthenticatorCommon::IsUserVerifyingPlatformAuthenticatorAvailableImpl( - AuthenticatorRequestClientDelegate* request_delegate) { - if (request_delegate->ShouldDisablePlatformAuthenticators()) { - return false; - } - -#if defined(OS_MACOSX) - // Touch ID is disabled, regardless of hardware support, if the embedder - // doesn't support it. - if (!GetContentClient() - ->browser() - ->IsWebAuthenticationTouchIdAuthenticatorSupported()) - return false; - - auto opt_config = request_delegate->GetTouchIdAuthenticatorConfig(); - return opt_config && - device::fido::mac::TouchIdAuthenticator::IsAvailable(*opt_config); -#elif defined(OS_WIN) - return base::FeatureList::IsEnabled(device::kWebAuthUseNativeWinApi) && - device::WinWebAuthnApiAuthenticator:: - IsUserVerifyingPlatformAuthenticatorAvailable(); -#else - return false; -#endif -} - void AuthenticatorCommon::Cancel() { CancelWithStatus(blink::mojom::AuthenticatorStatus::ABORT_ERROR); } @@ -1502,58 +1466,4 @@ ->GetBrowserContext(); } -#if defined(OS_MACOSX) -namespace { -std::unique_ptr<device::fido::mac::TouchIdAuthenticator> -CreateTouchIdAuthenticatorIfAvailable( - AuthenticatorRequestClientDelegate* request_delegate) { - // Not all embedders may provide an authenticator config. - auto opt_authenticator_config = - request_delegate->GetTouchIdAuthenticatorConfig(); - if (!opt_authenticator_config) { - return nullptr; - } - return device::fido::mac::TouchIdAuthenticator::CreateIfAvailable( - std::move(*opt_authenticator_config)); -} -} // namespace -#endif - -base::Optional<device::PlatformAuthenticatorInfo> -AuthenticatorCommon::CreatePlatformAuthenticatorIfAvailable() { - // Incognito mode disables platform authenticators, so check for availability - // first. - if (!IsUserVerifyingPlatformAuthenticatorAvailableImpl( - request_delegate_.get())) { - return base::nullopt; - } -#if defined(OS_MACOSX) - return device::PlatformAuthenticatorInfo( - CreateTouchIdAuthenticatorIfAvailable(request_delegate_.get()), false); -#else - return base::nullopt; -#endif -} - -base::Optional<device::PlatformAuthenticatorInfo> AuthenticatorCommon:: - CreatePlatformAuthenticatorIfAvailableAndCheckIfCredentialExists( - const device::CtapGetAssertionRequest& request) { - // Incognito mode disables platform authenticators, so check for availability - // first. - if (!IsUserVerifyingPlatformAuthenticatorAvailableImpl( - request_delegate_.get())) { - return base::nullopt; - } -#if defined(OS_MACOSX) - std::unique_ptr<device::fido::mac::TouchIdAuthenticator> authenticator = - CreateTouchIdAuthenticatorIfAvailable(request_delegate_.get()); - const bool has_credential = - authenticator->HasCredentialForGetAssertionRequest(request); - return device::PlatformAuthenticatorInfo(std::move(authenticator), - has_credential); -#else - return base::nullopt; -#endif -} - } // namespace content
diff --git a/content/browser/webauth/authenticator_common.h b/content/browser/webauth/authenticator_common.h index 61d63111..c3e48ad 100644 --- a/content/browser/webauth/authenticator_common.h +++ b/content/browser/webauth/authenticator_common.h
@@ -35,7 +35,6 @@ namespace device { -struct PlatformAuthenticatorInfo; class FidoRequestHandlerBase; enum class FidoReturnCode : uint8_t; @@ -87,11 +86,6 @@ IsUserVerifyingPlatformAuthenticatorAvailableCallback callback); void Cancel(); - // Synchronous implementation of - // IsUserVerifyingPlatformAuthenticatorAvailable. - bool IsUserVerifyingPlatformAuthenticatorAvailableImpl( - AuthenticatorRequestClientDelegate* request_delegate); - void Cleanup(); base::flat_set<device::FidoTransportProtocol> enabled_transports_for_testing() @@ -189,12 +183,6 @@ blink::mojom::AuthenticatorStatus status, blink::mojom::GetAssertionAuthenticatorResponsePtr response = nullptr); - base::Optional<device::PlatformAuthenticatorInfo> - CreatePlatformAuthenticatorIfAvailable(); - base::Optional<device::PlatformAuthenticatorInfo> - CreatePlatformAuthenticatorIfAvailableAndCheckIfCredentialExists( - const device::CtapGetAssertionRequest& request); - BrowserContext* browser_context() const; RenderFrameHost* const render_frame_host_;
diff --git a/content/browser/webauth/authenticator_environment_impl.cc b/content/browser/webauth/authenticator_environment_impl.cc index fb702c2..7bbf7a9 100644 --- a/content/browser/webauth/authenticator_environment_impl.cc +++ b/content/browser/webauth/authenticator_environment_impl.cc
@@ -29,24 +29,19 @@ AuthenticatorEnvironmentImpl::AuthenticatorEnvironmentImpl() { if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableWebAuthTestingAPI)) { - discovery_factory_ = std::make_unique<VirtualFidoDiscoveryFactory>(); - } else { - discovery_factory_ = std::make_unique<device::FidoDiscoveryFactory>(); + replaced_discovery_factory_ = + std::make_unique<VirtualFidoDiscoveryFactory>(); } } AuthenticatorEnvironmentImpl::~AuthenticatorEnvironmentImpl() = default; -device::FidoDiscoveryFactory* AuthenticatorEnvironmentImpl::GetFactory( - FrameTreeNode* node) { +device::FidoDiscoveryFactory* +AuthenticatorEnvironmentImpl::GetDiscoveryFactoryOverride(FrameTreeNode* node) { auto* factory = GetVirtualFactoryFor(node); if (factory) return factory; - return discovery_factory_.get(); -} - -device::FidoDiscoveryFactory* AuthenticatorEnvironmentImpl::GetFactory() { - return discovery_factory_.get(); + return replaced_discovery_factory_.get(); } void AuthenticatorEnvironmentImpl::EnableVirtualAuthenticatorFor( @@ -98,7 +93,7 @@ void AuthenticatorEnvironmentImpl::ReplaceDefaultDiscoveryFactoryForTesting( std::unique_ptr<device::FidoDiscoveryFactory> factory) { - discovery_factory_ = std::move(factory); + replaced_discovery_factory_ = std::move(factory); } void AuthenticatorEnvironmentImpl::OnFrameTreeNodeDestroyed(
diff --git a/content/browser/webauth/authenticator_environment_impl.h b/content/browser/webauth/authenticator_environment_impl.h index f386ee0..b468beb 100644 --- a/content/browser/webauth/authenticator_environment_impl.h +++ b/content/browser/webauth/authenticator_environment_impl.h
@@ -35,11 +35,9 @@ public: static AuthenticatorEnvironmentImpl* GetInstance(); - // Returns a FidoDiscoveryFactory for the given node. - device::FidoDiscoveryFactory* GetFactory(FrameTreeNode* node); - - // Returns the default FidoDiscoveryFactory. - device::FidoDiscoveryFactory* GetFactory(); + // Returns the FidoDiscoveryFactory acting as replacement for the |node|. + device::FidoDiscoveryFactory* GetDiscoveryFactoryOverride( + FrameTreeNode* node); // Enables the scoped virtual authenticator environment for the |node| and its // descendants. @@ -80,7 +78,7 @@ private: friend class base::NoDestructor<AuthenticatorEnvironmentImpl>; - std::unique_ptr<device::FidoDiscoveryFactory> discovery_factory_; + std::unique_ptr<device::FidoDiscoveryFactory> replaced_discovery_factory_; std::map<FrameTreeNode*, std::unique_ptr<VirtualFidoDiscoveryFactory>> virtual_discovery_factories_;
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc index b9b6dcfee..55372f1 100644 --- a/content/browser/webauth/authenticator_impl_unittest.cc +++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -1599,12 +1599,14 @@ base::OnceClosure action_callbacks_registered_callback, IndividualAttestation individual_attestation, AttestationConsent attestation_consent, - bool is_focused) + bool is_focused, + bool is_uvpaa) : action_callbacks_registered_callback_( std::move(action_callbacks_registered_callback)), individual_attestation_(individual_attestation), attestation_consent_(attestation_consent), - is_focused_(is_focused) {} + is_focused_(is_focused), + is_uvpaa_(is_uvpaa) {} ~TestAuthenticatorRequestDelegate() override {} void RegisterActionCallbacks( @@ -1632,12 +1634,17 @@ AttestationConsent::GRANTED); } + bool IsUserVerifyingPlatformAuthenticatorAvailable() override { + return is_uvpaa_; + } + bool IsFocused() override { return is_focused_; } base::OnceClosure action_callbacks_registered_callback_; const IndividualAttestation individual_attestation_; const AttestationConsent attestation_consent_; const bool is_focused_; + const bool is_uvpaa_; private: DISALLOW_COPY_AND_ASSIGN(TestAuthenticatorRequestDelegate); @@ -1656,7 +1663,7 @@ action_callbacks_registered_callback ? std::move(action_callbacks_registered_callback) : base::DoNothing(), - individual_attestation, attestation_consent, is_focused); + individual_attestation, attestation_consent, is_focused, is_uvpaa); } // If set, this closure will be called when the subsequently constructed @@ -1668,6 +1675,8 @@ AttestationConsent attestation_consent = AttestationConsent::DENIED; bool is_focused = true; + bool is_uvpaa = false; + // This emulates scenarios where a nullptr RequestClientDelegate is returned // because a request is already in progress. bool return_null_delegate = false; @@ -2072,8 +2081,8 @@ PlatformAuthenticatorAttestation) { virtual_device_factory_->SetSupportedProtocol( device::ProtocolVersion::kCtap2); - virtual_device_factory_->mutable_state()->transport = - device::FidoTransportProtocol::kInternal; + virtual_device_factory_->SetTransport( + device::FidoTransportProtocol::kInternal); virtual_device_factory_->mutable_state()->self_attestation = true; virtual_device_factory_->mutable_state() ->non_zero_aaguid_with_self_attestation = true; @@ -2305,43 +2314,20 @@ } } -#if defined(OS_WIN) -TEST_F(AuthenticatorContentBrowserClientTest, WinIsUVPAA) { - for (const bool enable_win_webauthn_api : {false, true}) { - SCOPED_TRACE(enable_win_webauthn_api ? "enable_win_webauthn_api" - : "!enable_win_webauthn_api"); - for (const bool is_uvpaa : {false, true}) { - SCOPED_TRACE(is_uvpaa ? "is_uvpaa" : "!is_uvpaa"); +TEST_F(AuthenticatorContentBrowserClientTest, IsUVPAA) { + for (const bool is_uvpaa : {false, true}) { + SCOPED_TRACE(::testing::Message() << "is_uvpaa=" << is_uvpaa); + test_client_.is_uvpaa = is_uvpaa; - win_webauthn_api_.set_available(enable_win_webauthn_api); - win_webauthn_api_.set_is_uvpaa(is_uvpaa); + mojo::Remote<blink::mojom::Authenticator> authenticator = + ConnectToAuthenticator(); - mojo::Remote<blink::mojom::Authenticator> authenticator = - ConnectToAuthenticator(); - TestIsUvpaaCallback cb; - authenticator->IsUserVerifyingPlatformAuthenticatorAvailable( - cb.callback()); - cb.WaitForCallback(); - EXPECT_EQ(enable_win_webauthn_api && is_uvpaa, cb.value()); - } + TestIsUvpaaCallback cb; + authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(cb.callback()); + cb.WaitForCallback(); + EXPECT_EQ(is_uvpaa, cb.value()); } } -#endif // defined(OS_WIN) - -#if !defined(OS_MACOSX) && !defined(OS_WIN) -TEST_F(AuthenticatorContentBrowserClientTest, IsUVPAAFalse) { - // There are no platform authenticators other than Windows Hello and macOS - // Touch ID. - NavigateAndCommit(GURL(kTestOrigin1)); - mojo::Remote<blink::mojom::Authenticator> authenticator = - ConnectToAuthenticator(); - - TestIsUvpaaCallback cb; - authenticator->IsUserVerifyingPlatformAuthenticatorAvailable(cb.callback()); - cb.WaitForCallback(); - EXPECT_FALSE(cb.value()); -} -#endif // !defined(OS_MACOSX) && !defined(OS_WIN) TEST_F(AuthenticatorContentBrowserClientTest, CryptotokenBypassesAttestationConsentPrompt) { @@ -2386,7 +2372,8 @@ base::DoNothing() /* did_start_request_callback */, IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED, - true /* is_focused */), + true /* is_focused */, + /*is_uvpaa=*/false), failure_reasons_callback_(std::move(failure_reasons_callback)) {} ~MockAuthenticatorRequestDelegateObserver() override = default; @@ -4172,98 +4159,4 @@ } } -#if defined(OS_MACOSX) -class TouchIdAuthenticatorRequestDelegate - : public AuthenticatorRequestClientDelegate { - public: - using TouchIdAuthenticatorConfig = ::device::fido::mac::AuthenticatorConfig; - - explicit TouchIdAuthenticatorRequestDelegate( - TouchIdAuthenticatorConfig config) - : config_(std::move(config)) {} - - base::Optional<TouchIdAuthenticatorConfig> GetTouchIdAuthenticatorConfig() - override { - return config_; - } - - private: - TouchIdAuthenticatorConfig config_; - DISALLOW_COPY_AND_ASSIGN(TouchIdAuthenticatorRequestDelegate); -}; - -class TouchIdAuthenticatorContentBrowserClient : public ContentBrowserClient { - public: - using TouchIdAuthenticatorConfig = ::device::fido::mac::AuthenticatorConfig; - - std::unique_ptr<AuthenticatorRequestClientDelegate> - GetWebAuthenticationRequestDelegate( - RenderFrameHost* render_frame_host, - const std::string& relying_party_id) override { - return std::make_unique<TouchIdAuthenticatorRequestDelegate>( - touch_id_config); - } - - bool IsWebAuthenticationTouchIdAuthenticatorSupported() override { - return supports_touch_id; - } - - bool supports_touch_id = true; - - TouchIdAuthenticatorConfig touch_id_config; -}; - -class TouchIdAuthenticatorContentBrowserClientTest - : public AuthenticatorContentBrowserClientTest { - protected: - TouchIdAuthenticatorContentBrowserClientTest() = default; - - void SetUp() override { - AuthenticatorImplTest::SetUp(); - old_client_ = SetBrowserClientForTesting(&test_client_); - NavigateAndCommit(GURL(kTestOrigin1)); - } - - void TearDown() override { - SetBrowserClientForTesting(old_client_); - AuthenticatorImplTest::TearDown(); - } - - TouchIdAuthenticatorContentBrowserClient test_client_; - - API_AVAILABLE(macos(10.12.2)) - device::fido::mac::ScopedTouchIdTestEnvironment touch_id_test_environment_; - - private: - ContentBrowserClient* old_client_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(TouchIdAuthenticatorContentBrowserClientTest); -}; - -TEST_F(TouchIdAuthenticatorContentBrowserClientTest, IsUVPAA) { - if (__builtin_available(macOS 10.12.2, *)) { - for (const bool touch_id_enabled_in_browser_client : {false, true}) { - SCOPED_TRACE(::testing::Message() << "touch_id_enabled_in_browser_client=" - << touch_id_enabled_in_browser_client); - for (const bool touch_id_available : {false, true}) { - SCOPED_TRACE(::testing::Message() - << "touch_id_available=" << touch_id_available); - touch_id_test_environment_.SetTouchIdAvailable(touch_id_available); - test_client_.supports_touch_id = touch_id_enabled_in_browser_client; - - mojo::Remote<blink::mojom::Authenticator> authenticator = - ConnectToAuthenticator(); - - TestIsUvpaaCallback cb; - authenticator->IsUserVerifyingPlatformAuthenticatorAvailable( - cb.callback()); - cb.WaitForCallback(); - EXPECT_EQ(cb.value(), - touch_id_enabled_in_browser_client && touch_id_available); - } - } - } -} -#endif // defined(OS_MACOSX) - } // namespace content
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc index d7c2ecf..6ec09b89 100644 --- a/content/browser/webauth/webauth_browsertest.cc +++ b/content/browser/webauth/webauth_browsertest.cc
@@ -933,6 +933,7 @@ // signal's aborted flag set after sending request, we get an AbortError. IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, CreatePublicKeyCredentialWithAbortSetAfterCreate) { + InjectVirtualFidoDeviceFactory(); CreateParameters parameters; parameters.signal = "authAbortSignal"; std::string result; @@ -1027,6 +1028,7 @@ // signal's aborted flag set after sending request, we get an AbortError. IN_PROC_BROWSER_TEST_F(WebAuthJavascriptClientBrowserTest, GetPublicKeyCredentialWithAbortSetAfterGet) { + InjectVirtualFidoDeviceFactory(); GetParameters parameters; parameters.signal = "authAbortSignal"; std::string result;
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc index 7ef1dfd..6de307c 100644 --- a/content/browser/worker_host/dedicated_worker_host.cc +++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -83,6 +83,7 @@ DCHECK(client); client_ = std::move(client); + // Get a storage partition. auto* worker_process_host = RenderProcessHost::FromID(worker_process_id_); if (!worker_process_host) { client_->OnScriptLoadStartFailed(); @@ -91,6 +92,25 @@ auto* storage_partition_impl = static_cast<StoragePartitionImpl*>( worker_process_host->GetStoragePartition()); + // Get a storage domain. + RenderFrameHostImpl* ancestor_render_frame_host = + GetAncestorRenderFrameHost(); + if (!ancestor_render_frame_host) { + client_->OnScriptLoadStartFailed(); + return; + } + SiteInstance* site_instance = ancestor_render_frame_host->GetSiteInstance(); + if (!site_instance) { + client_->OnScriptLoadStartFailed(); + return; + } + std::string storage_domain; + std::string partition_name; + bool in_memory; + GetContentClient()->browser()->GetStoragePartitionConfigForSite( + storage_partition_impl->browser_context(), site_instance->GetSiteURL(), + /*can_be_default=*/true, &storage_domain, &partition_name, &in_memory); + scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory; if (script_url.SchemeIsBlob()) { if (!blob_url_token) { @@ -119,6 +139,7 @@ storage_partition_impl->GetServiceWorkerContext(), service_worker_handle_.get(), appcache_handle_->core(), std::move(blob_url_loader_factory), nullptr, storage_partition_impl, + storage_domain, base::BindOnce(&DedicatedWorkerHost::DidStartScriptLoad, weak_factory_.GetWeakPtr())); } @@ -168,6 +189,9 @@ return; } + // TODO(https://crbug.com/986188): Check if the main script's final response + // URL is commitable. + // TODO(cammie): Change this approach when we support shared workers // creating dedicated workers, as there might be no ancestor frame. RenderFrameHostImpl* ancestor_render_frame_host =
diff --git a/content/browser/worker_host/shared_worker_service_impl.cc b/content/browser/worker_host/shared_worker_service_impl.cc index d473c56..54f9a69 100644 --- a/content/browser/worker_host/shared_worker_service_impl.cc +++ b/content/browser/worker_host/shared_worker_service_impl.cc
@@ -169,10 +169,23 @@ DestroyHost(host); } + // Get a storage domain. + SiteInstance* site_instance = render_frame_host->GetSiteInstance(); + if (!site_instance) { + client->OnScriptLoadFailed(); + return; + } + std::string storage_domain; + std::string partition_name; + bool in_memory; + GetContentClient()->browser()->GetStoragePartitionConfigForSite( + storage_partition_->browser_context(), site_instance->GetSiteURL(), + /*can_be_default=*/true, &storage_domain, &partition_name, &in_memory); + CreateWorker(std::move(instance), std::move(outside_fetch_client_settings_object), - std::move(client), client_process_id, frame_id, message_port, - std::move(blob_url_loader_factory)); + std::move(client), client_process_id, frame_id, storage_domain, + message_port, std::move(blob_url_loader_factory)); } void SharedWorkerServiceImpl::DestroyHost(SharedWorkerHost* host) { @@ -191,6 +204,7 @@ blink::mojom::SharedWorkerClientPtr client, int client_process_id, int frame_id, + const std::string& storage_domain, const blink::MessagePortChannel& message_port, scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -232,7 +246,7 @@ ResourceType::kSharedWorker, service_worker_context_, service_worker_handle_raw, appcache_handle_core, std::move(blob_url_loader_factory), url_loader_factory_override_, - storage_partition_, + storage_partition_, storage_domain, base::BindOnce(&SharedWorkerServiceImpl::DidCreateScriptLoader, weak_factory_.GetWeakPtr(), std::move(instance), weak_host, std::move(client), client_process_id, frame_id, @@ -262,6 +276,9 @@ return; } + // TODO(https://crbug.com/986188): Check if the main script's final response + // URL is commitable. + StartWorker(std::move(instance), std::move(host), std::move(client), process_id, frame_id, message_port, std::move(subresource_loader_factories),
diff --git a/content/browser/worker_host/shared_worker_service_impl.h b/content/browser/worker_host/shared_worker_service_impl.h index b9a650f..553f1de 100644 --- a/content/browser/worker_host/shared_worker_service_impl.h +++ b/content/browser/worker_host/shared_worker_service_impl.h
@@ -87,6 +87,7 @@ blink::mojom::SharedWorkerClientPtr client, int client_process_id, int frame_id, + const std::string& storage_domain, const blink::MessagePortChannel& message_port, scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory); void DidCreateScriptLoader(
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc index 3ca89a1..f5602a49c0 100644 --- a/content/browser/worker_host/worker_script_fetch_initiator.cc +++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -18,6 +18,7 @@ #include "content/browser/appcache/appcache_navigation_handle_core.h" #include "content/browser/data_url_loader_factory.h" #include "content/browser/file_url_loader_factory.h" +#include "content/browser/fileapi/file_system_url_loader_factory.h" #include "content/browser/loader/browser_initiated_resource_request.h" #include "content/browser/loader/navigation_url_loader_impl.h" #include "content/browser/navigation_subresource_loader_params.h" @@ -86,6 +87,7 @@ scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory, scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_override, StoragePartitionImpl* storage_partition, + const std::string& storage_domain, CompletionCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService)); @@ -105,16 +107,22 @@ bool constructor_uses_file_url = request_initiator.scheme() == url::kFileScheme; + // TODO(https://crbug.com/987517): Filesystem URL support on shared workers + // are now broken. + bool filesystem_url_support = resource_type == ResourceType::kWorker; + // Set up the factory bundle for non-NetworkService URLs, e.g., // chrome-extension:// URLs. One factory bundle is consumed by the browser // for WorkerScriptLoaderFactory, and one is sent to the renderer for // subresource loading. std::unique_ptr<blink::URLLoaderFactoryBundleInfo> factory_bundle_for_browser = CreateFactoryBundle( - worker_process_id, storage_partition, constructor_uses_file_url); + worker_process_id, storage_partition, storage_domain, + constructor_uses_file_url, filesystem_url_support); std::unique_ptr<blink::URLLoaderFactoryBundleInfo> subresource_loader_factories = CreateFactoryBundle( - worker_process_id, storage_partition, constructor_uses_file_url); + worker_process_id, storage_partition, storage_domain, + constructor_uses_file_url, filesystem_url_support); // Create a resource request for initiating worker script fetch from the // browser process. @@ -226,12 +234,23 @@ WorkerScriptFetchInitiator::CreateFactoryBundle( int worker_process_id, StoragePartitionImpl* storage_partition, - bool file_support) { + const std::string& storage_domain, + bool file_support, + bool filesystem_url_support) { DCHECK_CURRENTLY_ON(BrowserThread::UI); ContentBrowserClient::NonNetworkURLLoaderFactoryMap non_network_factories; non_network_factories[url::kDataScheme] = std::make_unique<DataURLLoaderFactory>(); + if (filesystem_url_support) { + // TODO(https://crbug.com/986188): Pass ChildProcessHost::kInvalidUniqueID + // instead of valid |worker_process_id| for |factory_bundle_for_browser| + // once CanCommitURL-like check is implemented in PlzWorker. + non_network_factories[url::kFileSystemScheme] = + CreateFileSystemURLLoaderFactory( + worker_process_id, RenderFrameHost::kNoFrameTreeNodeId, + storage_partition->GetFileSystemContext(), storage_domain); + } GetContentClient() ->browser() ->RegisterNonNetworkSubresourceURLLoaderFactories(
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.h b/content/browser/worker_host/worker_script_fetch_initiator.h index c2a1382..5142cb3 100644 --- a/content/browser/worker_host/worker_script_fetch_initiator.h +++ b/content/browser/worker_host/worker_script_fetch_initiator.h
@@ -75,6 +75,7 @@ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_override, StoragePartitionImpl* storage_partition, + const std::string& storage_domain, CompletionCallback callback); // Returns the BrowserThread::ID that the WorkerScriptLoaderFactory will be @@ -88,7 +89,9 @@ static std::unique_ptr<blink::URLLoaderFactoryBundleInfo> CreateFactoryBundle( int worker_process_id, StoragePartitionImpl* storage_partition, - bool file_support); + const std::string& storage_domain, + bool file_support, + bool filesystem_url_support); // Adds additional request headers to |resource_request|. Must be called on // the UI thread.
diff --git a/content/child/child_process.cc b/content/child/child_process.cc index 3d4cd9e..7765881 100644 --- a/content/child/child_process.cc +++ b/content/child/child_process.cc
@@ -16,6 +16,7 @@ #include "base/threading/thread_local.h" #include "build/build_config.h" #include "content/child/child_thread_impl.h" +#include "third_party/blink/public/common/features.h" namespace content { @@ -57,7 +58,10 @@ #if defined(OS_ANDROID) // TODO(reveman): Remove this in favor of setting it explicitly for each type // of process. - thread_options.priority = base::ThreadPriority::DISPLAY; + if (base::FeatureList::IsEnabled( + blink::features::kBlinkCompositorUseDisplayThreadPriority)) { + thread_options.priority = base::ThreadPriority::DISPLAY; + } #endif CHECK(io_thread_.StartWithOptions(thread_options)); }
diff --git a/content/common/DEPS b/content/common/DEPS index 1d1d07c6..f0157d6b 100644 --- a/content/common/DEPS +++ b/content/common/DEPS
@@ -5,6 +5,7 @@ "+components/viz/common", "+components/payments", "+device/base/synchronization", + "+services/media_session/public/cpp", "+services/network/loader_util.h", "+services/network/public/cpp", "+services/network/public/mojom",
diff --git a/content/common/content_param_traits.cc b/content/common/content_param_traits.cc index 09dc04c..f6a0272 100644 --- a/content/common/content_param_traits.cc +++ b/content/common/content_param_traits.cc
@@ -294,6 +294,7 @@ WriteParam(m, p->data.has_user_gesture); WriteParam(m, !!p->data.user_activation); WriteParam(m, p->data.transfer_user_activation); + WriteParam(m, p->data.allow_autoplay); if (p->data.user_activation) { WriteParam(m, p->data.user_activation->has_been_active); WriteParam(m, p->data.user_activation->was_active); @@ -325,7 +326,8 @@ !ReadParam(m, iter, &(*r)->data.stream_channels) || !ReadParam(m, iter, &(*r)->data.has_user_gesture) || !ReadParam(m, iter, &has_activation) || - !ReadParam(m, iter, &(*r)->data.transfer_user_activation)) { + !ReadParam(m, iter, &(*r)->data.transfer_user_activation) || + !ReadParam(m, iter, &(*r)->data.allow_autoplay)) { return false; }
diff --git a/content/common/content_switches_internal.cc b/content/common/content_switches_internal.cc index df9ba8b..4a8facef 100644 --- a/content/common/content_switches_internal.cc +++ b/content/common/content_switches_internal.cc
@@ -88,9 +88,9 @@ #if defined(OS_WIN) #if defined(GOOGLE_CHROME_BUILD) std::string title = "Google Chrome"; -#else // CHROMIUM_BUILD +#else // BUILDFLAG(CHROMIUM_BRANDING) std::string title = "Chromium"; -#endif // CHROMIUM_BUILD +#endif // BUILDFLAG(CHROMIUM_BRANDING) title += " "; title += label; // makes attaching to process easier std::string message = label;
diff --git a/content/common/media/media_player_delegate_messages.h b/content/common/media/media_player_delegate_messages.h index e9219e9..1f9f5cc 100644 --- a/content/common/media/media_player_delegate_messages.h +++ b/content/common/media/media_player_delegate_messages.h
@@ -16,6 +16,7 @@ #include "content/common/content_export.h" #include "ipc/ipc_message_macros.h" #include "media/base/media_content_type.h" +#include "services/media_session/public/cpp/media_position.h" #include "third_party/blink/public/platform/web_fullscreen_video_status.h" #include "ui/gfx/ipc/geometry/gfx_param_traits.h" @@ -23,6 +24,13 @@ #define IPC_MESSAGE_EXPORT CONTENT_EXPORT #define IPC_MESSAGE_START MediaPlayerDelegateMsgStart +IPC_STRUCT_TRAITS_BEGIN(media_session::MediaPosition) + IPC_STRUCT_TRAITS_MEMBER(playback_rate_) + IPC_STRUCT_TRAITS_MEMBER(duration_) + IPC_STRUCT_TRAITS_MEMBER(position_) + IPC_STRUCT_TRAITS_MEMBER(last_updated_time_) +IPC_STRUCT_TRAITS_END() + IPC_ENUM_TRAITS_MAX_VALUE(media::MediaContentType, media::MediaContentType::Max) IPC_ENUM_TRAITS_MAX_VALUE(blink::WebFullscreenVideoStatus, blink::WebFullscreenVideoStatus::kMax) @@ -82,6 +90,10 @@ int /* delegate_id, distinguishes instances */, bool /* the new muted status */) +IPC_MESSAGE_ROUTED2(MediaPlayerDelegateHostMsg_OnMediaPositionStateChanged, + int /* delegate_id, distinguishes instances */, + media_session::MediaPosition /* the new position state */) + IPC_MESSAGE_ROUTED2( MediaPlayerDelegateHostMsg_OnMediaEffectivelyFullscreenChanged, int /* delegate_id, distinguishes instances */,
diff --git a/content/common/service_manager/service_manager_connection_impl.cc b/content/common/service_manager/service_manager_connection_impl.cc index d8af976..647d57e 100644 --- a/content/common/service_manager/service_manager_connection_impl.cc +++ b/content/common/service_manager/service_manager_connection_impl.cc
@@ -77,6 +77,11 @@ FROM_HERE, base::BindOnce(&IOThreadContext::StartOnIOThread, this)); } + void Stop() { + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&IOThreadContext::StopOnIOThread, this)); + } + // Safe to call from whichever thread called Start() (or may have called // Start()). Must be called before IO thread shutdown. void ShutDown() { @@ -189,6 +194,11 @@ new MessageLoopObserver(weak_factory_.GetWeakPtr()); } + void StopOnIOThread() { + ClearConnectionFiltersOnIOThread(); + request_handlers_.clear(); + } + void ShutDownOnIOThread() { DCHECK(io_thread_checker_.CalledOnValidThread()); @@ -209,9 +219,7 @@ service_binding_.reset(); - ClearConnectionFiltersOnIOThread(); - - request_handlers_.clear(); + StopOnIOThread(); } void ClearConnectionFiltersOnIOThread() { @@ -399,6 +407,10 @@ weak_factory_.GetWeakPtr())); } +void ServiceManagerConnectionImpl::Stop() { + context_->Stop(); +} + service_manager::Connector* ServiceManagerConnectionImpl::GetConnector() { return connector_.get(); }
diff --git a/content/common/service_manager/service_manager_connection_impl.h b/content/common/service_manager/service_manager_connection_impl.h index 6f572250..37344d1 100644 --- a/content/common/service_manager/service_manager_connection_impl.h +++ b/content/common/service_manager/service_manager_connection_impl.h
@@ -36,6 +36,7 @@ // ServiceManagerConnection: void Start() override; + void Stop() override; service_manager::Connector* GetConnector() override; void SetConnectionLostClosure(const base::Closure& closure) override; int AddConnectionFilter(std::unique_ptr<ConnectionFilter> filter) override;
diff --git a/content/public/browser/authenticator_request_client_delegate.cc b/content/public/browser/authenticator_request_client_delegate.cc index 819996d5..b61d2ab 100644 --- a/content/public/browser/authenticator_request_client_delegate.cc +++ b/content/public/browser/authenticator_request_client_delegate.cc
@@ -8,6 +8,8 @@ #include "base/callback.h" #include "base/strings/string_piece.h" +#include "build/build_config.h" +#include "device/fido/fido_discovery_factory.h" namespace content { @@ -60,16 +62,34 @@ return true; } -bool AuthenticatorRequestClientDelegate::ShouldDisablePlatformAuthenticators() { - return false; -} - #if defined(OS_MACOSX) base::Optional<AuthenticatorRequestClientDelegate::TouchIdAuthenticatorConfig> AuthenticatorRequestClientDelegate::GetTouchIdAuthenticatorConfig() { return base::nullopt; } +#endif // defined(OS_MACOSX) + +bool AuthenticatorRequestClientDelegate:: + IsUserVerifyingPlatformAuthenticatorAvailable() { + return false; +} + +device::FidoDiscoveryFactory* +AuthenticatorRequestClientDelegate::GetDiscoveryFactory() { +#if defined(OS_ANDROID) + // Android uses an internal FIDO API to manage device discovery. + NOTREACHED(); + return nullptr; +#else + if (!discovery_factory_) { + discovery_factory_ = std::make_unique<device::FidoDiscoveryFactory>(); +#if defined(OS_MACOSX) + discovery_factory_->set_mac_touch_id_info(GetTouchIdAuthenticatorConfig()); +#endif // defined(OS_MACOSX) + } + return discovery_factory_.get(); #endif +} void AuthenticatorRequestClientDelegate::UpdateLastTransportUsed( device::FidoTransportProtocol transport) {}
diff --git a/content/public/browser/authenticator_request_client_delegate.h b/content/public/browser/authenticator_request_client_delegate.h index a23b507a3..eda57e6 100644 --- a/content/public/browser/authenticator_request_client_delegate.h +++ b/content/public/browser/authenticator_request_client_delegate.h
@@ -133,10 +133,6 @@ // that testing is possible. virtual bool IsFocused(); - // Returns whether IsUVPAA() should always return false, regardless of - // hardware support or enrollment status. - virtual bool ShouldDisablePlatformAuthenticators(); - #if defined(OS_MACOSX) using TouchIdAuthenticatorConfig = device::fido::mac::AuthenticatorConfig; @@ -145,7 +141,15 @@ // available. virtual base::Optional<TouchIdAuthenticatorConfig> GetTouchIdAuthenticatorConfig(); -#endif +#endif // defined(OS_MACOSX) + + // Returns true if a user verifying platform authenticator is available and + // configured. + virtual bool IsUserVerifyingPlatformAuthenticatorAvailable(); + + // Returns a FidoDiscoveryFactory that has been configured for the current + // environment. + virtual device::FidoDiscoveryFactory* GetDiscoveryFactory(); // Saves transport type the user used during WebAuthN API so that the // WebAuthN UI will default to the same transport type during next API call. @@ -188,6 +192,10 @@ void FinishCollectPIN() override; private: +#if !defined(OS_ANDROID) + std::unique_ptr<device::FidoDiscoveryFactory> discovery_factory_; +#endif // !defined(OS_ANDROID) + DISALLOW_COPY_AND_ASSIGN(AuthenticatorRequestClientDelegate); };
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 21da9c9c..e2b0dcd 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -868,12 +868,6 @@ return std::make_unique<AuthenticatorRequestClientDelegate>(); } -#if defined(OS_MACOSX) -bool ContentBrowserClient::IsWebAuthenticationTouchIdAuthenticatorSupported() { - return false; -} -#endif - std::unique_ptr<net::ClientCertStore> ContentBrowserClient::CreateClientCertStore(ResourceContext* resource_context) { return nullptr;
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index b0709c0..a14b357 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -1435,13 +1435,6 @@ GetWebAuthenticationRequestDelegate(RenderFrameHost* render_frame_host, const std::string& relying_party_id); -#if defined(OS_MACOSX) - // Returns whether WebAuthn supports the built-in Touch ID platform - // authenticator. If true, the embedder must supply a configuration in - // |AuthenticatorRequestClientDelegate::GetTouchIdAuthenticatorConfig|. - virtual bool IsWebAuthenticationTouchIdAuthenticatorSupported(); -#endif - // Get platform ClientCertStore. May return nullptr. virtual std::unique_ptr<net::ClientCertStore> CreateClientCertStore( ResourceContext* resource_context);
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 3c4af592..b9833a6 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -82,6 +82,11 @@ const base::Feature kCacheInlineScriptCode{"CacheInlineScriptCode", base::FEATURE_ENABLED_BY_DEFAULT}; +// Enables support for parallel cache_storage operations via the +// "max_shared_ops" fieldtrial parameter. +const base::Feature kCacheStorageParallelOps{"CacheStorageParallelOps", + base::FEATURE_DISABLED_BY_DEFAULT}; + // If Canvas2D Image Chromium is allowed, this feature controls whether it is // enabled. const base::Feature kCanvas2DImageChromium { @@ -270,7 +275,7 @@ // If enabled, the URLLoaderRequestController lives on the UI thread. const base::Feature kNavigationLoaderOnUI{"NavigationLoaderOnUI", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // Transmit the response body datapipe to the renderer process in // CommitNavigation() so that it can start reading earlier.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 99f2a31..3aa3ab6 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -29,6 +29,7 @@ CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources; CONTENT_EXPORT extern const base::Feature kBundledHTTPExchanges; CONTENT_EXPORT extern const base::Feature kCacheInlineScriptCode; +CONTENT_EXPORT extern const base::Feature kCacheStorageParallelOps; CONTENT_EXPORT extern const base::Feature kCanvas2DImageChromium; CONTENT_EXPORT extern const base::Feature kCompositeOpaqueFixedPosition; CONTENT_EXPORT extern const base::Feature kCompositeOpaqueScrollers;
diff --git a/content/public/common/navigation_policy.cc b/content/public/common/navigation_policy.cc index f437f0a..b1713d7f 100644 --- a/content/public/common/navigation_policy.cc +++ b/content/public/common/navigation_policy.cc
@@ -69,13 +69,15 @@ ResourceInterceptPolicy NavigationDownloadPolicy::GetResourceInterceptPolicy() const { if (disallowed_types.test( + static_cast<size_t>(NavigationDownloadType::kSandbox)) || + disallowed_types.test( static_cast<size_t>(NavigationDownloadType::kSandboxNoGesture)) || disallowed_types.test( static_cast<size_t>(NavigationDownloadType::kOpenerCrossOrigin)) || disallowed_types.test( - static_cast<size_t>(NavigationDownloadType::kAdFrameNoGesture)) || + static_cast<size_t>(NavigationDownloadType::kAdFrame)) || disallowed_types.test( - static_cast<size_t>(NavigationDownloadType::kAdFrameGesture))) { + static_cast<size_t>(NavigationDownloadType::kAdFrameNoGesture))) { return ResourceInterceptPolicy::kAllowPluginOnly; } return disallowed_types.any() ? ResourceInterceptPolicy::kAllowNone
diff --git a/content/public/common/navigation_policy.h b/content/public/common/navigation_policy.h index e7e3954..cad33697 100644 --- a/content/public/common/navigation_policy.h +++ b/content/public/common/navigation_policy.h
@@ -45,11 +45,17 @@ // activation. kAdFrameNoGesture = 8, - // The navigation was initiated from or occurred in an ad frame with user - // activation. - kAdFrameGesture = 9, + // The navigation was initiated from or occurred in an ad frame. + kAdFrame = 10, - kMaxValue = kAdFrameGesture + // The navigation was initiated from or occurred in an iframe with + // |WebSandboxFlags::kDownloads| flag set. + kSandbox = 11, + + // The navigation was initiated without user activation. + kNoGesture = 12, + + kMaxValue = kNoGesture }; // Stores the navigation types that may be of interest to the download-related
diff --git a/content/public/common/service_manager_connection.h b/content/public/common/service_manager_connection.h index 5fb927d..15a17230 100644 --- a/content/public/common/service_manager_connection.h +++ b/content/public/common/service_manager_connection.h
@@ -75,6 +75,10 @@ // below. virtual void Start() = 0; + // Stops accepting incoming connections. This happens asynchronously by + // posting to the IO thread, and cannot be undone. + virtual void Stop() = 0; + // Returns the service_manager::Connector received via this connection's // Service // implementation. Use this to initiate connections as this object's Identity.
diff --git a/content/renderer/loader/web_worker_fetch_context_impl.cc b/content/renderer/loader/web_worker_fetch_context_impl.cc index e659a2c..564b4b3 100644 --- a/content/renderer/loader/web_worker_fetch_context_impl.cc +++ b/content/renderer/loader/web_worker_fetch_context_impl.cc
@@ -52,8 +52,8 @@ scoped_refptr<base::SequencedTaskRunner> task_runner) { ServiceWorkerSubresourceLoaderFactory::Create( base::MakeRefCounted<ControllerServiceWorkerConnector>( - std::move(container_host_info), nullptr /* controller_ptr */, - client_id), + std::move(container_host_info), + mojo::NullRemote() /* remote_controller */, client_id), network::SharedURLLoaderFactory::Create(std::move(fallback_factory)), std::move(request), std::move(task_runner)); }
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc index 93a45c2..2e1635ee 100644 --- a/content/renderer/media/renderer_webmediaplayer_delegate.cc +++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -111,6 +111,13 @@ delegate_id, muted)); } +void RendererWebMediaPlayerDelegate::DidPlayerMediaPositionStateChange( + int delegate_id, + const media_session::MediaPosition& position) { + Send(new MediaPlayerDelegateHostMsg_OnMediaPositionStateChanged( + routing_id(), delegate_id, position)); +} + void RendererWebMediaPlayerDelegate::DidPause(int player_id) { DVLOG(2) << __func__ << "(" << player_id << ")"; DCHECK(id_map_.Lookup(player_id));
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.h b/content/renderer/media/renderer_webmediaplayer_delegate.h index 3deccaa7..8c4f71b2 100644 --- a/content/renderer/media/renderer_webmediaplayer_delegate.h +++ b/content/renderer/media/renderer_webmediaplayer_delegate.h
@@ -67,7 +67,7 @@ void DidPlayerMutedStatusChange(int delegate_id, bool muted) override; void DidPlayerMediaPositionStateChange( int delegate_id, - const media_session::MediaPosition& position) override {} + const media_session::MediaPosition& position) override; // content::RenderFrameObserver overrides. void WasHidden() override;
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc index 5425f4a..e0c2d35 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -1527,6 +1527,12 @@ return webkit_request.RequestSucceeded(); } +void RTCPeerConnectionHandler::RestartIce() { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + // The proxy invokes RestartIce() on the signaling thread. + native_peer_connection_->RestartIce(); +} + void RTCPeerConnectionHandler::GetStandardStatsForTracker( scoped_refptr<webrtc::RTCStatsCollectorCallback> observer) { native_peer_connection_->GetStats(observer.get());
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.h b/content/renderer/media/webrtc/rtc_peer_connection_handler.h index 5110fc0..e8861b12 100644 --- a/content/renderer/media/webrtc/rtc_peer_connection_handler.h +++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.h
@@ -151,6 +151,7 @@ scoped_refptr<blink::WebRTCICECandidate> candidate) override; virtual void OnaddICECandidateResult(const blink::WebRTCVoidRequest& request, bool result); + void RestartIce() override; void GetStats(const blink::WebRTCStatsRequest& request) override; void GetStats(blink::WebRTCStatsReportCallback callback,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 6578966..e2a9d4a 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -1752,21 +1752,33 @@ bool blocking_downloads_in_sandbox_without_user_activation_enabled, bool from_ad, NavigationDownloadPolicy* download_policy) { + bool has_gesture = request.HasUserGesture(); + if (!has_gesture) { + download_policy->SetAllowed(NavigationDownloadType::kNoGesture); + } + // Disallow downloads on an opener if the requestor is cross origin. // See crbug.com/632514. if (is_opener_navigation && !request.RequestorOrigin().CanAccess(current_origin)) { download_policy->SetDisallowed(NavigationDownloadType::kOpenerCrossOrigin); } - if (has_download_sandbox_flag && !request.HasUserGesture()) { - if (blocking_downloads_in_sandbox_without_user_activation_enabled) { - download_policy->SetDisallowed(NavigationDownloadType::kSandboxNoGesture); - } else { - download_policy->SetAllowed(NavigationDownloadType::kSandboxNoGesture); + + if (has_download_sandbox_flag) { + download_policy->SetAllowed(NavigationDownloadType::kSandbox); + if (!has_gesture) { + if (blocking_downloads_in_sandbox_without_user_activation_enabled) { + download_policy->SetDisallowed( + NavigationDownloadType::kSandboxNoGesture); + } else { + download_policy->SetAllowed(NavigationDownloadType::kSandboxNoGesture); + } } } + if (from_ad) { - if (!request.HasUserGesture()) { + download_policy->SetAllowed(NavigationDownloadType::kAdFrame); + if (!has_gesture) { if (base::FeatureList::IsEnabled( blink::features:: kBlockingDownloadsInAdFrameWithoutUserActivation)) { @@ -1775,8 +1787,6 @@ } else { download_policy->SetAllowed(NavigationDownloadType::kAdFrameNoGesture); } - } else { - download_policy->SetAllowed(NavigationDownloadType::kAdFrameGesture); } } }
diff --git a/content/renderer/render_process.cc b/content/renderer/render_process.cc index 0fdf095..9992d1f2b 100644 --- a/content/renderer/render_process.cc +++ b/content/renderer/render_process.cc
@@ -4,15 +4,28 @@ #include <utility> +#include "base/feature_list.h" #include "content/renderer/render_process.h" +#include "third_party/blink/public/common/features.h" namespace content { +namespace { + +base::ThreadPriority GetRenderIOThreadPriority() { + if (base::FeatureList::IsEnabled( + blink::features::kBlinkCompositorUseDisplayThreadPriority)) + return base::ThreadPriority::DISPLAY; + return base::ThreadPriority::NORMAL; +} + +} // namespace + RenderProcess::RenderProcess( const std::string& thread_pool_name, std::unique_ptr<base::ThreadPoolInstance::InitParams> thread_pool_init_params) - : ChildProcess(base::ThreadPriority::NORMAL, + : ChildProcess(GetRenderIOThreadPriority(), thread_pool_name, std::move(thread_pool_init_params)) {}
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index f2d4f932..76de46a 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -137,6 +137,7 @@ #include "services/viz/public/cpp/gpu/context_provider_command_buffer.h" #include "services/viz/public/cpp/gpu/gpu.h" #include "skia/ext/skia_memory_dump_provider.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h" #include "third_party/blink/public/platform/web_cache.h" #include "third_party/blink/public/platform/web_image_generator.h" @@ -927,8 +928,11 @@ discardable_shared_memory_manager_.get()); #if defined(OS_LINUX) - render_message_filter()->SetThreadPriority( - ChildProcess::current()->io_thread_id(), base::ThreadPriority::DISPLAY); + if (base::FeatureList::IsEnabled( + blink::features::kBlinkCompositorUseDisplayThreadPriority)) { + render_message_filter()->SetThreadPriority( + ChildProcess::current()->io_thread_id(), base::ThreadPriority::DISPLAY); + } #endif process_foregrounded_count_ = 0;
diff --git a/content/renderer/service_worker/controller_service_worker_connector.cc b/content/renderer/service_worker/controller_service_worker_connector.cc index 51a2ee1..6ade300 100644 --- a/content/renderer/service_worker/controller_service_worker_connector.cc +++ b/content/renderer/service_worker/controller_service_worker_connector.cc
@@ -12,14 +12,15 @@ ControllerServiceWorkerConnector::ControllerServiceWorkerConnector( blink::mojom::ServiceWorkerContainerHostPtrInfo container_host_info, - blink::mojom::ControllerServiceWorkerPtr controller_ptr, + mojo::PendingRemote<blink::mojom::ControllerServiceWorker> + remote_controller, const std::string& client_id) : client_id_(client_id) { container_host_ptr_.Bind(std::move(container_host_info)); container_host_ptr_.set_connection_error_handler(base::BindOnce( &ControllerServiceWorkerConnector::OnContainerHostConnectionClosed, base::Unretained(this))); - SetControllerServiceWorkerPtr(std::move(controller_ptr)); + SetControllerServiceWorker(std::move(remote_controller)); } blink::mojom::ControllerServiceWorker* @@ -29,10 +30,13 @@ case State::kDisconnected: { DCHECK(!controller_service_worker_); DCHECK(container_host_ptr_); - blink::mojom::ControllerServiceWorkerPtr controller_ptr; + mojo::PendingRemote<blink::mojom::ControllerServiceWorker> + remote_controller; + container_host_ptr_->EnsureControllerServiceWorker( - mojo::MakeRequest(&controller_ptr), purpose); - SetControllerServiceWorkerPtr(std::move(controller_ptr)); + remote_controller.InitWithNewPipeAndPassReceiver(), purpose); + + SetControllerServiceWorker(std::move(remote_controller)); return controller_service_worker_.get(); } case State::kConnected: @@ -78,19 +82,22 @@ } void ControllerServiceWorkerConnector::UpdateController( - blink::mojom::ControllerServiceWorkerPtr controller_ptr) { + mojo::PendingRemote<blink::mojom::ControllerServiceWorker> controller) { if (state_ == State::kNoContainerHost) return; - SetControllerServiceWorkerPtr(std::move(controller_ptr)); + SetControllerServiceWorker(std::move(controller)); if (!controller_service_worker_) state_ = State::kNoController; } -void ControllerServiceWorkerConnector::SetControllerServiceWorkerPtr( - blink::mojom::ControllerServiceWorkerPtr controller_ptr) { - controller_service_worker_ = std::move(controller_ptr); +void ControllerServiceWorkerConnector::SetControllerServiceWorker( + mojo::PendingRemote<blink::mojom::ControllerServiceWorker> controller) { + controller_service_worker_.reset(); + if (!controller) + return; + controller_service_worker_.Bind(std::move(controller)); if (controller_service_worker_) { - controller_service_worker_.set_connection_error_handler(base::BindOnce( + controller_service_worker_.set_disconnect_handler(base::BindOnce( &ControllerServiceWorkerConnector::OnControllerConnectionClosed, base::Unretained(this))); state_ = State::kConnected;
diff --git a/content/renderer/service_worker/controller_service_worker_connector.h b/content/renderer/service_worker/controller_service_worker_connector.h index 5267fa1..14c1c1db 100644 --- a/content/renderer/service_worker/controller_service_worker_connector.h +++ b/content/renderer/service_worker/controller_service_worker_connector.h
@@ -12,6 +12,8 @@ #include "base/observer_list.h" #include "content/common/content_export.h" #include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/pending_remote.h" +#include "mojo/public/cpp/bindings/remote.h" #include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_container.mojom.h" @@ -56,7 +58,7 @@ }; // This class should only be created if a controller exists for the client. - // |controller_ptr| may be nullptr if the caller does not yet have a Mojo + // |remote_controller| may be nullptr if the caller does not yet have a Mojo // connection to the controller. |state_| is set to kDisconnected in that // case. // Creates and holds the ownership of |container_host_ptr_| (as |this| @@ -64,7 +66,8 @@ // original |container_host|). ControllerServiceWorkerConnector( blink::mojom::ServiceWorkerContainerHostPtrInfo container_host_info, - blink::mojom::ControllerServiceWorkerPtr controller_ptr, + mojo::PendingRemote<blink::mojom::ControllerServiceWorker> + remote_controller, const std::string& client_id); // This may return nullptr if the connection to the ContainerHost (in the @@ -83,15 +86,16 @@ // blink::mojom::ControllerServiceWorkerConnector: void UpdateController( - blink::mojom::ControllerServiceWorkerPtr controller_ptr) override; + mojo::PendingRemote<blink::mojom::ControllerServiceWorker> controller) + override; State state() const { return state_; } const std::string& client_id() const { return client_id_; } private: - void SetControllerServiceWorkerPtr( - blink::mojom::ControllerServiceWorkerPtr controller_ptr); + void SetControllerServiceWorker( + mojo::PendingRemote<blink::mojom::ControllerServiceWorker> controller); State state_ = State::kDisconnected; @@ -105,7 +109,8 @@ // Connection to the controller service worker, which lives in a renderer // process that's not necessarily the same as this connector. - blink::mojom::ControllerServiceWorkerPtr controller_service_worker_; + mojo::Remote<blink::mojom::ControllerServiceWorker> + controller_service_worker_; base::ObserverList<Observer>::Unchecked observer_list_;
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc index 69c312e4..4aa6d26 100644 --- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc +++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -66,7 +66,7 @@ !params->installed_scripts_info.is_null(), std::move(params->renderer_preferences), std::move(params->service_worker_request), - std::move(params->controller_request), std::move(params->instance_host), + std::move(params->controller_receiver), std::move(params->instance_host), std::move(params->provider_info), this, std::move(start_timing), std::move(params->preference_watcher_request), std::move(params->subresource_loader_factories),
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc index 3818e4c..faae45f 100644 --- a/content/renderer/service_worker/service_worker_context_client.cc +++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -100,7 +100,8 @@ bool is_starting_installed_worker, blink::mojom::RendererPreferencesPtr renderer_preferences, blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> + controller_receiver, blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, EmbeddedWorkerInstanceClientImpl* owner, @@ -119,7 +120,7 @@ main_thread_task_runner_(std::move(main_thread_task_runner)), proxy_(nullptr), pending_service_worker_request_(std::move(service_worker_request)), - pending_controller_request_(std::move(controller_request)), + controller_receiver_(std::move(controller_receiver)), pending_subresource_loader_updater_( std::move(subresource_loader_updater)), owner_(owner), @@ -253,9 +254,8 @@ DCHECK(pending_service_worker_request_.is_pending()); proxy_->BindServiceWorker(pending_service_worker_request_.PassMessagePipe()); - DCHECK(pending_controller_request_.is_pending()); - proxy_->BindControllerServiceWorker( - pending_controller_request_.PassMessagePipe()); + DCHECK(controller_receiver_.is_valid()); + proxy_->BindControllerServiceWorker(controller_receiver_.PassPipe()); } void ServiceWorkerContextClient::WillEvaluateScript() {
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h index 5055b7e..2ac29fd 100644 --- a/content/renderer/service_worker/service_worker_context_client.h +++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -21,6 +21,7 @@ #include "content/common/content_export.h" #include "ipc/ipc_listener.h" #include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" #include "third_party/blink/public/common/service_worker/service_worker_status_code.h" #include "third_party/blink/public/mojom/background_fetch/background_fetch.mojom.h" #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h" @@ -83,7 +84,8 @@ bool is_starting_installed_worker, blink::mojom::RendererPreferencesPtr renderer_preferences, blink::mojom::ServiceWorkerRequest service_worker_request, - blink::mojom::ControllerServiceWorkerRequest controller_request, + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> + controller_receiver, blink::mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host, blink::mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info, EmbeddedWorkerInstanceClientImpl* owner, @@ -208,7 +210,8 @@ // These Mojo objects are bound on the worker thread. blink::mojom::ServiceWorkerRequest pending_service_worker_request_; - blink::mojom::ControllerServiceWorkerRequest pending_controller_request_; + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> + controller_receiver_; mojo::PendingReceiver<blink::mojom::ServiceWorkerSubresourceLoaderUpdater> pending_subresource_loader_updater_;
diff --git a/content/renderer/service_worker/service_worker_provider_context.cc b/content/renderer/service_worker/service_worker_provider_context.cc index 3eaf172..9bf7b557 100644 --- a/content/renderer/service_worker/service_worker_provider_context.cc +++ b/content/renderer/service_worker/service_worker_provider_context.cc
@@ -20,6 +20,7 @@ #include "content/renderer/service_worker/service_worker_subresource_loader.h" #include "content/renderer/service_worker/web_service_worker_provider_impl.h" #include "content/renderer/worker/worker_thread_registry.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h" @@ -31,16 +32,15 @@ void CreateSubresourceLoaderFactoryForProviderContext( blink::mojom::ServiceWorkerContainerHostPtrInfo container_host_info, - blink::mojom::ControllerServiceWorkerPtrInfo controller_ptr_info, + mojo::PendingRemote<blink::mojom::ControllerServiceWorker> + remote_controller, const std::string& client_id, std::unique_ptr<network::SharedURLLoaderFactoryInfo> fallback_factory_info, blink::mojom::ControllerServiceWorkerConnectorRequest connector_request, network::mojom::URLLoaderFactoryRequest request, scoped_refptr<base::SequencedTaskRunner> task_runner) { - blink::mojom::ControllerServiceWorkerPtr controller_ptr; - controller_ptr.Bind(std::move(controller_ptr_info)); auto connector = base::MakeRefCounted<ControllerServiceWorkerConnector>( - std::move(container_host_info), std::move(controller_ptr), client_id); + std::move(container_host_info), std::move(remote_controller), client_id); connector->AddBinding(std::move(connector_request)); ServiceWorkerSubresourceLoaderFactory::Create( std::move(connector), @@ -95,7 +95,7 @@ network::mojom::URLLoaderFactory* ServiceWorkerProviderContext::GetSubresourceLoaderFactoryInternal() { - if (!controller_endpoint_ && !controller_connector_) { + if (!remote_controller_ && !controller_connector_) { // No controller is attached. return nullptr; } @@ -108,7 +108,7 @@ if (!subresource_loader_factory_) { DCHECK(!controller_connector_); - DCHECK(controller_endpoint_); + DCHECK(remote_controller_); blink::mojom::ServiceWorkerContainerHostPtrInfo host_ptr_info = CloneContainerHostPtrInfo(); @@ -121,12 +121,12 @@ {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); task_runner->PostTask( FROM_HERE, - base::BindOnce( - &CreateSubresourceLoaderFactoryForProviderContext, - std::move(host_ptr_info), std::move(controller_endpoint_), - client_id_, fallback_loader_factory_->Clone(), - mojo::MakeRequest(&controller_connector_), - mojo::MakeRequest(&subresource_loader_factory_), task_runner)); + base::BindOnce(&CreateSubresourceLoaderFactoryForProviderContext, + std::move(host_ptr_info), std::move(remote_controller_), + client_id_, fallback_loader_factory_->Clone(), + mojo::MakeRequest(&controller_connector_), + mojo::MakeRequest(&subresource_loader_factory_), + task_runner)); DCHECK(!weak_wrapped_subresource_loader_factory_); weak_wrapped_subresource_loader_factory_ = @@ -285,7 +285,7 @@ blink::mojom::ControllerServiceWorkerMode::kNoController && controller_)); controller_mode_ = controller_info->mode; - controller_endpoint_ = std::move(controller_info->endpoint); + remote_controller_ = std::move(controller_info->remote_controller); // Propagate the controller to workers related to this provider. if (controller_) { @@ -319,9 +319,7 @@ // the existing controller or may use the new controller settings // depending on when the request is actually passed to the factory (this // part is inherently racy). - controller_connector_->UpdateController( - blink::mojom::ControllerServiceWorkerPtr( - std::move(controller_endpoint_))); + controller_connector_->UpdateController(std::move(remote_controller_)); } }
diff --git a/content/renderer/service_worker/service_worker_provider_context.h b/content/renderer/service_worker/service_worker_provider_context.h index e21aefc..a337bf0 100644 --- a/content/renderer/service_worker/service_worker_provider_context.h +++ b/content/renderer/service_worker/service_worker_provider_context.h
@@ -17,6 +17,7 @@ #include "content/common/content_export.h" #include "mojo/public/cpp/bindings/associated_binding.h" #include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/pending_remote.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" #include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom.h" #include "third_party/blink/public/mojom/service_worker/service_worker_container.mojom.h" @@ -287,7 +288,7 @@ // Used in |subresource_loader_factory_| to get the connection to the // controller service worker. // - // |controller_endpoint_| is a Mojo pipe to the controller service worker, + // |remote_controller_| is a Mojo pipe to the controller service worker, // and is to be passed to (i.e. taken by) a subresource loader factory when // GetSubresourceLoaderFactory() is called for the first time when a valid // controller exists. @@ -297,7 +298,7 @@ // subresource loader factory and lives on a background thread. This is // populated when GetSubresourceLoader() creates the subresource loader // factory and takes |controller_endpoint_|. - blink::mojom::ControllerServiceWorkerPtrInfo controller_endpoint_; + mojo::PendingRemote<blink::mojom::ControllerServiceWorker> remote_controller_; blink::mojom::ControllerServiceWorkerConnectorPtr controller_connector_; bool sent_execution_ready_ = false;
diff --git a/content/renderer/service_worker/service_worker_provider_context_unittest.cc b/content/renderer/service_worker/service_worker_provider_context_unittest.cc index b6b0a1b..ca58610 100644 --- a/content/renderer/service_worker/service_worker_provider_context_unittest.cc +++ b/content/renderer/service_worker/service_worker_provider_context_unittest.cc
@@ -23,6 +23,8 @@ #include "content/renderer/service_worker/controller_service_worker_connector.h" #include "content/renderer/service_worker/web_service_worker_provider_impl.h" #include "mojo/public/cpp/bindings/associated_binding_set.h" +#include "mojo/public/cpp/bindings/receiver_set.h" +#include "mojo/public/cpp/bindings/remote.h" #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" #include "services/network/public/cpp/features.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -193,8 +195,9 @@ if (fetch_event_callback_) std::move(fetch_event_callback_).Run(); } - void Clone(blink::mojom::ControllerServiceWorkerRequest request) override { - bindings_.AddBinding(this, std::move(request)); + void Clone(mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> + receiver) override { + receivers_.Add(this, std::move(receiver)); } void set_fetch_callback(base::OnceClosure closure) { @@ -205,13 +208,13 @@ return *fetch_event_request_; } - void Disconnect() { bindings_.CloseAllBindings(); } + void Disconnect() { receivers_.Clear(); } private: int fetch_event_count_ = 0; blink::mojom::FetchAPIRequestPtr fetch_event_request_; base::OnceClosure fetch_event_callback_; - mojo::BindingSet<blink::mojom::ControllerServiceWorker> bindings_; + mojo::ReceiverSet<blink::mojom::ControllerServiceWorker> receivers_; DISALLOW_COPY_AND_ASSIGN(FakeControllerServiceWorker); }; @@ -242,7 +245,7 @@ NOTIMPLEMENTED(); } void EnsureControllerServiceWorker( - blink::mojom::ControllerServiceWorkerRequest request, + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> receiver, blink::mojom::ControllerServiceWorkerPurpose purpose) override { NOTIMPLEMENTED(); } @@ -436,12 +439,12 @@ // Make the ControllerServiceWorkerInfo. FakeControllerServiceWorker fake_controller1; auto controller_info1 = blink::mojom::ControllerServiceWorkerInfo::New(); - blink::mojom::ControllerServiceWorkerPtr controller_ptr1; - fake_controller1.Clone(mojo::MakeRequest(&controller_ptr1)); + mojo::Remote<blink::mojom::ControllerServiceWorker> remote_controller1; + fake_controller1.Clone(remote_controller1.BindNewPipeAndPassReceiver()); controller_info1->mode = blink::mojom::ControllerServiceWorkerMode::kControlled; controller_info1->object_info = std::move(object_info1); - controller_info1->endpoint = controller_ptr1.PassInterface(); + controller_info1->remote_controller = remote_controller1.Unbind(); // Make the ServiceWorkerProviderContext, pasing it the controller, container, // and container host. @@ -479,12 +482,12 @@ EXPECT_EQ(1, object_host2->GetBindingCount()); FakeControllerServiceWorker fake_controller2; auto controller_info2 = blink::mojom::ControllerServiceWorkerInfo::New(); - blink::mojom::ControllerServiceWorkerPtr controller_ptr2; - fake_controller2.Clone(mojo::MakeRequest(&controller_ptr2)); + mojo::Remote<blink::mojom::ControllerServiceWorker> remote_controller2; + fake_controller2.Clone(remote_controller2.BindNewPipeAndPassReceiver()); controller_info2->mode = blink::mojom::ControllerServiceWorkerMode::kControlled; controller_info2->object_info = std::move(object_info2); - controller_info2->endpoint = controller_ptr2.PassInterface(); + controller_info2->remote_controller = remote_controller2.Unbind(); // Resetting the controller will trigger many things happening, including the // object binding being broken. @@ -568,12 +571,12 @@ EXPECT_EQ(1, object_host4->GetBindingCount()); FakeControllerServiceWorker fake_controller4; auto controller_info4 = blink::mojom::ControllerServiceWorkerInfo::New(); - blink::mojom::ControllerServiceWorkerPtr controller_ptr4; - fake_controller4.Clone(mojo::MakeRequest(&controller_ptr4)); + mojo::Remote<blink::mojom::ControllerServiceWorker> remote_controller4; + fake_controller4.Clone(remote_controller4.BindNewPipeAndPassReceiver()); controller_info4->mode = blink::mojom::ControllerServiceWorkerMode::kControlled; controller_info4->object_info = std::move(object_info4); - controller_info4->endpoint = controller_ptr4.PassInterface(); + controller_info4->remote_controller = remote_controller4.Unbind(); container_ptr->SetController(std::move(controller_info4), true); container_ptr.FlushForTesting(); @@ -718,12 +721,12 @@ // Make the ControllerServiceWorkerInfo. FakeControllerServiceWorker fake_controller; auto controller_info = blink::mojom::ControllerServiceWorkerInfo::New(); - blink::mojom::ControllerServiceWorkerPtr controller_ptr; - fake_controller.Clone(mojo::MakeRequest(&controller_ptr)); + mojo::Remote<blink::mojom::ControllerServiceWorker> remote_controller; + fake_controller.Clone(remote_controller.BindNewPipeAndPassReceiver()); controller_info->mode = blink::mojom::ControllerServiceWorkerMode::kControlled; controller_info->object_info = std::move(object_info); - controller_info->endpoint = controller_ptr.PassInterface(); + controller_info->remote_controller = remote_controller.Unbind(); // Make the container host and container pointers. blink::mojom::ServiceWorkerContainerHostAssociatedPtr host_ptr; @@ -765,12 +768,12 @@ // Make the ControllerServiceWorkerInfo. FakeControllerServiceWorker fake_controller; auto controller_info = blink::mojom::ControllerServiceWorkerInfo::New(); - blink::mojom::ControllerServiceWorkerPtr controller_ptr; - fake_controller.Clone(mojo::MakeRequest(&controller_ptr)); + mojo::Remote<blink::mojom::ControllerServiceWorker> remote_controller; + fake_controller.Clone(remote_controller.BindNewPipeAndPassReceiver()); controller_info->mode = blink::mojom::ControllerServiceWorkerMode::kControlled; controller_info->object_info = std::move(object_info); - controller_info->endpoint = controller_ptr.PassInterface(); + controller_info->remote_controller = remote_controller.Unbind(); // Make the container host and container pointers. blink::mojom::ServiceWorkerContainerHostAssociatedPtr host_ptr;
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc index 6aa478d..e518bd80 100644 --- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc +++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -21,6 +21,7 @@ #include "content/public/test/test_browser_thread_bundle.h" #include "content/renderer/service_worker/controller_service_worker_connector.h" #include "content/test/fake_network_url_loader_factory.h" +#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/system/data_pipe_utils.h" #include "net/http/http_util.h" @@ -118,7 +119,7 @@ return response; } - void CloseAllBindings() { bindings_.CloseAllBindings(); } + void ClearReceivers() { receivers_.Clear(); } // Tells this controller to abort the fetch event without a response. // i.e., simulate the service worker failing to handle the fetch event. @@ -301,8 +302,9 @@ std::move(fetch_event_callback_).Run(); } - void Clone(blink::mojom::ControllerServiceWorkerRequest request) override { - bindings_.AddBinding(this, std::move(request)); + void Clone(mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> + receiver) override { + receivers_.Add(this, std::move(receiver)); } void RunUntilFetchEvent() { @@ -334,7 +336,7 @@ int fetch_event_count_ = 0; blink::mojom::FetchAPIRequestPtr fetch_event_request_; base::OnceClosure fetch_event_callback_; - mojo::BindingSet<blink::mojom::ControllerServiceWorker> bindings_; + mojo::ReceiverSet<blink::mojom::ControllerServiceWorker> receivers_; // For ResponseMode::kStream. blink::mojom::ServiceWorkerStreamHandlePtr stream_handle_; @@ -389,12 +391,12 @@ NOTIMPLEMENTED(); } void EnsureControllerServiceWorker( - blink::mojom::ControllerServiceWorkerRequest request, + mojo::PendingReceiver<blink::mojom::ControllerServiceWorker> receiver, blink::mojom::ControllerServiceWorkerPurpose purpose) override { get_controller_service_worker_count_++; if (!fake_controller_) return; - fake_controller_->Clone(std::move(request)); + fake_controller_->Clone(std::move(receiver)); } void CloneContainerHost( blink::mojom::ServiceWorkerContainerHostRequest request) override { @@ -455,7 +457,7 @@ fake_container_host_.CloneContainerHost( mojo::MakeRequest(&host_ptr_info)); connector_ = base::MakeRefCounted<ControllerServiceWorkerConnector>( - std::move(host_ptr_info), nullptr /*controller_ptr*/, + std::move(host_ptr_info), mojo::NullRemote() /*remote_controller*/, "" /*client_id*/); } network::mojom::URLLoaderFactoryPtr service_worker_url_loader_factory; @@ -685,7 +687,7 @@ } // Drop the connection to the ControllerServiceWorker. - fake_controller_.CloseAllBindings(); + fake_controller_.ClearReceivers(); base::RunLoop().RunUntilIdle(); { @@ -722,7 +724,7 @@ } // Make the connector have no controller. - connector_->UpdateController(nullptr); + connector_->UpdateController(mojo::NullRemote()); base::RunLoop().RunUntilIdle(); base::HistogramTester histogram_tester; @@ -796,7 +798,7 @@ StartRequest(factory, request, &loader, &client); // Drop the connection to the ControllerServiceWorker. - fake_controller_.CloseAllBindings(); + fake_controller_.ClearReceivers(); base::RunLoop().RunUntilIdle(); // If connection is closed during fetch event, it's restarted and successfully
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index b0c56968..f68c93a 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -189,6 +189,8 @@ "browser/web_test/web_test_browser_main_parts.h", "browser/web_test/web_test_content_browser_client.cc", "browser/web_test/web_test_content_browser_client.h", + "browser/web_test/web_test_content_index_provider.cc", + "browser/web_test/web_test_content_index_provider.h", "browser/web_test/web_test_devtools_bindings.cc", "browser/web_test/web_test_devtools_bindings.h", "browser/web_test/web_test_download_manager_delegate.cc",
diff --git a/content/shell/browser/web_test/web_test_browser_context.cc b/content/shell/browser/web_test/web_test_browser_context.cc index 0635ec4d..05ad83f 100644 --- a/content/shell/browser/web_test/web_test_browser_context.cc +++ b/content/shell/browser/web_test/web_test_browser_context.cc
@@ -18,6 +18,7 @@ #include "content/public/browser/resource_context.h" #include "content/shell/browser/shell_url_request_context_getter.h" #include "content/shell/browser/web_test/web_test_background_fetch_delegate.h" +#include "content/shell/browser/web_test/web_test_content_index_provider.h" #include "content/shell/browser/web_test/web_test_download_manager_delegate.h" #include "content/shell/browser/web_test/web_test_permission_manager.h" #include "content/shell/browser/web_test/web_test_push_messaging_service.h" @@ -70,9 +71,8 @@ } PushMessagingService* WebTestBrowserContext::GetPushMessagingService() { - if (!push_messaging_service_) { + if (!push_messaging_service_) push_messaging_service_ = std::make_unique<WebTestPushMessagingService>(); - } return push_messaging_service_.get(); } @@ -104,4 +104,10 @@ GetPermissionControllerDelegate()); } +ContentIndexProvider* WebTestBrowserContext::GetContentIndexProvider() { + if (!content_index_provider_) + content_index_provider_ = std::make_unique<WebTestContentIndexProvider>(); + return content_index_provider_.get(); +} + } // namespace content
diff --git a/content/shell/browser/web_test/web_test_browser_context.h b/content/shell/browser/web_test/web_test_browser_context.h index 22e140d8..45bf4e0 100644 --- a/content/shell/browser/web_test/web_test_browser_context.h +++ b/content/shell/browser/web_test/web_test_browser_context.h
@@ -11,21 +11,22 @@ namespace device { class ScopedGeolocationOverrider; -} +} // namespace device namespace content { class BackgroundSyncController; +class ContentIndexProvider; class DownloadManagerDelegate; +class PermissionControllerDelegate; +class PushMessagingService; class WebTestBackgroundFetchDelegate; class WebTestPermissionManager; class WebTestPushMessagingService; -class PermissionControllerDelegate; -class PushMessagingService; class WebTestBrowserContext final : public ShellBrowserContext { public: - WebTestBrowserContext(bool off_the_record); + explicit WebTestBrowserContext(bool off_the_record); ~WebTestBrowserContext() override; // BrowserContext implementation. @@ -34,6 +35,7 @@ PermissionControllerDelegate* GetPermissionControllerDelegate() override; BackgroundFetchDelegate* GetBackgroundFetchDelegate() override; BackgroundSyncController* GetBackgroundSyncController() override; + ContentIndexProvider* GetContentIndexProvider() override; WebTestPermissionManager* GetWebTestPermissionManager(); @@ -48,6 +50,7 @@ std::unique_ptr<WebTestBackgroundFetchDelegate> background_fetch_delegate_; std::unique_ptr<BackgroundSyncController> background_sync_controller_; std::unique_ptr<device::ScopedGeolocationOverrider> geolocation_overrider_; + std::unique_ptr<ContentIndexProvider> content_index_provider_; DISALLOW_COPY_AND_ASSIGN(WebTestBrowserContext); };
diff --git a/content/shell/browser/web_test/web_test_content_index_provider.cc b/content/shell/browser/web_test/web_test_content_index_provider.cc new file mode 100644 index 0000000..1da729d --- /dev/null +++ b/content/shell/browser/web_test/web_test_content_index_provider.cc
@@ -0,0 +1,33 @@ +// 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. + +#include "content/shell/browser/web_test/web_test_content_index_provider.h" + +namespace content { + +WebTestContentIndexProvider::WebTestContentIndexProvider() = default; + +WebTestContentIndexProvider::~WebTestContentIndexProvider() = default; + +void WebTestContentIndexProvider::OnContentAdded(ContentIndexEntry entry) { + entries_[entry.description->id] = { + entry.service_worker_registration_id, + url::Origin::Create(entry.launch_url.GetOrigin())}; +} + +void WebTestContentIndexProvider::OnContentDeleted( + int64_t service_worker_registration_id, + const url::Origin& origin, + const std::string& description_id) { + entries_.erase(description_id); +} + +std::pair<int64_t, url::Origin> +WebTestContentIndexProvider::GetRegistrationDataFromId(const std::string& id) { + if (!entries_.count(id)) + return {-1, url::Origin()}; + return entries_[id]; +} + +} // namespace content \ No newline at end of file
diff --git a/content/shell/browser/web_test/web_test_content_index_provider.h b/content/shell/browser/web_test/web_test_content_index_provider.h new file mode 100644 index 0000000..4755dc5 --- /dev/null +++ b/content/shell/browser/web_test/web_test_content_index_provider.h
@@ -0,0 +1,46 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_BROWSER_WEB_TEST_WEB_TEST_CONTENT_INDEX_PROVIDER_H_ +#define CONTENT_SHELL_BROWSER_WEB_TEST_WEB_TEST_CONTENT_INDEX_PROVIDER_H_ + +#include <map> +#include <string> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "content/public/browser/content_index_provider.h" +#include "url/origin.h" + +namespace content { + +// When using WebTestContentIndexProvider, IDs need to be globally unique, +// instead of per Service Worker. +class WebTestContentIndexProvider : public ContentIndexProvider { + public: + WebTestContentIndexProvider(); + ~WebTestContentIndexProvider() override; + + // ContentIndexProvider implementation. + void OnContentAdded(ContentIndexEntry entry) override; + void OnContentDeleted(int64_t service_worker_registration_id, + const url::Origin& origin, + const std::string& description_id) override; + + // Returns the Service Worker Registration ID and the origin of the Content + // Index entry registered with |id|. If |id| does not exist, invalid values + // are returned, which would cause DB tasks to fail. + std::pair<int64_t, url::Origin> GetRegistrationDataFromId( + const std::string& id); + + private: + // Map from |description_id| to <|service_worker_registration_id|, |origin|>. + std::map<std::string, std::pair<int64_t, url::Origin>> entries_; + + DISALLOW_COPY_AND_ASSIGN(WebTestContentIndexProvider); +}; + +} // namespace content + +#endif // CONTENT_SHELL_BROWSER_WEB_TEST_WEB_TEST_CONTENT_INDEX_PROVIDER_H_
diff --git a/content/shell/browser/web_test/web_test_message_filter.cc b/content/shell/browser/web_test/web_test_message_filter.cc index b77391de..9fb4f8d 100644 --- a/content/shell/browser/web_test/web_test_message_filter.cc +++ b/content/shell/browser/web_test/web_test_message_filter.cc
@@ -12,7 +12,9 @@ #include "base/threading/thread_restrictions.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/child_process_security_policy.h" +#include "content/public/browser/content_index_context.h" #include "content/public/browser/permission_type.h" +#include "content/public/browser/storage_partition.h" #include "content/public/test/web_test_support.h" #include "content/shell/browser/shell_browser_context.h" #include "content/shell/browser/shell_content_browser_client.h" @@ -20,6 +22,7 @@ #include "content/shell/browser/web_test/blink_test_controller.h" #include "content/shell/browser/web_test/web_test_browser_context.h" #include "content/shell/browser/web_test/web_test_content_browser_client.h" +#include "content/shell/browser/web_test/web_test_content_index_provider.h" #include "content/shell/browser/web_test/web_test_permission_manager.h" #include "content/shell/common/web_test/web_test_messages.h" #include "content/shell/test_runner/web_test_delegate.h" @@ -29,10 +32,13 @@ #include "storage/browser/database/database_tracker.h" #include "storage/browser/fileapi/isolated_context.h" #include "storage/browser/quota/quota_manager.h" +#include "url/origin.h" namespace content { -static MockPlatformNotificationService* GetMockPlatformNotificationService() { +namespace { + +MockPlatformNotificationService* GetMockPlatformNotificationService() { auto* client = WebTestContentBrowserClient::Get(); auto* context = client->GetWebTestBrowserContext(); auto* service = client->GetPlatformNotificationService(context); @@ -40,6 +46,23 @@ return static_cast<MockPlatformNotificationService*>(service); } +WebTestContentIndexProvider* GetWebTestContentIndexProvider() { + auto* client = WebTestContentBrowserClient::Get(); + auto* context = client->GetWebTestBrowserContext(); + return static_cast<WebTestContentIndexProvider*>( + context->GetContentIndexProvider()); +} + +ContentIndexContext* GetContentIndexContext(const url::Origin& origin) { + auto* client = WebTestContentBrowserClient::Get(); + auto* context = client->GetWebTestBrowserContext(); + auto* storage_partition = BrowserContext::GetStoragePartitionForSite( + context, origin.GetURL(), /* can_create= */ false); + return storage_partition->GetContentIndexContext(); +} + +} // namespace + WebTestMessageFilter::WebTestMessageFilter( int render_process_id, storage::DatabaseTracker* database_tracker, @@ -67,6 +90,7 @@ return database_tracker_->task_runner(); case WebTestHostMsg_SimulateWebNotificationClick::ID: case WebTestHostMsg_SimulateWebNotificationClose::ID: + case WebTestHostMsg_SimulateWebContentIndexDelete::ID: case WebTestHostMsg_SetPermission::ID: case WebTestHostMsg_ResetPermissions::ID: case WebTestHostMsg_WebTestRuntimeFlagsChanged::ID: @@ -91,6 +115,8 @@ OnSimulateWebNotificationClick) IPC_MESSAGE_HANDLER(WebTestHostMsg_SimulateWebNotificationClose, OnSimulateWebNotificationClose) + IPC_MESSAGE_HANDLER(WebTestHostMsg_SimulateWebContentIndexDelete, + OnSimulateWebContentIndexDelete) IPC_MESSAGE_HANDLER(WebTestHostMsg_DeleteAllCookies, OnDeleteAllCookies) IPC_MESSAGE_HANDLER(WebTestHostMsg_SetPermission, OnSetPermission) IPC_MESSAGE_HANDLER(WebTestHostMsg_ResetPermissions, OnResetPermissions) @@ -165,6 +191,20 @@ GetMockPlatformNotificationService()->SimulateClose(title, by_user); } +void WebTestMessageFilter::OnSimulateWebContentIndexDelete( + const std::string& id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + auto* provider = GetWebTestContentIndexProvider(); + + std::pair<int64_t, url::Origin> registration_data = + provider->GetRegistrationDataFromId(id); + + auto* context = GetContentIndexContext(registration_data.second); + context->OnUserDeletedItem(registration_data.first, registration_data.second, + id); +} + void WebTestMessageFilter::OnDeleteAllCookies() { DCHECK_CURRENTLY_ON(BrowserThread::UI); cookie_manager_->DeleteCookies(network::mojom::CookieDeletionFilter::New(),
diff --git a/content/shell/browser/web_test/web_test_message_filter.h b/content/shell/browser/web_test/web_test_message_filter.h index a1f7f1b..7ab9690 100644 --- a/content/shell/browser/web_test/web_test_message_filter.h +++ b/content/shell/browser/web_test/web_test_message_filter.h
@@ -21,21 +21,18 @@ namespace base { class DictionaryValue; -} +} // namespace base namespace network { namespace mojom { class NetworkContext; -} +} // namespace mojom } // namespace network namespace storage { -class QuotaManager; -} - -namespace storage { class DatabaseTracker; -} +class QuotaManager; +} // namespace storage namespace content { @@ -71,6 +68,7 @@ const base::Optional<int>& action_index, const base::Optional<base::string16>& reply); void OnSimulateWebNotificationClose(const std::string& title, bool by_user); + void OnSimulateWebContentIndexDelete(const std::string& id); void OnDeleteAllCookies(); void OnSetPermission(const std::string& name, blink::mojom::PermissionStatus status,
diff --git a/content/shell/common/web_test/web_test_messages.h b/content/shell/common/web_test/web_test_messages.h index 2815a455..f71dfc5 100644 --- a/content/shell/common/web_test/web_test_messages.h +++ b/content/shell/common/web_test/web_test_messages.h
@@ -34,6 +34,8 @@ IPC_MESSAGE_ROUTED2(WebTestHostMsg_SimulateWebNotificationClose, std::string /* title */, bool /* by_user */) +IPC_MESSAGE_ROUTED1(WebTestHostMsg_SimulateWebContentIndexDelete, + std::string /* id */) IPC_MESSAGE_ROUTED1(WebTestHostMsg_BlockThirdPartyCookies, bool /* block */) IPC_MESSAGE_ROUTED0(WebTestHostMsg_DeleteAllCookies) IPC_MESSAGE_ROUTED4(WebTestHostMsg_SetPermission,
diff --git a/content/shell/renderer/web_test/blink_test_runner.cc b/content/shell/renderer/web_test/blink_test_runner.cc index 0cd46067..35825bf 100644 --- a/content/shell/renderer/web_test/blink_test_runner.cc +++ b/content/shell/renderer/web_test/blink_test_runner.cc
@@ -312,6 +312,10 @@ by_user)); } +void BlinkTestRunner::SimulateWebContentIndexDelete(const std::string& id) { + Send(new WebTestHostMsg_SimulateWebContentIndexDelete(routing_id(), id)); +} + void BlinkTestRunner::SetDeviceScaleFactor(float factor) { content::SetDeviceScaleFactor(render_view(), factor); }
diff --git a/content/shell/renderer/web_test/blink_test_runner.h b/content/shell/renderer/web_test/blink_test_runner.h index ad5ee73..3ac87a6 100644 --- a/content/shell/renderer/web_test/blink_test_runner.h +++ b/content/shell/renderer/web_test/blink_test_runner.h
@@ -27,7 +27,7 @@ namespace base { class DictionaryValue; -} +} // namespace base namespace blink { class WebView; @@ -35,7 +35,7 @@ namespace test_runner { class AppBannerService; -} +} // namespace test_runner namespace content { @@ -86,6 +86,7 @@ const base::Optional<base::string16>& reply) override; void SimulateWebNotificationClose(const std::string& title, bool by_user) override; + void SimulateWebContentIndexDelete(const std::string& id) override; void SetDeviceScaleFactor(float factor) override; void SetDeviceColorSpace(const std::string& name) override; float GetWindowToViewportScale() override;
diff --git a/content/shell/test_runner/test_runner.cc b/content/shell/test_runner/test_runner.cc index d933c90..6f92838 100644 --- a/content/shell/test_runner/test_runner.cc +++ b/content/shell/test_runner/test_runner.cc
@@ -273,6 +273,7 @@ void InspectSecondaryWindow(); void SimulateWebNotificationClick(gin::Arguments* args); void SimulateWebNotificationClose(const std::string& title, bool by_user); + void SimulateWebContentIndexDelete(const std::string& id); void UseUnfortunateSynchronousResizeMode(); void WaitForPolicyDelegate(); void WaitUntilDone(); @@ -605,6 +606,8 @@ &TestRunnerBindings::SimulateWebNotificationClick) .SetMethod("simulateWebNotificationClose", &TestRunnerBindings::SimulateWebNotificationClose) + .SetMethod("simulateWebContentIndexDelete", + &TestRunnerBindings::SimulateWebContentIndexDelete) .SetProperty("tooltipText", &TestRunnerBindings::TooltipText) .SetMethod("useUnfortunateSynchronousResizeMode", &TestRunnerBindings::UseUnfortunateSynchronousResizeMode) @@ -1298,6 +1301,12 @@ runner_->SimulateWebNotificationClose(title, by_user); } +void TestRunnerBindings::SimulateWebContentIndexDelete(const std::string& id) { + if (!runner_) + return; + runner_->SimulateWebContentIndexDelete(id); +} + void TestRunnerBindings::SetHighlightAds() { if (view_runner_) view_runner_->SetHighlightAds(true); @@ -2560,6 +2569,10 @@ delegate_->SimulateWebNotificationClose(title, by_user); } +void TestRunner::SimulateWebContentIndexDelete(const std::string& id) { + delegate_->SimulateWebContentIndexDelete(id); +} + void TestRunner::SetAnimationRequiresRaster(bool do_raster) { animation_requires_raster_ = do_raster; }
diff --git a/content/shell/test_runner/test_runner.h b/content/shell/test_runner/test_runner.h index cbb532f..cbdce21 100644 --- a/content/shell/test_runner/test_runner.h +++ b/content/shell/test_runner/test_runner.h
@@ -506,6 +506,9 @@ // Simulates closing a Web Notification. void SimulateWebNotificationClose(const std::string& title, bool by_user); + // Simulates a user deleting a content index entry. + void SimulateWebContentIndexDelete(const std::string& id); + // Takes care of notifying the delegate after a change to web test runtime // flags. void OnWebTestRuntimeFlagsChanged();
diff --git a/content/shell/test_runner/web_test_delegate.h b/content/shell/test_runner/web_test_delegate.h index 0c6397d1..ea49e65a 100644 --- a/content/shell/test_runner/web_test_delegate.h +++ b/content/shell/test_runner/web_test_delegate.h
@@ -22,7 +22,7 @@ namespace base { class DictionaryValue; -} +} // namespace base namespace blink { struct Manifest; @@ -32,7 +32,7 @@ struct WebPluginParams; struct WebSize; class WebView; -} +} // namespace blink namespace test_runner { @@ -121,6 +121,9 @@ virtual void SimulateWebNotificationClose(const std::string& title, bool by_user) = 0; + // Controls Content Index entries. + virtual void SimulateWebContentIndexDelete(const std::string& id) = 0; + // Controls the device scale factor of the main WebView for hidpi tests. virtual void SetDeviceScaleFactor(float factor) = 0;
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index 05505a9..2f33a85e 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -179,7 +179,6 @@ crbug.com/976370 [ skia-renderer ] Pixel_CSS3DBlueBox [ Skip ] # Fails when the browser features SkiaRenderer & Vulkan are enabled on Linux -crbug.com/984954 [ linux skia-renderer use-vulkan ] Pixel_CanvasDisplayLinearRGBAccelerated2D [ Skip ] crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_CanvasDisplayLinearRGBUnaccelerated2D [ Skip ] crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_CanvasDisplayLinearRGBUnaccelerated2DGPUCompositing [ Skip ] crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_CanvasDisplaySRGBUnaccelerated2D [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index 6c114917..131e462f 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -262,6 +262,7 @@ # Passthrough command decoder / OpenGL / Windows crbug.com/835364 [ opengl win passthrough ] deqp/functional/gles3/fbocompleteness.html [ Failure ] crbug.com/835364 [ opengl win passthrough ] conformance/renderbuffers/depth-renderbuffer-initialization.html [ RetryOnFailure ] +crbug.com/angleproject/3742 [ opengl win passthrough ] conformance2/rendering/clearbuffer-sub-source.html [ Failure ] # Passthrough command decoder / Linux / OpenGL / NVIDIA crbug.com/766918 [ opengl linux passthrough nvidia ] conformance2/textures/image_bitmap_from_video/* [ RetryOnFailure ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 8b48838..8a50fe4 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -276,6 +276,7 @@ crbug.com/angleproject/2905 [ win vulkan passthrough ] WebglExtension_WEBGL_depth_texture [ Failure ] crbug.com/angleproject/2394 [ win vulkan passthrough ] WebglExtension_WEBGL_draw_buffers [ Failure ] crbug.com/angleproject/3111 [ win vulkan passthrough ] deqp/data/gles2/shaders/swizzles.html [ Skip ] +crbug.com/angleproject/3741 [ win vulkan passthrough ] conformance/textures/misc/mipmap-fbo.html [ RetryOnFailure ] # Vulkan / Win / NVIDIA / Passthrough command decoder crbug.com/angleproject/2918 [ win nvidia vulkan passthrough ] conformance/canvas/to-data-url-test.html [ Failure ] @@ -546,22 +547,6 @@ # expectation at the top of this file to just not declare any OS. crbug.com/986808 [ android opengles ] conformance/textures/misc/texture-corner-case-videos.html [ Failure ] -# Related to SharedImages -crbug.com/987228 [ android opengles passthrough ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_byte.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/misc/texture-upload-size.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_short_5_6_5.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/image_bitmap_from_video/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_byte.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/image_bitmap_from_video/tex-2d-rgb-rgb-unsigned_byte.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/misc/texture-npot-video.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/video/tex-2d-alpha-alpha-unsigned_byte.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/image_bitmap_from_video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/image_bitmap_from_video/tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html [ Failure ] -crbug.com/987228 [ android opengles passthrough ] conformance/textures/misc/tex-video-using-tex-unit-non-zero.html [ Failure ] - # Misc failures crbug.com/angleproject/2988 [ android opengles ] conformance/context/context-size-change.html [ Failure ]
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn index e8c4026..f96b016 100644 --- a/device/fido/BUILD.gn +++ b/device/fido/BUILD.gn
@@ -196,6 +196,8 @@ "mac/credential_metadata.h", "mac/credential_store.h", "mac/credential_store.mm", + "mac/discovery.cc", + "mac/discovery.h", "mac/get_assertion_operation.h", "mac/get_assertion_operation.mm", "mac/keychain.h",
diff --git a/device/fido/ble_adapter_manager_unittest.cc b/device/fido/ble_adapter_manager_unittest.cc index 30c78c3..a6b61424 100644 --- a/device/fido/ble_adapter_manager_unittest.cc +++ b/device/fido/ble_adapter_manager_unittest.cc
@@ -18,6 +18,7 @@ #include "device/fido/fido_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 "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -70,7 +71,9 @@ public: FakeFidoRequestHandlerBase(MockObserver* observer, FidoDiscoveryFactory* fido_discovery_factory) - : FidoRequestHandlerBase(nullptr, fido_discovery_factory, {}) { + : FidoRequestHandlerBase(nullptr, + fido_discovery_factory, + {FidoTransportProtocol::kBluetoothLowEnergy}) { set_observer(observer); } @@ -99,10 +102,6 @@ BluetoothAdapterFactory::SetAdapterForTesting(adapter_); } - std::unique_ptr<BleAdapterManager> CreateTestBleAdapterManager() { - return std::make_unique<BleAdapterManager>(fake_request_handler_.get()); - } - MockBluetoothDevice* AddMockBluetoothDeviceToAdapter() { auto mock_bluetooth_device = std::make_unique<MockBluetoothDevice>( adapter_.get(), 0 /* bluetooth_class */, kTestBluetoothDisplayName, @@ -154,7 +153,7 @@ fido_discovery_factory_.get()); }; -TEST_F(FidoBleAdapterManagerTest, AdapaterNotPresent) { +TEST_F(FidoBleAdapterManagerTest, AdapterNotPresent) { EXPECT_CALL(*adapter(), IsPresent()).WillOnce(::testing::Return(false)); EXPECT_CALL(*adapter(), IsPowered()).WillOnce(::testing::Return(false)); EXPECT_CALL(*adapter(), CanPower()).WillOnce(::testing::Return(false)); @@ -163,7 +162,6 @@ EXPECT_CALL(*observer(), OnTransportAvailabilityEnumerated(_)) .WillOnce(::testing::SaveArg<0>(&data)); - CreateTestBleAdapterManager(); scoped_task_environment_.RunUntilIdle(); EXPECT_FALSE(data.is_ble_powered); @@ -179,7 +177,6 @@ EXPECT_CALL(*observer(), OnTransportAvailabilityEnumerated(_)) .WillOnce(::testing::SaveArg<0>(&data)); - CreateTestBleAdapterManager(); scoped_task_environment_.RunUntilIdle(); EXPECT_TRUE(data.is_ble_powered); @@ -195,7 +192,6 @@ EXPECT_CALL(*observer(), OnTransportAvailabilityEnumerated(_)) .WillOnce(::testing::SaveArg<0>(&data)); - CreateTestBleAdapterManager(); scoped_task_environment_.RunUntilIdle(); EXPECT_FALSE(data.is_ble_powered); @@ -203,7 +199,9 @@ } TEST_F(FidoBleAdapterManagerTest, SetBluetoothPowerOn) { - auto power_manager = CreateTestBleAdapterManager(); + scoped_task_environment_.RunUntilIdle(); + auto& power_manager = + fake_request_handler_->get_bluetooth_adapter_manager_for_testing(); ::testing::InSequence s; EXPECT_CALL(*adapter(), SetPowered(true, _, _)); EXPECT_CALL(*adapter(), SetPowered(false, _, _)); @@ -229,7 +227,9 @@ })); EXPECT_CALL(*mock_bluetooth_device, SetPinCode(kTestPinCode)); - auto adapter_manager = CreateTestBleAdapterManager(); + scoped_task_environment_.RunUntilIdle(); + auto& adapter_manager = + fake_request_handler_->get_bluetooth_adapter_manager_for_testing(); test::TestCallbackReceiver<> callback_receiver; adapter_manager->InitiatePairing(kTestFidoBleAuthenticatorId, kTestPinCode, callback_receiver.callback(), @@ -251,7 +251,9 @@ .WillRepeatedly(::testing::Return(adapter()->GetConstMockDevices())); EXPECT_CALL(*mock_bluetooth_device, Pair).Times(0); - auto power_manager = CreateTestBleAdapterManager(); + scoped_task_environment_.RunUntilIdle(); + auto& power_manager = + fake_request_handler_->get_bluetooth_adapter_manager_for_testing(); test::TestCallbackReceiver<> callback_receiver; power_manager->InitiatePairing(kTestFidoBleAuthenticatorId, kTestPinCode, base::DoNothing(), @@ -276,7 +278,9 @@ success_callback.Run(); })); - auto adapter_manager = CreateTestBleAdapterManager(); + scoped_task_environment_.RunUntilIdle(); + auto& adapter_manager = + fake_request_handler_->get_bluetooth_adapter_manager_for_testing(); test::TestCallbackReceiver<> callback_receiver; adapter_manager->InitiatePairing(kTestFidoBleAuthenticatorId, kTestPinCode, callback_receiver.callback(),
diff --git a/device/fido/fake_fido_discovery.cc b/device/fido/fake_fido_discovery.cc index ded9ea9..1ea5307 100644 --- a/device/fido/fake_fido_discovery.cc +++ b/device/fido/fake_fido_discovery.cc
@@ -80,6 +80,13 @@ return next_cable_discovery_.get(); } +FakeFidoDiscovery* FakeFidoDiscoveryFactory::ForgeNextPlatformDiscovery( + FakeFidoDiscovery::StartMode mode) { + next_platform_discovery_ = std::make_unique<FakeFidoDiscovery>( + FidoTransportProtocol::kInternal, mode); + return next_platform_discovery_.get(); +} + std::unique_ptr<FidoDiscoveryBase> FakeFidoDiscoveryFactory::Create( FidoTransportProtocol transport, ::service_manager::Connector* connector) { @@ -94,8 +101,7 @@ NOTREACHED() << "CaBLE should be handled by CreateCable()."; return nullptr; case FidoTransportProtocol::kInternal: - NOTREACHED() << "Internal authenticators should be handled separately."; - return nullptr; + return std::move(next_platform_discovery_); } NOTREACHED(); return nullptr;
diff --git a/device/fido/fake_fido_discovery.h b/device/fido/fake_fido_discovery.h index 2576406..fe55962 100644 --- a/device/fido/fake_fido_discovery.h +++ b/device/fido/fake_fido_discovery.h
@@ -119,6 +119,8 @@ FakeFidoDiscovery* ForgeNextBleDiscovery(StartMode mode = StartMode::kManual); FakeFidoDiscovery* ForgeNextCableDiscovery( StartMode mode = StartMode::kManual); + FakeFidoDiscovery* ForgeNextPlatformDiscovery( + StartMode mode = StartMode::kManual); // device::FidoDiscoveryFactory: std::unique_ptr<FidoDiscoveryBase> Create( @@ -132,6 +134,7 @@ std::unique_ptr<FakeFidoDiscovery> next_nfc_discovery_; std::unique_ptr<FakeFidoDiscovery> next_ble_discovery_; std::unique_ptr<FakeFidoDiscovery> next_cable_discovery_; + std::unique_ptr<FakeFidoDiscovery> next_platform_discovery_; DISALLOW_COPY_AND_ASSIGN(FakeFidoDiscoveryFactory); };
diff --git a/device/fido/fido_discovery_factory.cc b/device/fido/fido_discovery_factory.cc index bfa1120a..bf94e5c 100644 --- a/device/fido/fido_discovery_factory.cc +++ b/device/fido/fido_discovery_factory.cc
@@ -5,7 +5,6 @@ #include "device/fido/fido_discovery_factory.h" #include "base/logging.h" -#include "build/build_config.h" #include "device/fido/ble/fido_ble_discovery.h" #include "device/fido/cable/fido_cable_discovery.h" #include "device/fido/features.h" @@ -22,6 +21,10 @@ #include "device/fido/win/webauthn_api.h" #endif // defined(OS_WIN) +#if defined(OS_MACOSX) +#include "device/fido/mac/discovery.h" +#endif // defined(OSMACOSX) + namespace device { namespace { @@ -40,6 +43,9 @@ } // namespace +FidoDiscoveryFactory::FidoDiscoveryFactory() = default; +FidoDiscoveryFactory::~FidoDiscoveryFactory() = default; + std::unique_ptr<FidoDiscoveryBase> FidoDiscoveryFactory::Create( FidoTransportProtocol transport, service_manager::Connector* connector) { @@ -56,8 +62,14 @@ // TODO(https://crbug.com/825949): Add NFC support. return nullptr; case FidoTransportProtocol::kInternal: - NOTREACHED() << "Internal authenticators should be handled separately."; +#if defined(OS_MACOSX) + return mac_touch_id_config_ + ? std::make_unique<fido::mac::FidoTouchIdDiscovery>( + *mac_touch_id_config_) + : nullptr; +#else return nullptr; +#endif // defined(OS_MACOSX) } NOTREACHED() << "Unhandled transport type"; return nullptr;
diff --git a/device/fido/fido_discovery_factory.h b/device/fido/fido_discovery_factory.h index 71a078f..236b15f 100644 --- a/device/fido/fido_discovery_factory.h +++ b/device/fido/fido_discovery_factory.h
@@ -9,12 +9,18 @@ #include <vector> #include "base/component_export.h" +#include "base/optional.h" #include "build/build_config.h" #include "device/fido/cable/cable_discovery_data.h" #include "device/fido/fido_device_discovery.h" #include "device/fido/fido_discovery_base.h" +#include "device/fido/fido_request_handler_base.h" #include "device/fido/fido_transport_protocol.h" +#if defined(OS_MACOSX) +#include "device/fido/mac/authenticator_config.h" +#endif // defined(OS_MACOSX) + namespace service_manager { class Connector; } @@ -25,8 +31,8 @@ // FidoDiscoveryBase for a given |transport| protocol. class COMPONENT_EXPORT(DEVICE_FIDO) FidoDiscoveryFactory { public: - FidoDiscoveryFactory() = default; - virtual ~FidoDiscoveryFactory() = default; + FidoDiscoveryFactory(); + virtual ~FidoDiscoveryFactory(); // Instantiates a FidoDiscoveryBase for all protocols except caBLE and // internal/platform. @@ -39,6 +45,15 @@ // Instantiates a FidoDiscovery for caBLE. virtual std::unique_ptr<FidoDiscoveryBase> CreateCable( std::vector<CableDiscoveryData> cable_data); + +#if defined(OS_MACOSX) + // Configures the Touch ID authenticator. Set to base::nullopt to disable it. + void set_mac_touch_id_info( + base::Optional<fido::mac::AuthenticatorConfig> mac_touch_id_config) { + mac_touch_id_config_ = std::move(mac_touch_id_config); + } +#endif // defined(OS_MACOSX) + #if defined(OS_WIN) // Instantiates a FidoDiscovery for the native Windows WebAuthn // API where available. Returns nullptr otherwise. @@ -46,6 +61,9 @@ #endif // defined(OS_WIN) private: +#if defined(OS_MACOSX) + base::Optional<fido::mac::AuthenticatorConfig> mac_touch_id_config_; +#endif // defined(OS_MACOSX) }; } // namespace device
diff --git a/device/fido/fido_request_handler_base.cc b/device/fido/fido_request_handler_base.cc index c10b539..dcad2b1 100644 --- a/device/fido/fido_request_handler_base.cc +++ b/device/fido/fido_request_handler_base.cc
@@ -24,20 +24,6 @@ namespace device { -// PlatformAuthenticatorInfo -------------------------- - -PlatformAuthenticatorInfo::PlatformAuthenticatorInfo( - std::unique_ptr<FidoAuthenticator> authenticator_, - bool has_recognized_mac_touch_id_credential_) - : authenticator(std::move(authenticator_)), - has_recognized_mac_touch_id_credential( - has_recognized_mac_touch_id_credential_) {} -PlatformAuthenticatorInfo::PlatformAuthenticatorInfo( - PlatformAuthenticatorInfo&&) = default; -PlatformAuthenticatorInfo& PlatformAuthenticatorInfo::operator=( - PlatformAuthenticatorInfo&&) = default; -PlatformAuthenticatorInfo::~PlatformAuthenticatorInfo() = default; - // FidoRequestHandlerBase::TransportAvailabilityInfo -------------------------- FidoRequestHandlerBase::TransportAvailabilityInfo::TransportAvailabilityInfo() = @@ -77,36 +63,42 @@ const base::flat_set<FidoTransportProtocol>& available_transports) { // The number of times |notify_observer_callback_| needs to be invoked before // Observer::OnTransportAvailabilityEnumerated is dispatched. Essentially this - // is used to wait until all the parts of |transport_availability_info_| are + // is used to wait until the parts |transport_availability_info_| are // filled out; the |notify_observer_callback_| is invoked once for each part // once that part is ready, namely: // - // 1) Once the platform authenticator related fields are filled out. - // 2) [Optionally, if BLE or caBLE enabled] if Bluetooth adapter is present. + // 1) [If the platform authenticator is enabled] once the platform + // authenticator is ready. + // 2) [If BLE or caBLE are enabled] if Bluetooth adapter is present. // // On top of that, we wait for (3) an invocation that happens when the // |observer_| is set, so that OnTransportAvailabilityEnumerated is never // called before the observer is set. - size_t transport_info_callback_count = 1u + 0u + 1u; + size_t transport_info_callback_count = 1u; #if defined(OS_WIN) if (transport_availability_info_.has_win_native_api_authenticator) - transport_info_callback_count++; + ++transport_info_callback_count; #endif // defined(OS_WIN) + transport_availability_info_.available_transports = available_transports; for (const auto transport : available_transports) { // Construction of CaBleDiscovery is handled by the implementing class as it // requires an extension passed on from the relying party. if (transport == FidoTransportProtocol::kCloudAssistedBluetoothLowEnergy) continue; + std::unique_ptr<FidoDiscoveryBase> discovery = + fido_discovery_factory_->Create(transport, connector_); if (transport == FidoTransportProtocol::kInternal) { - // Platform authenticator availability is always indicated by - // |AuthenticatorImpl|. - continue; + if (discovery) { + ++transport_info_callback_count; + } else { + // The platform authenticator is not configured for this request. + transport_availability_info_.available_transports.erase( + FidoTransportProtocol::kInternal); + } } - - auto discovery = fido_discovery_factory_->Create(transport, connector_); if (discovery == nullptr) { // This can occur in tests when a ScopedVirtualU2fDevice is in effect and // HID transports are not configured. @@ -128,7 +120,6 @@ weak_factory_.GetWeakPtr())); } - transport_availability_info_.available_transports = available_transports; notify_observer_callback_ = base::BarrierClosure( transport_info_callback_count, base::BindOnce( @@ -358,31 +349,12 @@ notify_observer_callback_.Run(); } #endif // defined(OS_WIN) -} -void FidoRequestHandlerBase::SetPlatformAuthenticatorOrMarkUnavailable( - base::Optional<PlatformAuthenticatorInfo> platform_authenticator_info) { - DCHECK(!platform_authenticator_); - if (platform_authenticator_info && - base::Contains(transport_availability_info_.available_transports, - FidoTransportProtocol::kInternal)) { - DCHECK(platform_authenticator_info->authenticator); - DCHECK( - platform_authenticator_info->authenticator->AuthenticatorTransport() && - *platform_authenticator_info->authenticator->AuthenticatorTransport() == - FidoTransportProtocol::kInternal); - transport_availability_info_.has_recognized_mac_touch_id_credential = - platform_authenticator_info->has_recognized_mac_touch_id_credential; - platform_authenticator_ = - std::move(platform_authenticator_info->authenticator); - AddAuthenticator(platform_authenticator_.get()); - } else { - transport_availability_info_.available_transports.erase( - FidoTransportProtocol::kInternal); + if (authenticator->AuthenticatorTransport() == + FidoTransportProtocol::kInternal) { + DCHECK(notify_observer_callback_); + notify_observer_callback_.Run(); } - - DCHECK(notify_observer_callback_); - notify_observer_callback_.Run(); } bool FidoRequestHandlerBase::HasAuthenticator(
diff --git a/device/fido/fido_request_handler_base.h b/device/fido/fido_request_handler_base.h index 56523f39..af0f5e4a 100644 --- a/device/fido/fido_request_handler_base.h +++ b/device/fido/fido_request_handler_base.h
@@ -34,17 +34,6 @@ class FidoAuthenticator; class FidoDiscoveryFactory; -struct COMPONENT_EXPORT(DEVICE_FIDO) PlatformAuthenticatorInfo { - PlatformAuthenticatorInfo(std::unique_ptr<FidoAuthenticator> authenticator, - bool has_recognized_mac_touch_id_credential); - PlatformAuthenticatorInfo(PlatformAuthenticatorInfo&&); - PlatformAuthenticatorInfo& operator=(PlatformAuthenticatorInfo&& other); - ~PlatformAuthenticatorInfo(); - - std::unique_ptr<FidoAuthenticator> authenticator; - bool has_recognized_mac_touch_id_credential; -}; - // Base class that handles authenticator discovery/removal. Its lifetime is // equivalent to that of a single WebAuthn request. For each authenticator, the // per-device work is carried out by one FidoAuthenticator instance, which is @@ -211,13 +200,6 @@ notify_observer_callback_.Run(); } - // Set the platform authenticator for this request, if one is available. - // |AuthenticatorImpl| must call this method after invoking |set_observer| - // even if no platform authenticator is available, in which case it passes - // nullptr. - virtual void SetPlatformAuthenticatorOrMarkUnavailable( - base::Optional<PlatformAuthenticatorInfo> platform_authenticator_info); - // Returns whether FidoAuthenticator with id equal to |authenticator_id| // exists. Fake FidoRequestHandler objects used in testing overrides this // function to simulate scenarios where authenticator with |authenticator_id| @@ -232,6 +214,11 @@ return active_authenticators_; } + std::unique_ptr<BleAdapterManager>& + get_bluetooth_adapter_manager_for_testing() { + return bluetooth_adapter_manager_; + } + protected: // Subclasses implement this method to dispatch their request onto the given // FidoAuthenticator. The FidoAuthenticator is owned by this @@ -286,9 +273,6 @@ TransportAvailabilityInfo transport_availability_info_; base::RepeatingClosure notify_observer_callback_; std::unique_ptr<BleAdapterManager> bluetooth_adapter_manager_; - // TODO(martinkr): Inject platform authenticators through a new - // FidoDiscoveryBase specialization and hold ownership there. - std::unique_ptr<FidoAuthenticator> platform_authenticator_; service_manager::Connector* const connector_; base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_;
diff --git a/device/fido/fido_request_handler_unittest.cc b/device/fido/fido_request_handler_unittest.cc index 5bb8f4a..8517667 100644 --- a/device/fido/fido_request_handler_unittest.cc +++ b/device/fido/fido_request_handler_unittest.cc
@@ -331,7 +331,6 @@ {FidoTransportProtocol::kUsbHumanInterfaceDevice, FidoTransportProtocol::kBluetoothLowEnergy}), cb_.callback()); - handler->SetPlatformAuthenticatorOrMarkUnavailable(base::nullopt); return handler; } @@ -556,8 +555,7 @@ // pending authenticators. TEST_F(FidoRequestHandlerTest, TestRequestWithOperationDeniedErrorInternalTransport) { - auto request_handler = CreateFakeHandler(); - discovery()->WaitForCallToStartAndSimulateSuccess(); + TestObserver observer; // Device will send CTAP2_ERR_OPERATION_DENIED. auto device0 = MockFidoDevice::MakeCtapWithGetInfoExpectation( @@ -567,12 +565,23 @@ CreateFakeOperationDeniedError(), base::TimeDelta::FromMicroseconds(10)); + ForgeNextHidDiscovery(); + auto* platform_discovery = + fake_discovery_factory_.ForgeNextPlatformDiscovery(); + auto request_handler = std::make_unique<FakeFidoRequestHandler>( + &fake_discovery_factory_, + base::flat_set<FidoTransportProtocol>( + {FidoTransportProtocol::kInternal, + FidoTransportProtocol::kUsbHumanInterfaceDevice}), + callback().callback()); + request_handler->set_observer(&observer); + auto device1 = MockFidoDevice::MakeCtapWithGetInfoExpectation(); device1->ExpectRequestAndDoNotRespond(std::vector<uint8_t>()); EXPECT_CALL(*device1, Cancel(_)); discovery()->AddDevice(std::move(device0)); - discovery()->AddDevice(std::move(device1)); + platform_discovery->AddDevice(std::move(device1)); scoped_task_environment_.FastForwardUntilNoTasksRemain(); callback().WaitForCallback(); @@ -606,9 +615,8 @@ EXPECT_EQ(FidoReturnCode::kUserConsentDenied, callback().status()); } -// Requests should be dispatched to the authenticator passed to -// SetPlatformAuthenticatorOrMarkUnavailable. -TEST_F(FidoRequestHandlerTest, TestSetPlatformAuthenticator) { +// Requests should be dispatched to the platform authenticator. +TEST_F(FidoRequestHandlerTest, TestWithPlatformAuthenticator) { // A platform authenticator usually wouldn't usually use a FidoDevice, but // that's not the point of the test here. The test is only trying to ensure // the authenticator gets injected and used. @@ -621,8 +629,7 @@ device->ExpectRequestAndRespondWith(std::vector<uint8_t>(), CreateFakeSuccessDeviceResponse()); device->SetDeviceTransport(FidoTransportProtocol::kInternal); - auto authenticator = - std::make_unique<FidoDeviceAuthenticator>(std::move(device)); + auto* fake_discovery = fake_discovery_factory_.ForgeNextPlatformDiscovery(); TestObserver observer; auto request_handler = std::make_unique<FakeFidoRequestHandler>( @@ -630,8 +637,7 @@ base::flat_set<FidoTransportProtocol>({FidoTransportProtocol::kInternal}), callback().callback()); request_handler->set_observer(&observer); - request_handler->SetPlatformAuthenticatorOrMarkUnavailable( - PlatformAuthenticatorInfo(std::move(authenticator), false)); + fake_discovery->AddDevice(std::move(device)); observer.WaitForAndExpectAvailableTransportsAre( {FidoTransportProtocol::kInternal}, @@ -642,43 +648,6 @@ EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); } -// SetPlatformAuthenticatorOrMarkUnavailable should propagate the -// has_recognized_mac_touch_id_credential field. -TEST_F(FidoRequestHandlerTest, - TestSetPlatformAuthenticatorHasTouchIdCredential) { - // A platform authenticator usually wouldn't usually use a FidoDevice, but - // that's not the point of the test here. The test is only trying to ensure - // the authenticator gets injected and used. - auto device = MockFidoDevice::MakeCtap(); - EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); - // Device returns success response. - device->ExpectCtap2CommandAndRespondWith( - CtapRequestCommand::kAuthenticatorGetInfo, - test_data::kTestAuthenticatorGetInfoResponse); - device->ExpectRequestAndRespondWith(std::vector<uint8_t>(), - CreateFakeSuccessDeviceResponse()); - device->SetDeviceTransport(FidoTransportProtocol::kInternal); - auto authenticator = - std::make_unique<FidoDeviceAuthenticator>(std::move(device)); - - TestObserver observer; - auto request_handler = std::make_unique<FakeFidoRequestHandler>( - &fake_discovery_factory_, - base::flat_set<FidoTransportProtocol>({FidoTransportProtocol::kInternal}), - callback().callback()); - request_handler->set_observer(&observer); - request_handler->SetPlatformAuthenticatorOrMarkUnavailable( - PlatformAuthenticatorInfo(std::move(authenticator), true)); - - observer.WaitForAndExpectAvailableTransportsAre( - {FidoTransportProtocol::kInternal}, - true /* has_recognized_mac_touch_id_credential */); - - callback().WaitForCallback(); - EXPECT_TRUE(request_handler->is_complete()); - EXPECT_EQ(FidoReturnCode::kSuccess, callback().status()); -} - TEST_F(FidoRequestHandlerTest, InternalTransportDisallowedIfMarkedUnavailable) { TestObserver observer; auto request_handler = std::make_unique<FakeFidoRequestHandler>( @@ -686,7 +655,6 @@ base::flat_set<FidoTransportProtocol>({FidoTransportProtocol::kInternal}), callback().callback()); request_handler->set_observer(&observer); - request_handler->SetPlatformAuthenticatorOrMarkUnavailable(base::nullopt); observer.WaitForAndExpectAvailableTransportsAre({}); } @@ -756,7 +724,6 @@ EmptyRequestHandler request_handler( {FidoTransportProtocol::kUsbHumanInterfaceDevice}, &fake_discovery_factory_); - request_handler.SetPlatformAuthenticatorOrMarkUnavailable(base::nullopt); request_handler.set_observer(&observer); scoped_task_environment_.FastForwardUntilNoTasksRemain();
diff --git a/device/fido/get_assertion_handler_unittest.cc b/device/fido/get_assertion_handler_unittest.cc index 0e38841..dbd2d1e 100644 --- a/device/fido/get_assertion_handler_unittest.cc +++ b/device/fido/get_assertion_handler_unittest.cc
@@ -66,6 +66,7 @@ ble_discovery_ = fake_discovery_factory_->ForgeNextBleDiscovery(); cable_discovery_ = fake_discovery_factory_->ForgeNextCableDiscovery(); nfc_discovery_ = fake_discovery_factory_->ForgeNextNfcDiscovery(); + platform_discovery_ = fake_discovery_factory_->ForgeNextPlatformDiscovery(); } CtapGetAssertionRequest CreateTestRequestWithCableExtension() { @@ -102,8 +103,6 @@ nullptr /* connector */, fake_discovery_factory_.get(), supported_transports_, std::move(request), get_assertion_cb_.callback()); - handler->SetPlatformAuthenticatorOrMarkUnavailable( - CreatePlatformAuthenticator()); return handler; } @@ -119,6 +118,8 @@ cable_discovery()->WaitForCallToStartAndSimulateSuccess(); if (base::Contains(transports, Transport::kNearFieldCommunication)) nfc_discovery()->WaitForCallToStartAndSimulateSuccess(); + if (base::Contains(transports, Transport::kInternal)) + platform_discovery()->WaitForCallToStartAndSimulateSuccess(); scoped_task_environment_.FastForwardUntilNoTasksRemain(); EXPECT_FALSE(get_assertion_callback().was_called()); @@ -132,11 +133,8 @@ EXPECT_FALSE(cable_discovery()->is_start_requested()); if (!base::Contains(transports, Transport::kNearFieldCommunication)) EXPECT_FALSE(nfc_discovery()->is_start_requested()); - - // Even with FidoTransportProtocol::kInternal allowed, unless the platform - // authenticator factory returns a FidoAuthenticator instance (which it will - // not be default), the transport will be marked `unavailable`. - transports.erase(Transport::kInternal); + if (!base::Contains(transports, Transport::kInternal)) + EXPECT_FALSE(platform_discovery()->is_start_requested()); EXPECT_THAT( request_handler->transport_availability_info().available_transports, @@ -153,29 +151,19 @@ test::FakeFidoDiscovery* ble_discovery() const { return ble_discovery_; } test::FakeFidoDiscovery* cable_discovery() const { return cable_discovery_; } test::FakeFidoDiscovery* nfc_discovery() const { return nfc_discovery_; } + test::FakeFidoDiscovery* platform_discovery() const { + return platform_discovery_; + } TestGetAssertionRequestCallback& get_assertion_callback() { return get_assertion_cb_; } - void set_mock_platform_device(std::unique_ptr<MockFidoDevice> device) { - pending_mock_platform_device_ = std::move(device); - } - void set_supported_transports( base::flat_set<FidoTransportProtocol> transports) { supported_transports_ = std::move(transports); } protected: - base::Optional<PlatformAuthenticatorInfo> CreatePlatformAuthenticator() { - if (!pending_mock_platform_device_) - return base::nullopt; - return PlatformAuthenticatorInfo( - std::make_unique<FidoDeviceAuthenticator>( - std::move(pending_mock_platform_device_)), - false /* has_recognized_mac_touch_id_credential_available */); - } - base::test::ScopedTaskEnvironment scoped_task_environment_{ base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME}; std::unique_ptr<test::FakeFidoDiscoveryFactory> fake_discovery_factory_ = @@ -184,8 +172,8 @@ test::FakeFidoDiscovery* ble_discovery_; test::FakeFidoDiscovery* cable_discovery_; test::FakeFidoDiscovery* nfc_discovery_; + test::FakeFidoDiscovery* platform_discovery_; scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_; - std::unique_ptr<MockFidoDevice> pending_mock_platform_device_; TestGetAssertionRequestCallback get_assertion_cb_; base::flat_set<FidoTransportProtocol> supported_transports_ = GetAllTransportProtocols(); @@ -654,6 +642,9 @@ set_supported_transports({FidoTransportProtocol::kInternal}); + auto request_handler = + CreateGetAssertionHandlerWithRequest(std::move(request)); + auto device = MockFidoDevice::MakeCtap( ReadCTAPGetInfoResponse(test_data::kTestGetInfoResponsePlatformDevice)); EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0")); @@ -664,10 +655,9 @@ device->ExpectCtap2CommandAndRespondWith( CtapRequestCommand::kAuthenticatorGetAssertion, test_data::kTestGetAssertionResponse); - set_mock_platform_device(std::move(device)); + platform_discovery()->WaitForCallToStartAndSimulateSuccess(); + platform_discovery()->AddDevice(std::move(device)); - auto request_handler = - CreateGetAssertionHandlerWithRequest(std::move(request)); get_assertion_callback().WaitForCallback(); EXPECT_EQ(FidoReturnCode::kSuccess, get_assertion_callback().status()); @@ -684,6 +674,8 @@ // cancelled. TEST_F(FidoGetAssertionHandlerTest, TestRequestWithOperationDeniedErrorPlatform) { + auto request_handler = CreateGetAssertionHandlerCtap(); + auto platform_device = MockFidoDevice::MakeCtapWithGetInfoExpectation( test_data::kTestGetInfoResponsePlatformDevice); platform_device->SetDeviceTransport(FidoTransportProtocol::kInternal); @@ -691,14 +683,14 @@ CtapRequestCommand::kAuthenticatorGetAssertion, CtapDeviceResponseCode::kCtap2ErrOperationDenied, base::TimeDelta::FromMicroseconds(10)); - set_mock_platform_device(std::move(platform_device)); + platform_discovery()->WaitForCallToStartAndSimulateSuccess(); + platform_discovery()->AddDevice(std::move(platform_device)); auto other_device = MockFidoDevice::MakeCtapWithGetInfoExpectation(); other_device->ExpectCtap2CommandAndDoNotRespond( CtapRequestCommand::kAuthenticatorGetAssertion); EXPECT_CALL(*other_device, Cancel); - auto request_handler = CreateGetAssertionHandlerCtap(); discovery()->WaitForCallToStartAndSimulateSuccess(); discovery()->AddDevice(std::move(other_device)); @@ -821,7 +813,6 @@ base::flat_set<FidoTransportProtocol>( {FidoTransportProtocol::kUsbHumanInterfaceDevice}), std::move(request), cb.callback()); - request_handler->SetPlatformAuthenticatorOrMarkUnavailable(base::nullopt); scoped_task_environment.FastForwardUntilNoTasksRemain(); EXPECT_FALSE(cb.was_called());
diff --git a/device/fido/get_assertion_request_handler.cc b/device/fido/get_assertion_request_handler.cc index 8fe2362..2c322ca6 100644 --- a/device/fido/get_assertion_request_handler.cc +++ b/device/fido/get_assertion_request_handler.cc
@@ -14,6 +14,7 @@ #include "base/feature_list.h" #include "base/metrics/histogram_functions.h" #include "base/stl_util.h" +#include "build/build_config.h" #include "components/device_event_log/device_event_log.h" #include "device/fido/authenticator_get_assertion_response.h" #include "device/fido/cable/fido_cable_discovery.h" @@ -24,6 +25,10 @@ #include "device/fido/get_assertion_task.h" #include "device/fido/pin.h" +#if defined(OS_MACOSX) +#include "device/fido/mac/authenticator.h" +#endif // defined(OS_MACOSX) + namespace device { namespace { @@ -304,6 +309,23 @@ weak_factory_.GetWeakPtr(), authenticator)); } +void GetAssertionRequestHandler::AuthenticatorAdded( + FidoDiscoveryBase* discovery, + FidoAuthenticator* authenticator) { + DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); + +#if defined(OS_MACOSX) + if (authenticator->AuthenticatorTransport() == + FidoTransportProtocol::kInternal) { + transport_availability_info().has_recognized_mac_touch_id_credential = + static_cast<fido::mac::TouchIdAuthenticator*>(authenticator) + ->HasCredentialForGetAssertionRequest(request_); + } +#endif // defined(OS_MACOSX) + + FidoRequestHandlerBase::AuthenticatorAdded(discovery, authenticator); +} + void GetAssertionRequestHandler::AuthenticatorRemoved( FidoDiscoveryBase* discovery, FidoAuthenticator* authenticator) {
diff --git a/device/fido/get_assertion_request_handler.h b/device/fido/get_assertion_request_handler.h index 9233d84..bf4f3e7 100644 --- a/device/fido/get_assertion_request_handler.h +++ b/device/fido/get_assertion_request_handler.h
@@ -54,6 +54,8 @@ // FidoRequestHandlerBase: void DispatchRequest(FidoAuthenticator* authenticator) override; + void AuthenticatorAdded(FidoDiscoveryBase* discovery, + FidoAuthenticator* authenticator) override; void AuthenticatorRemoved(FidoDiscoveryBase* discovery, FidoAuthenticator* authenticator) override;
diff --git a/device/fido/mac/authenticator.h b/device/fido/mac/authenticator.h index 787994a7..0dc83a4 100644 --- a/device/fido/mac/authenticator.h +++ b/device/fido/mac/authenticator.h
@@ -39,12 +39,9 @@ // off-the-record/incognito context. static bool IsAvailable(const AuthenticatorConfig& config); - // CreateIfAvailable returns a TouchIdAuthenticator if IsAvailable() returns - // true and nullptr otherwise. - static std::unique_ptr<TouchIdAuthenticator> CreateIfAvailable( - AuthenticatorConfig config); - - static std::unique_ptr<TouchIdAuthenticator> CreateForTesting( + // CreateIfAvailable returns a TouchIdAuthenticator. Callers must check + // IsAvailable() first. + static std::unique_ptr<TouchIdAuthenticator> Create( AuthenticatorConfig config); ~TouchIdAuthenticator() override;
diff --git a/device/fido/mac/authenticator.mm b/device/fido/mac/authenticator.mm index 7436b4d..6efc2db 100644 --- a/device/fido/mac/authenticator.mm +++ b/device/fido/mac/authenticator.mm
@@ -39,17 +39,9 @@ } // static -std::unique_ptr<TouchIdAuthenticator> TouchIdAuthenticator::CreateIfAvailable( +std::unique_ptr<TouchIdAuthenticator> TouchIdAuthenticator::Create( AuthenticatorConfig config) { - return IsAvailable(config) ? base::WrapUnique(new TouchIdAuthenticator( - std::move(config.keychain_access_group), - std::move(config.metadata_secret))) - : nullptr; -} - -// static -std::unique_ptr<TouchIdAuthenticator> TouchIdAuthenticator::CreateForTesting( - AuthenticatorConfig config) { + DCHECK(IsAvailable(config)); return base::WrapUnique( new TouchIdAuthenticator(std::move(config.keychain_access_group), std::move(config.metadata_secret)));
diff --git a/device/fido/mac/browsing_data_deletion_unittest.mm b/device/fido/mac/browsing_data_deletion_unittest.mm index a5f590c..02abcc9 100644 --- a/device/fido/mac/browsing_data_deletion_unittest.mm +++ b/device/fido/mac/browsing_data_deletion_unittest.mm
@@ -130,7 +130,7 @@ std::unique_ptr<TouchIdAuthenticator> MakeAuthenticator( std::string profile_metadata_secret) { - return TouchIdAuthenticator::CreateForTesting( + return TouchIdAuthenticator::Create( {kKeychainAccessGroup, std::move(profile_metadata_secret)}); }
diff --git a/device/fido/mac/discovery.cc b/device/fido/mac/discovery.cc new file mode 100644 index 0000000..d7f79396 --- /dev/null +++ b/device/fido/mac/discovery.cc
@@ -0,0 +1,53 @@ +// 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. + +#include "device/fido/mac/discovery.h" + +#include "base/bind.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "device/fido/mac/authenticator.h" + +namespace device { +namespace fido { +namespace mac { + +FidoTouchIdDiscovery::FidoTouchIdDiscovery( + AuthenticatorConfig authenticator_config) + : FidoDiscoveryBase(FidoTransportProtocol::kInternal), + authenticator_config_(std::move(authenticator_config)), + weak_factory_(this) {} + +FidoTouchIdDiscovery::~FidoTouchIdDiscovery() = default; + +void FidoTouchIdDiscovery::Start() { + DCHECK(!authenticator_); + if (!observer()) { + return; + } + + if (!TouchIdAuthenticator::IsAvailable(authenticator_config_)) { + observer()->DiscoveryStarted(this, /*success=*/false); + return; + } + + observer()->DiscoveryStarted(this, /*success=*/true); + + // Start() is currently invoked synchronously in the + // FidoRequestHandler ctor. Invoke AddAuthenticator() asynchronously + // to avoid hairpinning FidoRequestHandler::AuthenticatorAdded() + // before the request handler has an observer. + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&FidoTouchIdDiscovery::AddAuthenticator, + weak_factory_.GetWeakPtr())); +} + +void FidoTouchIdDiscovery::AddAuthenticator() { + DCHECK(TouchIdAuthenticator::IsAvailable(authenticator_config_)); + authenticator_ = TouchIdAuthenticator::Create(authenticator_config_); + observer()->AuthenticatorAdded(this, authenticator_.get()); +} + +} // namespace mac +} // namespace fido +} // namespace device
diff --git a/device/fido/mac/discovery.h b/device/fido/mac/discovery.h new file mode 100644 index 0000000..96a3402 --- /dev/null +++ b/device/fido/mac/discovery.h
@@ -0,0 +1,43 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_FIDO_MAC_DISCOVERY_H_ +#define DEVICE_FIDO_MAC_DISCOVERY_H_ + +#include <memory> + +#include "base/component_export.h" +#include "base/memory/weak_ptr.h" +#include "device/fido/fido_discovery_base.h" +#include "device/fido/mac/authenticator_config.h" + +namespace device { +namespace fido { +namespace mac { + +class TouchIdAuthenticator; + +// Creates Touch ID authenticators. +class COMPONENT_EXPORT(DEVICE_FIDO) FidoTouchIdDiscovery + : public FidoDiscoveryBase { + public: + explicit FidoTouchIdDiscovery(AuthenticatorConfig config); + ~FidoTouchIdDiscovery() override; + + // FidoDiscoveryBase: + void Start() override; + + private: + void AddAuthenticator(); + + AuthenticatorConfig authenticator_config_; + std::unique_ptr<TouchIdAuthenticator> authenticator_; + base::WeakPtrFactory<FidoTouchIdDiscovery> weak_factory_; +}; + +} // namespace mac +} // namespace fido +} // namespace device + +#endif // DEVICE_FIDO_MAC_DISCOVERY_H_
diff --git a/device/fido/mac/scoped_touch_id_test_environment.mm b/device/fido/mac/scoped_touch_id_test_environment.mm index 6e407c4..34eb9b1 100644 --- a/device/fido/mac/scoped_touch_id_test_environment.mm +++ b/device/fido/mac/scoped_touch_id_test_environment.mm
@@ -44,6 +44,7 @@ touch_id_context_touch_id_available_ptr_; Keychain::ClearInstanceOverride(); + g_current_environment = nullptr; } // static
diff --git a/device/fido/make_credential_handler_unittest.cc b/device/fido/make_credential_handler_unittest.cc index 04cb0b3..68572c5 100644 --- a/device/fido/make_credential_handler_unittest.cc +++ b/device/fido/make_credential_handler_unittest.cc
@@ -66,6 +66,7 @@ discovery_ = fake_discovery_factory_->ForgeNextHidDiscovery(); ble_discovery_ = fake_discovery_factory_->ForgeNextBleDiscovery(); nfc_discovery_ = fake_discovery_factory_->ForgeNextNfcDiscovery(); + platform_discovery_ = fake_discovery_factory_->ForgeNextPlatformDiscovery(); } std::unique_ptr<MakeCredentialRequestHandler> CreateMakeCredentialHandler() { @@ -91,8 +92,8 @@ nullptr, fake_discovery_factory_.get(), supported_transports_, std::move(request_parameter), std::move(authenticator_selection_criteria), cb_.callback()); - handler->SetPlatformAuthenticatorOrMarkUnavailable( - CreatePlatformAuthenticator()); + if (pending_mock_platform_device_) + platform_discovery_->AddDevice(std::move(pending_mock_platform_device_)); return handler; } @@ -137,15 +138,6 @@ } protected: - base::Optional<PlatformAuthenticatorInfo> CreatePlatformAuthenticator() { - if (!pending_mock_platform_device_) - return base::nullopt; - return PlatformAuthenticatorInfo( - std::make_unique<FidoDeviceAuthenticator>( - std::move(pending_mock_platform_device_)), - false /* has_recognized_mac_touch_id_credential_available */); - } - base::test::ScopedTaskEnvironment scoped_task_environment_{ base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME}; std::unique_ptr<test::FakeFidoDiscoveryFactory> fake_discovery_factory_ = @@ -153,6 +145,7 @@ test::FakeFidoDiscovery* discovery_; test::FakeFidoDiscovery* ble_discovery_; test::FakeFidoDiscovery* nfc_discovery_; + test::FakeFidoDiscovery* platform_discovery_; scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> mock_adapter_; std::unique_ptr<MockFidoDevice> pending_mock_platform_device_; TestMakeCredentialRequestCallback cb_; @@ -262,34 +255,6 @@ callback().status()); } -// TODO(crbug.com/873710): Platform authenticators are temporarily disabled if -// AuthenticatorAttachment is unset (kAny). -TEST_F(FidoMakeCredentialHandlerTest, AnyAttachment) { - auto platform_device = MockFidoDevice::MakeCtap( - ReadCTAPGetInfoResponse(test_data::kTestGetInfoResponsePlatformDevice)); - platform_device->SetDeviceTransport(FidoTransportProtocol::kInternal); - set_mock_platform_device(std::move(platform_device)); - EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true)); - auto request_handler = - CreateMakeCredentialHandlerWithAuthenticatorSelectionCriteria( - AuthenticatorSelectionCriteria( - AuthenticatorAttachment::kAny, /*require_resident_key=*/false, - UserVerificationRequirement::kPreferred)); - - // MakeCredentialHandler will not dispatch the kAny request to the platform - // authenticator since the request does not get dispatched through UI. Despite - // setting a platform authenticator, the internal transport never becomes - // available. - scoped_task_environment_.FastForwardUntilNoTasksRemain(); - EXPECT_FALSE(callback().was_called()); - - // kCloudAssistedBluetoothLowEnergy not yet supported for MakeCredential. - ExpectAllowedTransportsForRequestAre( - request_handler.get(), {FidoTransportProtocol::kBluetoothLowEnergy, - FidoTransportProtocol::kNearFieldCommunication, - FidoTransportProtocol::kUsbHumanInterfaceDevice}); -} - TEST_F(FidoMakeCredentialHandlerTest, CrossPlatformAttachment) { EXPECT_CALL(*mock_adapter_, IsPresent()).WillOnce(::testing::Return(true)); auto request_handler =
diff --git a/device/fido/make_credential_request_handler.cc b/device/fido/make_credential_request_handler.cc index 811acf5..aa726ca2 100644 --- a/device/fido/make_credential_request_handler.cc +++ b/device/fido/make_credential_request_handler.cc
@@ -572,27 +572,4 @@ weak_factory_.GetWeakPtr(), authenticator_)); } -void MakeCredentialRequestHandler::SetPlatformAuthenticatorOrMarkUnavailable( - base::Optional<PlatformAuthenticatorInfo> platform_authenticator_info) { - DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); - - if (platform_authenticator_info) { - // TODO(crbug.com/873710): In the case of a request with - // AuthenticatorAttachment::kAny and when there is no embedder-provided - // transport selection UI, disable the platform authenticator to avoid the - // Touch ID fingerprint prompt competing with external devices. - const bool has_transport_selection_ui = - observer() && observer()->EmbedderControlsAuthenticatorDispatch( - *platform_authenticator_info->authenticator); - if (authenticator_selection_criteria_.authenticator_attachment() == - AuthenticatorAttachment::kAny && - !has_transport_selection_ui) { - platform_authenticator_info = base::nullopt; - } - } - - FidoRequestHandlerBase::SetPlatformAuthenticatorOrMarkUnavailable( - std::move(platform_authenticator_info)); -} - } // namespace device
diff --git a/device/fido/make_credential_request_handler.h b/device/fido/make_credential_request_handler.h index 5b57f2ae..fb90ddd 100644 --- a/device/fido/make_credential_request_handler.h +++ b/device/fido/make_credential_request_handler.h
@@ -42,11 +42,6 @@ CompletionCallback completion_callback); ~MakeCredentialRequestHandler() override; - // FidoRequestHandlerBase: - void SetPlatformAuthenticatorOrMarkUnavailable( - base::Optional<PlatformAuthenticatorInfo> platform_authenticator_info) - override; - private: enum class State { kWaitingForTouch,
diff --git a/device/vr/oculus/oculus_gamepad_helper.cc b/device/vr/oculus/oculus_gamepad_helper.cc index 3af77379..5a93ddf9 100644 --- a/device/vr/oculus/oculus_gamepad_helper.cc +++ b/device/vr/oculus/oculus_gamepad_helper.cc
@@ -291,8 +291,7 @@ OculusGamepadBuilder touch(input_touch, hand); - // TODO(https://crbug.com/966060): Determine if inverting the y value here is - // necessary. + // Invert the y axis because -1 is up in the Gamepad API, but down in Oculus. touch.AddAxis(input_touch.Thumbstick[hand].x); touch.AddAxis(-input_touch.Thumbstick[hand].y);
diff --git a/device/vr/openvr/openvr_gamepad_helper.cc b/device/vr/openvr/openvr_gamepad_helper.cc index ca303e9..1f73992 100644 --- a/device/vr/openvr/openvr_gamepad_helper.cc +++ b/device/vr/openvr/openvr_gamepad_helper.cc
@@ -60,8 +60,7 @@ GamepadBuilder::ButtonData button_data; - // TODO(https://crbug.com/966060): Determine if inverting the y value here - // is necessary. + // Invert the y axis because -1 is up in the Gamepad API but down in OpenVR. double x_axis = controller_state.rAxis[j].x; double y_axis = -controller_state.rAxis[j].y;
diff --git a/device/vr/openvr/test/test_helper.cc b/device/vr/openvr/test/test_helper.cc index 87580f0..365bc15 100644 --- a/device/vr/openvr/test/test_helper.cc +++ b/device/vr/openvr/test/test_helper.cc
@@ -331,9 +331,7 @@ controller_state->ulButtonTouched = TranslateButtonMask(controller_data.buttons_touched); for (unsigned int i = 0; i < device::kMaxNumAxes; ++i) { - // Invert the y axis because gamepad and the rest of Chrome follows the - // convention that -1 is up, but WMR reports -1 as down. - // TODO(https://crbug.com/966060): Revisit this if the convention changes. + // Invert the y axis because -1 is up in the Gamepad API, but down in WMR. controller_state->rAxis[i].x = controller_data.axis_data[i].x; controller_state->rAxis[i].y = -controller_data.axis_data[i].y; }
diff --git a/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc b/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc index 27739b2..2216ff2 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc +++ b/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
@@ -286,8 +286,7 @@ data.touched = data.pressed; data.value = data.pressed ? 1.0 : 0.0; - // TODO(https://crbug.com/966060): Determine if inverting the y value here is - // necessary. + // Invert the y axis because -1 is up in the Gamepad API, but down in WMR. data.has_both_axes = true; data.x_axis = source_state->ThumbstickX(); data.y_axis = -source_state->ThumbstickY(); @@ -303,8 +302,7 @@ // The Touchpad does have Axes, but if it's not touched, they are 0. data.has_both_axes = true; if (data.touched) { - // TODO(https://crbug.com/966060): Determine if inverting the y value here - // is necessary. + // Invert the y axis because -1 is up in the Gamepad API, but down in WMR. data.x_axis = source_state->TouchpadX(); data.y_axis = -source_state->TouchpadY(); } else {
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.cc index a410918..8243aa7 100644 --- a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.cc +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_source_state.cc
@@ -68,9 +68,7 @@ return val; } -// Invert the y axis because gamepad and the rest of Chrome follows the -// convention that -1 is up, but WMR reports -1 as down. -// TODO(https://crbug.com/966060): Revisit this if the convention changes. +// Invert the y axis because -1 is up in the Gamepad API, but down in WMR. double MockWMRInputSourceState::ThumbstickY() const { double val = data_.axis_data[XrAxisOffsetFromId(XrButtonId::kAxisPrimary)].y; // Should be in [-1, 1] for joysticks. @@ -88,9 +86,7 @@ return val; } -// Invert the y axis because gamepad and the rest of Chrome follows the -// convention that -1 is up, but WMR reports -1 as down. -// TODO(https://crbug.com/966060): Revisit this if the convention changes. +// Invert the y axis because -1 is up in the Gamepad API, but down in WMR. double MockWMRInputSourceState::TouchpadY() const { double val = data_.axis_data[XrAxisOffsetFromId(XrButtonId::kAxisSecondary)].y;
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc index 1a0a43a..b83d047e 100644 --- a/extensions/browser/api/web_request/web_request_api.cc +++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -2363,13 +2363,6 @@ return true; } - if (request->is_web_view) { - const bool has_declarative_rules = !relevant_registries.empty(); - UMA_HISTOGRAM_BOOLEAN( - "Extensions.DeclarativeWebRequest.WebViewRequestDeclarativeRules", - has_declarative_rules); - } - bool deltas_created = false; for (const auto& it : relevant_registries) { WebRequestRulesRegistry* rules_registry = it.first;
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 4187e85..f628346 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1423,6 +1423,8 @@ ACTION_SETBADGEBACKGROUNDCOLOR = 1360, AUTOTESTPRIVATE_SETARCAPPWINDOWSTATE = 1361, ACCESSIBILITY_PRIVATE_OPENSETTINGSSUBPAGE = 1362, + ACTION_ENABLE = 1363, + ACTION_DISABLE = 1364, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc index 7a04e76..23ff1550 100644 --- a/extensions/browser/extension_prefs.cc +++ b/extensions/browser/extension_prefs.cc
@@ -1844,6 +1844,9 @@ DeleteExtensionPrefs(id); } +const char ExtensionPrefs::kFakeObsoletePrefForTesting[] = + "__fake_obsolete_pref_for_testing"; + ExtensionPrefs::ExtensionPrefs( content::BrowserContext* browser_context, PrefService* prefs, @@ -2105,4 +2108,29 @@ observer.OnExtensionRegistered(extension_id, install_time, is_enabled); } +void ExtensionPrefs::MigrateObsoleteExtensionPrefs() { + const base::Value* extensions_dictionary = + prefs_->GetDictionary(pref_names::kExtensions); + DCHECK(extensions_dictionary->is_dict()); + + // Please clean this list up periodically, removing any entries added more + // than a year ago (with the exception of the testing key). + constexpr const char* kObsoleteKeys[] = { + // Permanent testing-only key. + kFakeObsoletePrefForTesting, + + // Added 2019-07. + "has_set_script_all_urls", + }; + + for (const auto& key_value : extensions_dictionary->DictItems()) { + if (!crx_file::id_util::IdIsValid(key_value.first)) + continue; + ScopedExtensionPrefUpdate update(prefs_, key_value.first); + std::unique_ptr<prefs::DictionaryValueUpdate> inner_update = update.Get(); + for (const char* key : kObsoleteKeys) + inner_update->Remove(key, nullptr); + } +} + } // namespace extensions
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h index 25f7955..b11f1c60 100644 --- a/extensions/browser/extension_prefs.h +++ b/extensions/browser/extension_prefs.h
@@ -614,12 +614,20 @@ void SetDNRUseActionCountAsBadgeText(const ExtensionId& extension_id, bool use_action_count_as_badge_text); + // Iterates over the extension pref entries and removes any obsolete keys. We + // need to do this here specially (rather than in + // MigrateObsoleteProfilePrefs()) because these entries are subkeys of the + // extension's dictionary, which is keyed on the extension ID. + void MigrateObsoleteExtensionPrefs(); + // When called before the ExtensionService is created, alerts that are // normally suppressed in first run will still trigger. static void SetRunAlertsInFirstRunForTest(); void ClearExternalUninstallForTesting(const ExtensionId& id); + static const char kFakeObsoletePrefForTesting[]; + private: friend class ExtensionPrefsBlacklistedExtensions; // Unit test. friend class ExtensionPrefsComponentExtension; // Unit test.
diff --git a/gpu/command_buffer/service/swap_chain_factory_dxgi_unittest.cc b/gpu/command_buffer/service/swap_chain_factory_dxgi_unittest.cc index c27dcde..2e2ed8d 100644 --- a/gpu/command_buffer/service/swap_chain_factory_dxgi_unittest.cc +++ b/gpu/command_buffer/service/swap_chain_factory_dxgi_unittest.cc
@@ -15,6 +15,7 @@ #include "gpu/command_buffer/service/shared_image_manager.h" #include "gpu/command_buffer/service/shared_image_representation.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gl/gl_angle_util_win.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_image_dxgi_swap_chain.h" #include "ui/gl/gl_surface.h" @@ -78,9 +79,9 @@ GLenum expected_target = GL_TEXTURE_2D; Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture; scoped_refptr<gles2::TexturePassthrough> back_passthrough_texture; - gles2::Texture* back_texture; - gl::GLImageDXGISwapChain* back_image; - gl::GLImageDXGISwapChain* front_image; + gles2::Texture* back_texture = nullptr; + gl::GLImageDXGISwapChain* back_image = nullptr; + gl::GLImageDXGISwapChain* front_image = nullptr; std::unique_ptr<SharedImageRepresentationFactoryRef> back_factory_ref = shared_image_manager_.Register(std::move(backings.back_buffer), @@ -217,7 +218,6 @@ back_factory_ref->PresentSwapChain(); - // TODO(ashithasantosh): Check contents of front buffer. { GLubyte pixel_color[4]; const uint8_t expected_color[4] = {0, 0, 0, 255}; @@ -228,6 +228,49 @@ EXPECT_EQ(expected_color[2], pixel_color[2]); EXPECT_EQ(expected_color[3], pixel_color[3]); } + + { + // A staging texture must be used to check front buffer since it cannot be + // bound to an FBO or use ReadPixels. + D3D11_TEXTURE2D_DESC desc = {}; + desc.Width = 1; + desc.Height = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Usage = D3D11_USAGE_STAGING; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.SampleDesc.Count = 1; + + auto d3d11_device = gl::QueryD3D11DeviceObjectFromANGLE(); + ASSERT_TRUE(d3d11_device); + + Microsoft::WRL::ComPtr<ID3D11Texture2D> staging_texture; + ASSERT_TRUE(SUCCEEDED( + d3d11_device->CreateTexture2D(&desc, nullptr, &staging_texture))); + + Microsoft::WRL::ComPtr<ID3D11DeviceContext> context; + d3d11_device->GetImmediateContext(&context); + ASSERT_TRUE(context); + + context->CopyResource(staging_texture.Get(), front_image->texture().Get()); + + D3D11_MAPPED_SUBRESOURCE mapped_resource; + ASSERT_TRUE(SUCCEEDED(context->Map(staging_texture.Get(), 0, D3D11_MAP_READ, + 0, &mapped_resource))); + ASSERT_GE(mapped_resource.RowPitch, 4u); + // After present, front buffer should have color rendered to back buffer. + const uint8_t* pixel_color = + static_cast<const uint8_t*>(mapped_resource.pData); + const uint8_t expected_color[4] = {0, 255, 0, 255}; + EXPECT_EQ(expected_color[0], pixel_color[0]); + EXPECT_EQ(expected_color[1], pixel_color[1]); + EXPECT_EQ(expected_color[2], pixel_color[2]); + EXPECT_EQ(expected_color[3], pixel_color[3]); + + context->Unmap(staging_texture.Get(), 0); + } + api->glDeleteFramebuffersEXTFn(1, &fbo); }
diff --git a/gpu/command_buffer/tests/command_buffer_gles2_tests_main.cc b/gpu/command_buffer/tests/command_buffer_gles2_tests_main.cc index 67100fe..931ab3c 100644 --- a/gpu/command_buffer/tests/command_buffer_gles2_tests_main.cc +++ b/gpu/command_buffer/tests/command_buffer_gles2_tests_main.cc
@@ -3,7 +3,7 @@ // found in the LICENSE file. #include "base/bind.h" -#include "base/message_loop/message_loop.h" +#include "base/task/single_thread_task_executor.h" #if defined(OS_MACOSX) #include "base/mac/scoped_nsautorelease_pool.h" #endif @@ -19,9 +19,9 @@ int RunHelper(base::TestSuite* testSuite) { #if defined(USE_OZONE) - base::MessageLoopForUI main_loop; + base::SingleThreadTaskExecutor executor(base::MessagePump::Type::UI); #else - base::MessageLoopForIO message_loop; + base::SingleThreadTaskExecutor executor(base::MessagePump::Type::IO); #endif return testSuite->Run(); }
diff --git a/gpu/command_buffer/tests/gl_tests_main.cc b/gpu/command_buffer/tests/gl_tests_main.cc index 7c3b1c5c..d3e5028 100644 --- a/gpu/command_buffer/tests/gl_tests_main.cc +++ b/gpu/command_buffer/tests/gl_tests_main.cc
@@ -6,7 +6,8 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/feature_list.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_pump.h" +#include "base/task/single_thread_task_executor.h" #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" #include "build/build_config.h" @@ -24,9 +25,9 @@ int RunHelper(base::TestSuite* testSuite) { base::FeatureList::InitializeInstance(std::string(), std::string()); #if defined(USE_OZONE) - base::MessageLoopForUI main_loop; + base::SingleThreadTaskExecutor executor(base::MessagePump::Type::UI); #else - base::MessageLoopForIO message_loop; + base::SingleThreadTaskExecutor executor(base::MessagePump::Type::IO); #endif gpu::GLTestHelper::InitializeGLDefault();
diff --git a/gpu/perftests/run_all_tests.cc b/gpu/perftests/run_all_tests.cc index 5c6586c..c96f59e 100644 --- a/gpu/perftests/run_all_tests.cc +++ b/gpu/perftests/run_all_tests.cc
@@ -5,7 +5,8 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/feature_list.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_pump.h" +#include "base/task/single_thread_task_executor.h" #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" #include "build/build_config.h" @@ -18,12 +19,12 @@ static int RunHelper(base::TestSuite* test_suite) { base::FeatureList::InitializeInstance(std::string(), std::string()); #if defined(USE_OZONE) - base::MessageLoopForUI main_loop; + base::SingleThreadTaskExecutor executor(base::MessagePump::Type::UI); ui::OzonePlatform::InitParams params; params.single_process = true; ui::OzonePlatform::InitializeForGPU(params); #else - base::MessageLoopForIO message_loop; + base::SingleThreadTaskExecutor executor(base::MessagePump::Type::IO); #endif CHECK(gl::init::InitializeGLOneOff()); return test_suite->Run();
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg index 7a27466..3d517cb 100644 --- a/infra/config/cr-buildbucket.cfg +++ b/infra/config/cr-buildbucket.cfg
@@ -2946,11 +2946,6 @@ mixins: "builderless" } builders { - name: "chromeos-amd64-generic-rel-goma-canary" - dimensions: "os:Ubuntu-14.04" - mixins: "fyi-ci" - } - builders { name: "Linux MSan Builder" mixins: "memory-ci-goma-rbe-prod" mixins: "linux-xenial" @@ -3265,45 +3260,45 @@ # Goma RBE FYI builders { name: "Cast Linux (Goma RBE FYI)" - dimensions: "os:Ubuntu-14.04" mixins: "builderless" mixins: "goma-ci" mixins: "goma-rbe-prod-ats" + mixins: "linux-xenial" } builders { name: "chromeos-amd64-generic-rel (Goma RBE FYI)" - dimensions: "os:Ubuntu-14.04" mixins: "builderless" mixins: "goma-ci" mixins: "goma-ats" + mixins: "linux-xenial" } builders { name: "fuchsia-fyi-arm64-rel (Goma RBE FYI)" - dimensions: "os:Ubuntu-14.04" mixins: "builderless" mixins: "goma-ci" mixins: "goma-rbe-prod-ats" + mixins: "linux-xenial" } builders { name: "fuchsia-fyi-x64-rel (Goma RBE FYI)" - dimensions: "os:Ubuntu-14.04" mixins: "builderless" mixins: "goma-ci" mixins: "goma-rbe-prod-ats" + mixins: "linux-xenial" } builders { name: "Linux ASan LSan Builder (Goma RBE FYI)" - dimensions: "os:Ubuntu-14.04" mixins: "builderless" mixins: "goma-ci" mixins: "goma-rbe-prod-ats" + mixins: "linux-xenial" } builders { name: "Linux MSan Builder (Goma RBE FYI)" - dimensions: "os:Ubuntu-14.04" mixins: "builderless" mixins: "goma-ci" mixins: "goma-rbe-prod-ats" + mixins: "linux-xenial" } # Goma Staging builders { @@ -3342,9 +3337,16 @@ mixins: "fyi-ci" } builders { - name: "Android Builder (dbg) Goma Canary" - dimensions: "os:Ubuntu-14.04" + name: "chromeos-amd64-generic-rel-goma-canary" mixins: "fyi-ci" + mixins: "linux-xenial" + mixins: "builderless" + } + builders { + name: "Android Builder (dbg) Goma Canary" + mixins: "fyi-ci" + mixins: "linux-xenial" + mixins: "builderless" } builders { name: "Mac Goma Canary LocalOutputCache" @@ -3370,13 +3372,17 @@ } builders { name: "Linux x64 Goma Canary LocalOutputCache" - dimensions: "os:Ubuntu-14.04" mixins: "fyi-ci" + mixins: "builderless" + mixins: "linux-xenial" } builders { name: "Linux Builder Goma Canary" + # keep to use trusty for this until chrome drops support of development + # on trusty. dimensions: "os:Ubuntu-14.04" mixins: "fyi-ci" + mixins: "builderless" } builders { name: "Win cl.exe Goma Canary LocalOutputCache" @@ -3406,8 +3412,9 @@ } builders { name: "Linux x64 Goma Canary (clobber)" - dimensions: "os:Ubuntu-14.04" mixins: "fyi-ci" + mixins: "linux-xenial" + mixins: "builderless" } # Goma Latest Client builders {
diff --git a/ios/build/bots/scripts/xcode_log_parser.py b/ios/build/bots/scripts/xcode_log_parser.py index 1eb77d8f..442281e 100644 --- a/ios/build/bots/scripts/xcode_log_parser.py +++ b/ios/build/bots/scripts/xcode_log_parser.py
@@ -30,7 +30,8 @@ passed_tests = [] # Test has format: # [09:04:42:INFO] Test case '-[Test_class test_method]' passed. - passed_test_regex = re.compile(r'Test case \'\-\[(.+?)\s(.+?)\]\' passed') + # [09:04:42:INFO] Test Case '-[Test_class test_method]' passed. + passed_test_regex = re.compile(r'Test [Cc]ase \'\-\[(.+?)\s(.+?)\]\' passed') for test_line in output: m_test = passed_test_regex.search(test_line)
diff --git a/ios/build/bots/scripts/xcode_log_parser_test.py b/ios/build/bots/scripts/xcode_log_parser_test.py index bc5bb4cb..cd37b17 100644 --- a/ios/build/bots/scripts/xcode_log_parser_test.py +++ b/ios/build/bots/scripts/xcode_log_parser_test.py
@@ -256,7 +256,7 @@ mock_path_exists.side_effect = [True, False] output = [ '[09:03:42:INFO] Test case \'-[TestCase1 method1]\' passed on device.', - '[09:06:40:INFO] Test case \'-[TestCase2 method1]\' passed on device.', + '[09:06:40:INFO] Test Case \'-[TestCase2 method1]\' passed on device.', '[09:09:00:INFO] Test case \'-[TestCase2 method1]\' failed on device.', '** BUILD INTERRUPTED **', ]
diff --git a/ios/chrome/app/application_delegate/mock_tab_opener.h b/ios/chrome/app/application_delegate/mock_tab_opener.h index fe7bc7b1..85f0173 100644 --- a/ios/chrome/app/application_delegate/mock_tab_opener.h +++ b/ios/chrome/app/application_delegate/mock_tab_opener.h
@@ -19,7 +19,7 @@ // -dismissModalsAndOpenSelectedTabInMode:withUrlLoadParams:dismissOmnibox: // completion:. @property(nonatomic, readonly) UrlLoadParams urlLoadParams; -@property(nonatomic, readonly) ApplicationMode applicationMode; +@property(nonatomic, readonly) ApplicationModeForTabOpening applicationMode; @property(nonatomic, strong, readonly) void (^completionBlock)(void); // Clear the URL.
diff --git a/ios/chrome/app/application_delegate/mock_tab_opener.mm b/ios/chrome/app/application_delegate/mock_tab_opener.mm index d8697b5..21121972 100644 --- a/ios/chrome/app/application_delegate/mock_tab_opener.mm +++ b/ios/chrome/app/application_delegate/mock_tab_opener.mm
@@ -17,7 +17,8 @@ @implementation MockTabOpener -- (void)dismissModalsAndOpenSelectedTabInMode:(ApplicationMode)targetMode +- (void)dismissModalsAndOpenSelectedTabInMode: + (ApplicationModeForTabOpening)targetMode withUrlLoadParams: (const UrlLoadParams&)urlLoadParams dismissOmnibox:(BOOL)dismissOmnibox
diff --git a/ios/chrome/app/application_delegate/tab_opening.h b/ios/chrome/app/application_delegate/tab_opening.h index 96e85829..cb44995e 100644 --- a/ios/chrome/app/application_delegate/tab_opening.h +++ b/ios/chrome/app/application_delegate/tab_opening.h
@@ -15,6 +15,8 @@ @protocol StartupInformation; struct UrlLoadParams; +enum class ApplicationModeForTabOpening { NORMAL, INCOGNITO, CURRENT }; + // Protocol for object that can open new tabs during application launch. @protocol TabOpening<NSObject> @@ -22,7 +24,8 @@ // then opens either a normal or incognito tab with |url|. After opening |url|, // run completion |handler| if it is not nil. After Tab is opened the virtual // URL is set to the pending navigation item. -- (void)dismissModalsAndOpenSelectedTabInMode:(ApplicationMode)targetMode +- (void)dismissModalsAndOpenSelectedTabInMode: + (ApplicationModeForTabOpening)targetMode withUrlLoadParams: (const UrlLoadParams&)urlLoadParams dismissOmnibox:(BOOL)dismissOmnibox
diff --git a/ios/chrome/app/application_delegate/url_opener.mm b/ios/chrome/app/application_delegate/url_opener.mm index 6209b46..ca5f2d40 100644 --- a/ios/chrome/app/application_delegate/url_opener.mm +++ b/ios/chrome/app/application_delegate/url_opener.mm
@@ -80,10 +80,17 @@ URL = [params externalURL]; } UrlLoadParams urlLoadParams = UrlLoadParams::InNewTab(URL, virtualURL); + + ApplicationModeForTabOpening targetMode = + [params launchInIncognito] ? ApplicationModeForTabOpening::INCOGNITO + : ApplicationModeForTabOpening::NORMAL; + // If the call is coming from the app, it should be opened in the current + // mode to avoid changing mode. + if (callerApp == CALLER_APP_GOOGLE_CHROME) + targetMode = ApplicationModeForTabOpening::CURRENT; + [tabOpener - dismissModalsAndOpenSelectedTabInMode:[params launchInIncognito] - ? ApplicationMode::INCOGNITO - : ApplicationMode::NORMAL + dismissModalsAndOpenSelectedTabInMode:targetMode withUrlLoadParams:urlLoadParams dismissOmnibox:[params postOpeningAction] != FOCUS_OMNIBOX
diff --git a/ios/chrome/app/application_delegate/user_activity_handler.mm b/ios/chrome/app/application_delegate/user_activity_handler.mm index f7b45d0..d7d33fa4 100644 --- a/ios/chrome/app/application_delegate/user_activity_handler.mm +++ b/ios/chrome/app/application_delegate/user_activity_handler.mm
@@ -172,10 +172,10 @@ if (applicationIsActive && ![startupInformation isPresentingFirstRunUI]) { // The app is already active so the applicationDidBecomeActive: method will // never be called. Open the requested URL immediately. - ApplicationMode targetMode = + ApplicationModeForTabOpening targetMode = [[startupInformation startupParameters] launchInIncognito] - ? ApplicationMode::INCOGNITO - : ApplicationMode::NORMAL; + ? ApplicationModeForTabOpening::INCOGNITO + : ApplicationModeForTabOpening::NORMAL; UrlLoadParams params = UrlLoadParams::InNewTab(webpageGURL); [tabOpener dismissModalsAndOpenSelectedTabInMode:targetMode withUrlLoadParams:params @@ -262,10 +262,10 @@ // will never be called. Open the requested URL after all modal UIs have // been dismissed. |_startupParameters| must be retained until all deferred // modal UIs are dismissed and tab opened with requested URL. - ApplicationMode targetMode = + ApplicationModeForTabOpening targetMode = [[startupInformation startupParameters] launchInIncognito] - ? ApplicationMode::INCOGNITO - : ApplicationMode::NORMAL; + ? ApplicationModeForTabOpening::INCOGNITO + : ApplicationModeForTabOpening::NORMAL; GURL URL; GURL virtualURL; GURL completeURL = startupInformation.startupParameters.completeURL;
diff --git a/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm b/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm index c087b51..04f8229 100644 --- a/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm +++ b/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm
@@ -385,7 +385,7 @@ GURL newTabURL(kChromeUINewTabURL); EXPECT_EQ(newTabURL, tabOpener.urlLoadParams.web_params.url); // AppStartupParameters default to opening pages in non-Incognito mode. - EXPECT_EQ(ApplicationMode::NORMAL, [tabOpener applicationMode]); + EXPECT_EQ(ApplicationModeForTabOpening::NORMAL, [tabOpener applicationMode]); EXPECT_TRUE(result); // Verifies that a new tab is being requested. EXPECT_EQ(newTabURL, @@ -493,7 +493,8 @@ // and omnibox shows virtual URL. EXPECT_EQ(completeURL, tabOpener.urlLoadParams.web_params.url); EXPECT_EQ(externalURL, tabOpener.urlLoadParams.web_params.virtual_url); - EXPECT_EQ(ApplicationMode::INCOGNITO, [tabOpener applicationMode]); + EXPECT_EQ(ApplicationModeForTabOpening::INCOGNITO, + [tabOpener applicationMode]); } // Tests that handleStartupParameters with a non-U2F url opens a new tab. @@ -528,7 +529,8 @@ EXPECT_OCMOCK_VERIFY(startupInformationMock); EXPECT_EQ(gurl, tabOpener.urlLoadParams.web_params.url); EXPECT_TRUE(tabOpener.urlLoadParams.web_params.virtual_url.is_empty()); - EXPECT_EQ(ApplicationMode::INCOGNITO, [tabOpener applicationMode]); + EXPECT_EQ(ApplicationModeForTabOpening::INCOGNITO, + [tabOpener applicationMode]); } // Tests that handleStartupParameters with a U2F url opens in the correct tab.
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm index 407ae1a..4ffa5a5 100644 --- a/ios/chrome/app/main_controller.mm +++ b/ios/chrome/app/main_controller.mm
@@ -461,7 +461,7 @@ // If the current tab in |targetMode| is a NTP, it can be reused to open URL. // |completion| is executed after the tab is opened. After Tab is open the // virtual URL is set to the pending navigation item. -- (void)openSelectedTabInMode:(ApplicationMode)targetMode +- (void)openSelectedTabInMode:(ApplicationModeForTabOpening)targetMode withUrlLoadParams:(const UrlLoadParams&)urlLoadParams completion:(ProceduralBlock)completion; // Checks the target BVC's current tab's URL. If this URL is chrome://newtab, @@ -838,7 +838,8 @@ if (_startupParameters) { UrlLoadParams params = UrlLoadParams::InNewTab(_startupParameters.externalURL); - [self dismissModalsAndOpenSelectedTabInMode:ApplicationMode::NORMAL + [self dismissModalsAndOpenSelectedTabInMode:ApplicationModeForTabOpening:: + NORMAL withUrlLoadParams:params dismissOmnibox:YES completion:^{ @@ -1838,7 +1839,8 @@ UrlLoadParams params = UrlLoadParams::InNewTab([command URL]); params.web_params.transition_type = ui::PAGE_TRANSITION_TYPED; ProceduralBlock completion = ^{ - [self dismissModalsAndOpenSelectedTabInMode:ApplicationMode::NORMAL + [self dismissModalsAndOpenSelectedTabInMode:ApplicationModeForTabOpening:: + NORMAL withUrlLoadParams:params dismissOmnibox:YES completion:nil]; @@ -2351,9 +2353,21 @@ } } -- (void)openSelectedTabInMode:(ApplicationMode)targetMode +- (void)openSelectedTabInMode:(ApplicationModeForTabOpening)tabOpeningTargetMode withUrlLoadParams:(const UrlLoadParams&)urlLoadParams completion:(ProceduralBlock)completion { + ApplicationMode targetMode; + + if (tabOpeningTargetMode == ApplicationModeForTabOpening::CURRENT) { + targetMode = self.interfaceProvider.currentInterface.incognito + ? ApplicationMode::INCOGNITO + : ApplicationMode::NORMAL; + } else if (tabOpeningTargetMode == ApplicationModeForTabOpening::NORMAL) { + targetMode = ApplicationMode::NORMAL; + } else { + targetMode = ApplicationMode::INCOGNITO; + } + id<BrowserInterface> targetInterface = targetMode == ApplicationMode::NORMAL ? self.interfaceProvider.mainInterface @@ -2532,7 +2546,8 @@ #pragma mark - TabOpening implementation. -- (void)dismissModalsAndOpenSelectedTabInMode:(ApplicationMode)targetMode +- (void)dismissModalsAndOpenSelectedTabInMode: + (ApplicationModeForTabOpening)targetMode withUrlLoadParams: (const UrlLoadParams&)urlLoadParams dismissOmnibox:(BOOL)dismissOmnibox
diff --git a/ios/chrome/app/startup/chrome_app_startup_parameters.h b/ios/chrome/app/startup/chrome_app_startup_parameters.h index 3b5cb04..aad5aca0 100644 --- a/ios/chrome/app/startup/chrome_app_startup_parameters.h +++ b/ios/chrome/app/startup/chrome_app_startup_parameters.h
@@ -28,6 +28,7 @@ CALLER_APP_GOOGLE_CHROME_SEARCH_EXTENSION, CALLER_APP_GOOGLE_CHROME_CONTENT_EXTENSION, CALLER_APP_GOOGLE_CHROME_SHARE_EXTENSION, + CALLER_APP_GOOGLE_CHROME, MOBILE_SESSION_CALLER_APP_COUNT, };
diff --git a/ios/chrome/app/startup/chrome_app_startup_parameters.mm b/ios/chrome/app/startup/chrome_app_startup_parameters.mm index c0c0372..7fbc9c4 100644 --- a/ios/chrome/app/startup/chrome_app_startup_parameters.mm +++ b/ios/chrome/app/startup/chrome_app_startup_parameters.mm
@@ -389,6 +389,9 @@ if (![_declaredSourceApp length]) return CALLER_APP_NOT_AVAILABLE; + if ([_declaredSourceApp + isEqualToString:[[NSBundle mainBundle] bundleIdentifier]]) + return CALLER_APP_GOOGLE_CHROME; if ([_declaredSourceApp isEqualToString:@"com.google.GoogleMobile"]) return CALLER_APP_GOOGLE_SEARCH; if ([_declaredSourceApp isEqualToString:@"com.google.Gmail"])
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn index 8cf184a1..ca53b74 100644 --- a/ios/chrome/browser/BUILD.gn +++ b/ios/chrome/browser/BUILD.gn
@@ -68,6 +68,7 @@ deps = [ ":settings_resources", "//base", + "//build:branding_buildflags", "//components/autofill/core/browser", "//components/autofill/core/common", "//components/autofill/ios/browser",
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc index 9dda9484..79f25d2 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc +++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.cc
@@ -69,9 +69,6 @@ return base.Append(kIOSChromeCacheDirname); } -const base::FilePath::CharType kIOSChromeChannelIDFilename[] = - FILE_PATH_LITERAL("Origin Bound Certs"); - } // namespace ChromeBrowserStateImpl::ChromeBrowserStateImpl( @@ -116,14 +113,6 @@ base::FilePath cache_path = GetCachePath(base_cache_path); int cache_max_size = 0; - // TODO(crbug.com/903642): Remove the following when no longer needed. - base::FilePath channel_id_path = - state_path_.Append(kIOSChromeChannelIDFilename); - base::DeleteFile(channel_id_path, false); - base::DeleteFile( - base::FilePath(channel_id_path.value() + FILE_PATH_LITERAL("-journal")), - false); - // Make sure we initialize the io_data_ after everything else has been // initialized that we might be reading from the IO thread. io_data_->Init(cookie_path, cache_path, cache_max_size, state_path_);
diff --git a/ios/chrome/browser/memory/BUILD.gn b/ios/chrome/browser/memory/BUILD.gn index e11599c..ee0d8a2 100644 --- a/ios/chrome/browser/memory/BUILD.gn +++ b/ios/chrome/browser/memory/BUILD.gn
@@ -14,6 +14,7 @@ ] deps = [ "//base", + "//build:branding_buildflags", "//components/prefs", "//ios/chrome/browser", "//ios/chrome/browser/ui/util",
diff --git a/ios/chrome/browser/memory/memory_debugger.mm b/ios/chrome/browser/memory/memory_debugger.mm index ac46264..fb52dff 100644 --- a/ios/chrome/browser/memory/memory_debugger.mm +++ b/ios/chrome/browser/memory/memory_debugger.mm
@@ -8,6 +8,7 @@ #include <memory> +#import "build/branding_buildflags.h" #import "ios/chrome/browser/memory/memory_metrics.h" #include "ios/chrome/browser/ui/util/ui_util.h" #import "ios/chrome/browser/ui/util/uikit_ui_util.h" @@ -116,7 +117,7 @@ // official builds. // TODO(lliabraa): Figure out how to support memory warnings (or something // like them) in official builds. -#if CHROMIUM_BUILD +#if BUILDFLAG(CHROMIUM_BRANDING) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" [self addButtonWithTitle:@"Trigger Memory Warning" @@ -124,7 +125,7 @@ action:@selector(_performMemoryWarning) withOrigin:[self originForSubviewAtIndex:index++]]; #pragma clang diagnostic pop -#endif // CHROMIUM_BUILD +#endif // BUILDFLAG(CHROMIUM_BRANDING) // Display a text input to set the amount of artificial memory bloat and a // button to reset the bloat to zero. @@ -144,7 +145,7 @@ // official builds. // TODO(lliabraa): Figure out how to support memory warnings (or something // like them) in official builds. -#if CHROMIUM_BUILD +#if BUILDFLAG(CHROMIUM_BRANDING) // Display a text input to control the rate of continuous memory warnings. _continuousMemoryWarningField = [[UITextField alloc] initWithFrame:CGRectZero]; @@ -154,7 +155,7 @@ inputAction:@selector(updateMemoryWarningInterval) atIndex:index++]; [_continuousMemoryWarningField setText:@"0.0"]; -#endif // CHROMIUM_BUILD +#endif // BUILDFLAG(CHROMIUM_BRANDING) // Display a text input to control the refresh rate of the memory debugger. _refreshField = [[UITextField alloc] initWithFrame:CGRectZero]; @@ -475,7 +476,7 @@ // official builds. // TODO(lliabraa): Figure out how to support memory warnings (or something // like them) in official builds. -#if CHROMIUM_BUILD +#if BUILDFLAG(CHROMIUM_BRANDING) - (void)updateMemoryWarningInterval { [_memoryWarningTimer invalidate]; double timerValue; @@ -511,7 +512,7 @@ repeats:YES]; #pragma clang diagnostic push } -#endif // CHROMIUM_BUILD +#endif // BUILDFLAG(CHROMIUM_BRANDING) #pragma mark UITextViewDelegate methods
diff --git a/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.mm b/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.mm index c7a495c..bc64993d 100644 --- a/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.mm +++ b/ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.mm
@@ -9,6 +9,7 @@ #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/strings/sys_string_conversions.h" +#include "base/system/sys_info.h" #include "base/version.h" #include "components/metrics/metrics_service.h" #include "components/version_info/version_info.h" @@ -70,7 +71,7 @@ // Logs the device's |available_storage| as a UTE stability metric. void LogAvailableStorage(NSInteger available_storage) { UMA_STABILITY_HISTOGRAM_CUSTOM_COUNTS("Stability.iOS.UTE.AvailableStorage", - available_storage, 1, 100000, 100); + available_storage, 1, 200000, 100); } // Logs the OS version change between |os_version| and the current os version. @@ -79,7 +80,7 @@ void LogOSVersionChange(std::string os_version) { base::Version previous_os_version = base::Version(os_version); base::Version current_os_version = - base::Version(version_info::GetVersionNumber()); + base::Version(base::SysInfo::OperatingSystemVersion()); VersionComparison difference = VersionComparison::kSameVersion; if (previous_os_version.CompareTo(current_os_version) != 0) {
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm index d6559435..30b29552 100644 --- a/ios/chrome/browser/prefs/browser_prefs.mm +++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -198,4 +198,11 @@ // Added 07/2019. syncer::MigrateSyncSuppressedPref(prefs); + syncer::ClearObsoleteMemoryPressurePrefs(prefs); + syncer::MigrateSessionsToProxyTabsPrefs(prefs); + syncer::ClearObsoleteUserTypePrefs(prefs); + syncer::ClearObsoleteClearServerDataPrefs(prefs); + syncer::ClearObsoleteAuthErrorPrefs(prefs); + syncer::ClearObsoleteFirstSyncTime(prefs); + syncer::ClearObsoleteSyncLongPollIntervalSeconds(prefs); }
diff --git a/ios/chrome/browser/system_flags.mm b/ios/chrome/browser/system_flags.mm index 7bb4d91e..52edc3d5 100644 --- a/ios/chrome/browser/system_flags.mm +++ b/ios/chrome/browser/system_flags.mm
@@ -18,6 +18,7 @@ #include "base/metrics/field_trial.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" +#include "build/branding_buildflags.h" #include "components/autofill/core/common/autofill_switches.h" #include "components/password_manager/core/common/password_manager_features.h" #include "components/variations/variations_associated_data.h" @@ -84,12 +85,12 @@ bool IsMemoryDebuggingEnabled() { // Always return true for Chromium builds, but check the user default for // official builds because memory debugging should never be enabled on stable. -#if CHROMIUM_BUILD +#if BUILDFLAG(CHROMIUM_BRANDING) return true; #else return [[NSUserDefaults standardUserDefaults] boolForKey:@"EnableMemoryDebugging"]; -#endif // CHROMIUM_BUILD +#endif // BUILDFLAG(CHROMIUM_BRANDING) } bool IsStartupCrashEnabled() {
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/keyboard_observer_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/keyboard_observer_egtest.mm index 064d50f..677a748f 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/keyboard_observer_egtest.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/keyboard_observer_egtest.mm
@@ -3,6 +3,7 @@ // found in the LICENSE file. #import <EarlGrey/EarlGrey.h> +#import <EarlGrey/GREYKeyboard.h> #include "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" @@ -75,6 +76,9 @@ // Observer to be tested. @property(nonatomic, strong) KeyboardObserverHelper* keyboardObserver; +// Token to register a NSNotificationCenter observer. +@property(nonatomic, strong) id<NSObject> notificationToken; + // Delegate mock to confirm the observer callbacks. @property(nonatomic, strong) OCMockObject<KeyboardObserverHelperConsumer>* keyboardObserverDelegateMock; @@ -103,6 +107,7 @@ } - (void)tearDown { + self.notificationToken = nil; self.keyboardObserverDelegateMock = nil; self.keyboardObserver = nil; @@ -118,32 +123,44 @@ // Brings up the keyboard by tapping on one of the form's field. TapOnWebElementWithID(kFormElementID1); + // Wait for keyboard to finish animating. + __block BOOL keyboardDidAppear = NO; + self.notificationToken = [[NSNotificationCenter defaultCenter] + addObserverForName:UIKeyboardDidShowNotification + object:nil + queue:nil + usingBlock:^(NSNotification* note) { + keyboardDidAppear = YES; + }]; + ConditionBlock condition = ^{ + return keyboardDidAppear; + }; + using base::test::ios::WaitUntilConditionOrTimeout; + using base::test::ios::kWaitForUIElementTimeout; + GREYAssert(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition), + @"Wait for keyboard did show notification"); + // Verifies that the taped element is focused. AssertElementIsFocused(kFormElementID1); - // Create the callback expectation. + // Create a new callback expectation. OCMExpect([self.keyboardObserverDelegateMock keyboardDidStayOnScreen]); + // Reset our keyboard boolean. + keyboardDidAppear = NO; + // Tap the second field. TapOnWebElementWithID(kFormElementID2); + // Wait for keyboard to finish animating. + GREYAssert(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition), + @"Wait for keyboard did show notification"); + // Verifies that the taped element is focused. AssertElementIsFocused(kFormElementID2); // Verify the delegate call was made. [self.keyboardObserverDelegateMock verify]; - - // Add another callback expectation. - OCMExpect([self.keyboardObserverDelegateMock keyboardDidStayOnScreen]); - - // Tap the first field. - TapOnWebElementWithID(kFormElementID1); - - // Verifies that the taped element is focused. - AssertElementIsFocused(kFormElementID1); - - // Verify the delegate call was made. - [self.keyboardObserverDelegateMock verify]; } // Tests that when the keyboard actually dismiss the right callback is done.
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm index bb45c3e..ee44ebdb 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -808,10 +808,7 @@ _downloadManagerCoordinator.presenter = [[VerticalAnimationContainer alloc] init]; - if (base::FeatureList::IsEnabled(dialogs::kNonModalDialogs)) { - _javaScriptDialogPresenter = - std::make_unique<OverlayJavaScriptDialogPresenter>(); - } else { + if (!base::FeatureList::IsEnabled(dialogs::kNonModalDialogs)) { _dialogPresenter = [[DialogPresenter alloc] initWithDelegate:self presentingViewController:self]; _javaScriptDialogPresenter = @@ -3393,6 +3390,11 @@ - (web::JavaScriptDialogPresenter*)javaScriptDialogPresenterForWebState: (web::WebState*)webState { + if (base::FeatureList::IsEnabled(dialogs::kNonModalDialogs)) { + return WebStateDelegateTabHelper::FromWebState(webState) + ->GetJavaScriptDialogPresenter(webState); + } + DCHECK(_javaScriptDialogPresenter.get()); return _javaScriptDialogPresenter.get(); }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm index 41e3d027..e53ae4f 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -216,6 +216,12 @@ self.view = [[ContentSuggestionsHeaderView alloc] init]; } +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, + self.fakeOmnibox); +} + - (CGFloat)headerHeight { return content_suggestions::heightForLogoHeader( self.logoIsShowing, self.promoCanShow, YES, [self topInset]);
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn index c298336a..40f19bd 100644 --- a/ios/chrome/browser/ui/omnibox/BUILD.gn +++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -54,6 +54,7 @@ "resources:omnibox_completion_default_favicon", "resources:omnibox_completion_history", "resources:omnibox_completion_search", + "resources:omnibox_popup_recent_query", "resources:search", "//base", ]
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.h b/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.h index 67c9d9e..2f693108 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.h +++ b/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.h
@@ -14,6 +14,7 @@ DEFAULT_FAVICON, HISTORY, SEARCH, + SEARCH_HISTORY, CONVERSION, DICTIONARY, STOCK,
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.mm b/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.mm index 2daf584..1d737bd 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_suggestion_icon_util.mm
@@ -49,6 +49,7 @@ case FALLBACK_ANSWER: NOTREACHED(); return @"omnibox_completion_default_favicon"; + case SEARCH_HISTORY: case OMNIBOX_SUGGESTION_ICON_TYPE_COUNT: NOTREACHED(); return @"omnibox_completion_default_favicon"; @@ -84,6 +85,8 @@ return @"answer_translation"; case FALLBACK_ANSWER: return @"search"; + case SEARCH_HISTORY: + return @"omnibox_popup_recent_query"; case OMNIBOX_SUGGESTION_ICON_TYPE_COUNT: NOTREACHED(); return @"favicon_fallback";
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.mm b/ios/chrome/browser/ui/omnibox/omnibox_util.mm index 8885915a..eb32628 100644 --- a/ios/chrome/browser/ui/omnibox/omnibox_util.mm +++ b/ios/chrome/browser/ui/omnibox/omnibox_util.mm
@@ -55,8 +55,9 @@ case AutocompleteMatchType::CLIPBOARD_IMAGE: return SEARCH; case AutocompleteMatchType::SEARCH_HISTORY: - return base::FeatureList::IsEnabled(kNewOmniboxPopupLayout) ? SEARCH - : HISTORY; + return base::FeatureList::IsEnabled(kNewOmniboxPopupLayout) + ? SEARCH_HISTORY + : HISTORY; case AutocompleteMatchType::CALCULATOR: return CALCULATOR; case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm index 96531373..f72c7d79 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm
@@ -64,7 +64,6 @@ case AutocompleteMatchType::TAB_SEARCH_DEPRECATED: return DEFAULT_FAVICON; case AutocompleteMatchType::CONTACT_DEPRECATED: - case AutocompleteMatchType::SEARCH_HISTORY: case AutocompleteMatchType::SEARCH_OTHER_ENGINE: case AutocompleteMatchType::SEARCH_SUGGEST: case AutocompleteMatchType::SEARCH_SUGGEST_ENTITY: @@ -76,6 +75,8 @@ case AutocompleteMatchType::CLIPBOARD_TEXT: case AutocompleteMatchType::CLIPBOARD_IMAGE: return SEARCH; + case AutocompleteMatchType::SEARCH_HISTORY: + return HISTORY; case AutocompleteMatchType::CALCULATOR: return CALCULATOR; case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
diff --git a/ios/chrome/browser/ui/omnibox/popup/simple_omnibox_icon.mm b/ios/chrome/browser/ui/omnibox/popup/simple_omnibox_icon.mm index 31262c7..7e6e2a4 100644 --- a/ios/chrome/browser/ui/omnibox/popup/simple_omnibox_icon.mm +++ b/ios/chrome/browser/ui/omnibox/popup/simple_omnibox_icon.mm
@@ -62,6 +62,7 @@ case DEFAULT_FAVICON: case HISTORY: case SEARCH: + case SEARCH_HISTORY: return NO; case CALCULATOR: case CONVERSION:
diff --git a/ios/chrome/browser/ui/omnibox/resources/BUILD.gn b/ios/chrome/browser/ui/omnibox/resources/BUILD.gn index 43c652a..2301d851 100644 --- a/ios/chrome/browser/ui/omnibox/resources/BUILD.gn +++ b/ios/chrome/browser/ui/omnibox/resources/BUILD.gn
@@ -170,3 +170,11 @@ "background_stroke.imageset/background_stroke@3x.png", ] } + +imageset("omnibox_popup_recent_query") { + sources = [ + "omnibox_popup_recent_query.imageset/Contents.json", + "omnibox_popup_recent_query.imageset/omnibox_popup_recent_query@2x.png", + "omnibox_popup_recent_query.imageset/omnibox_popup_recent_query@3x.png", + ] +}
diff --git a/ios/chrome/browser/ui/omnibox/resources/omnibox_popup_recent_query.imageset/Contents.json b/ios/chrome/browser/ui/omnibox/resources/omnibox_popup_recent_query.imageset/Contents.json new file mode 100644 index 0000000..2eb7869 --- /dev/null +++ b/ios/chrome/browser/ui/omnibox/resources/omnibox_popup_recent_query.imageset/Contents.json
@@ -0,0 +1,18 @@ +{ + "images": [ + { + "idiom": "universal", + "scale": "2x", + "filename": "omnibox_popup_recent_query@2x.png" + }, + { + "idiom": "universal", + "scale": "3x", + "filename": "omnibox_popup_recent_query@3x.png" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +}
diff --git a/ios/chrome/browser/ui/omnibox/resources/omnibox_popup_recent_query.imageset/omnibox_popup_recent_query@2x.png b/ios/chrome/browser/ui/omnibox/resources/omnibox_popup_recent_query.imageset/omnibox_popup_recent_query@2x.png new file mode 100644 index 0000000..34852fb --- /dev/null +++ b/ios/chrome/browser/ui/omnibox/resources/omnibox_popup_recent_query.imageset/omnibox_popup_recent_query@2x.png Binary files differ
diff --git a/ios/chrome/browser/ui/omnibox/resources/omnibox_popup_recent_query.imageset/omnibox_popup_recent_query@3x.png b/ios/chrome/browser/ui/omnibox/resources/omnibox_popup_recent_query.imageset/omnibox_popup_recent_query@3x.png new file mode 100644 index 0000000..7f4c791 --- /dev/null +++ b/ios/chrome/browser/ui/omnibox/resources/omnibox_popup_recent_query.imageset/omnibox_popup_recent_query@3x.png Binary files differ
diff --git a/ios/chrome/browser/ui/open_in/open_in_mediator.mm b/ios/chrome/browser/ui/open_in/open_in_mediator.mm index 8ebf649..ef70af6e 100644 --- a/ios/chrome/browser/ui/open_in/open_in_mediator.mm +++ b/ios/chrome/browser/ui/open_in/open_in_mediator.mm
@@ -37,6 +37,11 @@ self = [super init]; if (self) { _webStateList = webStateList; + // Set the delegates for all existing webstates in the |_webStateList|. + for (int i = 0; i < _webStateList->count(); i++) { + web::WebState* webState = _webStateList->GetWebStateAt(i); + OpenInTabHelper::FromWebState(webState)->SetDelegate(self); + } _webStateListObserver = std::make_unique<WebStateListObserverBridge>(self); _webStateList->AddObserver(_webStateListObserver.get()); } @@ -69,7 +74,6 @@ atIndex:(int)index activating:(BOOL)activating { DCHECK_EQ(_webStateList, webStateList); - OpenInTabHelper::FromWebState(webState)->SetDelegate(self); }
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm index f9d5403..e643beaa 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
@@ -584,6 +584,7 @@ self.selectedUnreadItemCount, self.selectedReadItemCount); if (self.toolbarManager.buttonItemsUpdated) [self setToolbarItems:[self.toolbarManager buttonItems] animated:YES]; + [self.toolbarManager updateMarkButtonTitle]; } #pragma mark - Item Editing Helpers
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_manager.h b/ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_manager.h index cda7abd5..68366052d 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_manager.h +++ b/ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_manager.h
@@ -40,6 +40,11 @@ // to |self.commandHandler|. - (NSArray<UIBarButtonItem*>*)buttonItems; +// Updates the title of the mark button based on the selection state. This +// method isn't part of the update of the selection state to avoid updating it +// too soon and messing with VoiceOver. See https://crbug.com/985744 . +- (void)updateMarkButtonTitle; + // Returns an empty ActionSheetCoordinator anchored to the mark button with no // message and no title. - (ActionSheetCoordinator*)markButtonConfirmationWithBaseViewController:
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_manager.mm b/ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_manager.mm index a9c4e3a..d18cca1 100644 --- a/ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_manager.mm +++ b/ios/chrome/browser/ui/reading_list/reading_list_toolbar_button_manager.mm
@@ -116,7 +116,6 @@ return; BOOL hadSelectedItems = _selectionState != ReadingListSelectionState::NONE; _selectionState = selectionState; - _markButton.title = GetMarkButtonTitleForSelectionState(_selectionState); // Check whether selection status has changed to or from NONE. if ((_selectionState != ReadingListSelectionState::NONE) != hadSelectedItems) _buttonItems = nil; @@ -144,6 +143,12 @@ self.selectionState = ReadingListSelectionState::NONE; } +- (void)updateMarkButtonTitle { + if (!_editing) + return; + _markButton.title = GetMarkButtonTitleForSelectionState(_selectionState); +} + - (BOOL)buttonItemsUpdated { // When the changes to the values of this class's public properties require // an updated buttons array, |_buttonItems| will be reset to nil. Subsequent
diff --git a/ios/chrome/browser/ui/settings/BUILD.gn b/ios/chrome/browser/ui/settings/BUILD.gn index d0f90ada..1c386ca 100644 --- a/ios/chrome/browser/ui/settings/BUILD.gn +++ b/ios/chrome/browser/ui/settings/BUILD.gn
@@ -97,6 +97,7 @@ "resources:sync_and_google_services_sync_on", "//base", "//base:i18n", + "//build:branding_buildflags", "//components/autofill/core/browser", "//components/autofill/core/common", "//components/browsing_data/core",
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm index 752bf6ef..de48c09f 100644 --- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -9,6 +9,7 @@ #include "base/feature_list.h" #import "base/mac/foundation_util.h" #include "base/strings/sys_string_conversions.h" +#include "build/branding_buildflags.h" #include "components/autofill/core/common/autofill_prefs.h" #include "components/keyed_service/core/service_access_type.h" #include "components/password_manager/core/browser/password_store.h" @@ -150,9 +151,9 @@ ItemTypeArticlesForYou, }; -#if CHROMIUM_BUILD && !defined(NDEBUG) +#if BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) NSString* kDevViewSourceKey = @"DevViewSource"; -#endif // CHROMIUM_BUILD && !defined(NDEBUG) +#endif // BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) } // namespace @@ -435,14 +436,14 @@ toSectionWithIdentifier:SectionIdentifierDebug]; } -#if CHROMIUM_BUILD && !defined(NDEBUG) +#if BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) [model addItem:[self viewSourceSwitchItem] toSectionWithIdentifier:SectionIdentifierDebug]; [model addItem:[self collectionViewCatalogDetailItem] toSectionWithIdentifier:SectionIdentifierDebug]; [model addItem:[self tableViewCatalogDetailItem] toSectionWithIdentifier:SectionIdentifierDebug]; -#endif // CHROMIUM_BUILD && !defined(NDEBUG) +#endif // BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) } #pragma mark - Model Items @@ -645,7 +646,7 @@ return articlesForYouSwitchItem; } -#if CHROMIUM_BUILD && !defined(NDEBUG) +#if BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) - (SettingsSwitchItem*)viewSourceSwitchItem { return [self switchItemWithType:ItemTypeViewSource @@ -667,7 +668,7 @@ detailText:nil iconImageName:kSettingsDebugImageName]; } -#endif // CHROMIUM_BUILD && !defined(NDEBUG) +#endif // BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) #pragma mark Item Constructors @@ -751,7 +752,7 @@ break; } case ItemTypeViewSource: { -#if CHROMIUM_BUILD && !defined(NDEBUG) +#if BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) SettingsSwitchCell* switchCell = base::mac::ObjCCastStrict<SettingsSwitchCell>(cell); [switchCell.switchView addTarget:self @@ -759,7 +760,7 @@ forControlEvents:UIControlEventValueChanged]; #else NOTREACHED(); -#endif // CHROMIUM_BUILD && !defined(NDEBUG) +#endif // BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) break; } default: @@ -901,7 +902,7 @@ [_articlesEnabled setValue:newSwitchValue]; } -#if CHROMIUM_BUILD && !defined(NDEBUG) +#if BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) - (void)viewSourceSwitchToggled:(UISwitch*)sender { NSIndexPath* switchPath = [self.tableViewModel indexPathForItemType:ItemTypeViewSource @@ -915,7 +916,7 @@ switchItem.on = newSwitchValue; [self setBooleanNSUserDefaultsValue:newSwitchValue forKey:kDevViewSourceKey]; } -#endif // CHROMIUM_BUILD && !defined(NDEBUG) +#endif // BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) #pragma mark Private methods @@ -944,14 +945,14 @@ // Chromium builds, but for official builds it is gated by an experimental flag // because the "Debug" section should never be showing in stable channel. - (BOOL)hasDebugSection { -#if CHROMIUM_BUILD && !defined(NDEBUG) +#if BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) return YES; #else if (experimental_flags::IsMemoryDebuggingEnabled()) { return YES; } return NO; -#endif // CHROMIUM_BUILD && !defined(NDEBUG) +#endif // BUILDFLAG(CHROMIUM_BRANDING) && !defined(NDEBUG) } // Updates the identity cell.
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_bottom_toolbar.h b/ios/chrome/browser/ui/tab_grid/tab_grid_bottom_toolbar.h index 5427496..616e7ca 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_bottom_toolbar.h +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_bottom_toolbar.h
@@ -20,10 +20,10 @@ // Remote page: [ trailingButton] // // Other screen size: -// Large newTabButton, transparent background. +// Large newTabButton, floating layout without UIToolbar. // Incognito & Regular page: [ newTabButton] // Remote page: [ ] -@interface TabGridBottomToolbar : UIToolbar +@interface TabGridBottomToolbar : UIView // This property together with self.traitCollection control the items shown // in toolbar and its background color. Setting this property will also set it // on |newTabButton|. @@ -32,11 +32,9 @@ // contents, visibility and actions. @property(nonatomic, strong, readonly) UIBarButtonItem* leadingButton; @property(nonatomic, strong, readonly) UIBarButtonItem* trailingButton; -// Clang does not allow property getters to start with the reserved word "new", -// but provides a workaround. The getter must be set before the property is -// declared. -- (TabGridNewTabButton*)newTabButton __attribute__((objc_method_family(none))); -@property(nonatomic, strong, readonly) TabGridNewTabButton* newTabButton; + +// Sets target/action for tapping event on new tab button. +- (void)setNewTabButtonTarget:(id)target action:(SEL)action; // Hides components and uses a black background color for tab grid transition // animation.
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_bottom_toolbar.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_bottom_toolbar.mm index 1200936..86f0239 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_bottom_toolbar.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_bottom_toolbar.mm
@@ -13,33 +13,17 @@ #endif @implementation TabGridBottomToolbar { + UIToolbar* _toolbar; + UIBarButtonItem* _newTabButtonItem; UIBarButtonItem* _spaceItem; - UIImage* _transparentBackground; - UIImage* _translucentBackground; -} - -- (void)hide { - self.newTabButton.button.alpha = 0.0; -} - -- (void)show { - self.newTabButton.button.alpha = 1.0; + NSArray<NSLayoutConstraint*>* _compactConstraints; + NSArray<NSLayoutConstraint*>* _floatingConstraints; + TabGridNewTabButton* _smallNewTabButton; + TabGridNewTabButton* _largeNewTabButton; } #pragma mark - UIView -// Controls hit testing of the bottom toolbar. When the toolbar is transparent, -// only respond to tapping on the new tab button. -- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event { - // The toolbar is not tranparent under compact layout. - if ([self shouldUseCompactLayout]) { - return [super pointInside:point withEvent:event]; - } - return [self.newTabButton.button - pointInside:[self convertPoint:point toView:self.newTabButton.button] - withEvent:event]; -} - - (void)willMoveToSuperview:(UIView*)newSuperview { // The first time this moves to a superview, perform the view setup. if (newSuperview && self.subviews.count == 0) { @@ -52,63 +36,64 @@ [self updateLayout]; } +// Controls hit testing of the bottom toolbar. When the toolbar is transparent, +// only respond to tapping on the new tab button. +- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event { + if ([self shouldUseCompactLayout]) { + return [super pointInside:point withEvent:event]; + } + // Only floating new tab button is tappable. + return [_largeNewTabButton pointInside:[self convertPoint:point + toView:_largeNewTabButton] + withEvent:event]; +} + #pragma mark - Public +// TODO(crbug.com/929981): "traitCollectionDidChange:" method won't get called +// when the view is not displayed, and in that case the only chance +// TabGridBottomToolbar can update its layout is when the TabGrid sets its +// "page" property in the +// "viewWillTransitionToSize:withTransitionCoordinator:" method. An early +// return for "self.page == page" can be added here since iOS 13 where the bug +// is fixed in UIKit. - (void)setPage:(TabGridPage)page { - // TODO(crbug.com/929981): "traitCollectionDidChange:" method won't get called - // when the view is not displayed, and in that case the only chance - // TabGridBottomToolbar can update its layout is when the TabGrid sets its - // "page" property in the - // "viewWillTransitionToSize:withTransitionCoordinator:" method. An early - // return for "self.page == page" can be added here once UIKit fixes its - // issue or TabGridBottomToolbar is turned into a view controller. _page = page; - self.newTabButton.page = page; + _smallNewTabButton.page = page; + _largeNewTabButton.page = page; [self updateLayout]; } +- (void)setNewTabButtonTarget:(id)target action:(SEL)action { + [_smallNewTabButton addTarget:target + action:action + forControlEvents:UIControlEventTouchUpInside]; + [_largeNewTabButton addTarget:target + action:action + forControlEvents:UIControlEventTouchUpInside]; +} + +- (void)hide { + _smallNewTabButton.alpha = 0.0; + _largeNewTabButton.alpha = 0.0; +} + +- (void)show { + _smallNewTabButton.alpha = 1.0; + _largeNewTabButton.alpha = 1.0; +} + #pragma mark - Private -- (void)updateLayout { - if (self.page == TabGridPageRemoteTabs) { - if ([self shouldUseCompactLayout]) { - [self setItems:@[ _spaceItem, self.trailingButton ]]; - [self setBackgroundImage:_translucentBackground - forToolbarPosition:UIBarPositionAny - barMetrics:UIBarMetricsDefault]; - } else { - [self setItems:@[]]; - [self setBackgroundImage:_transparentBackground - forToolbarPosition:UIToolbarPositionAny - barMetrics:UIBarMetricsDefault]; - } - } else { - if ([self shouldUseCompactLayout]) { - self.newTabButton.sizeClass = TabGridNewTabButtonSizeClassSmall; - [self setItems:@[ - self.leadingButton, _spaceItem, _newTabButton, _spaceItem, - self.trailingButton - ]]; - [self setBackgroundImage:_translucentBackground - forToolbarPosition:UIBarPositionAny - barMetrics:UIBarMetricsDefault]; - } else { - self.newTabButton.sizeClass = TabGridNewTabButtonSizeClassLarge; - [self setItems:@[ _spaceItem, _newTabButton ]]; - [self setBackgroundImage:_transparentBackground - forToolbarPosition:UIToolbarPositionAny - barMetrics:UIBarMetricsDefault]; - } - } -} - - (void)setupViews { - self.translatesAutoresizingMaskIntoConstraints = NO; - self.barStyle = UIBarStyleBlack; - self.translucent = YES; + // For Regular(V) x Compact(H) layout, display UIToolbar. + _toolbar = [[UIToolbar alloc] init]; + _toolbar.translatesAutoresizingMaskIntoConstraints = NO; + _toolbar.barStyle = UIBarStyleBlack; + _toolbar.translucent = YES; // Remove the border of UIToolbar. - [self setShadowImage:[[UIImage alloc] init] - forToolbarPosition:UIBarPositionAny]; + [_toolbar setShadowImage:[[UIImage alloc] init] + forToolbarPosition:UIBarPositionAny]; _leadingButton = [[UIBarButtonItem alloc] init]; _leadingButton.tintColor = UIColorFromRGB(kTabGridToolbarTextButtonColor); @@ -117,20 +102,86 @@ _trailingButton.style = UIBarButtonItemStyleDone; _trailingButton.tintColor = UIColorFromRGB(kTabGridToolbarTextButtonColor); - _newTabButton = [[TabGridNewTabButton alloc] init]; - _spaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; - // Store the translucent background generated by self.translucent=YES. - _translucentBackground = - [self backgroundImageForToolbarPosition:UIBarPositionAny - barMetrics:UIBarMetricsDefault]; - _transparentBackground = [[UIImage alloc] init]; + UIImage* regularImage = [UIImage imageNamed:@"new_tab_toolbar_button"]; + UIImage* incognitoImage = + [UIImage imageNamed:@"new_tab_toolbar_button_incognito"]; + _smallNewTabButton = + [[TabGridNewTabButton alloc] initWithRegularImage:regularImage + incognitoImage:incognitoImage]; + _smallNewTabButton.translatesAutoresizingMaskIntoConstraints = NO; + _smallNewTabButton.page = self.page; - [self updateLayout]; + _newTabButtonItem = + [[UIBarButtonItem alloc] initWithCustomView:_smallNewTabButton]; + // Set UIBarButtonItem.image to get a built-in accessibility modal panel. + // The panel will be shown when user long press on the button, under + // accessibility font size. The image will be normalized into a bi-color + // image, so the incognito image is suitable because it has a transparent + // "+". Use the larger image for higher resolution. + _newTabButtonItem.image = incognitoImage; + _newTabButtonItem.title = _smallNewTabButton.accessibilityLabel; + + _compactConstraints = @[ + [_toolbar.topAnchor constraintEqualToAnchor:self.topAnchor], + [_toolbar.bottomAnchor + constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor], + [_toolbar.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], + [_toolbar.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], + ]; + + // For other layout, display a floating new tab button. + _largeNewTabButton = [[TabGridNewTabButton alloc] + initWithRegularImage:[UIImage imageNamed:@"new_tab_floating_button"] + incognitoImage: + [UIImage imageNamed:@"new_tab_floating_button_incognito"]]; + _largeNewTabButton.translatesAutoresizingMaskIntoConstraints = NO; + _largeNewTabButton.page = self.page; + + _floatingConstraints = @[ + [_largeNewTabButton.topAnchor constraintEqualToAnchor:self.topAnchor], + [_largeNewTabButton.bottomAnchor + constraintEqualToAnchor:self.safeAreaLayoutGuide.bottomAnchor + constant:-kTabGridFloatingButtonVerticalInset], + [_largeNewTabButton.trailingAnchor + constraintEqualToAnchor:self.trailingAnchor + constant:-kTabGridFloatingButtonHorizontalInset], + ]; +} + +- (void)updateLayout { + if ([self shouldUseCompactLayout]) { + // For incognito/regular pages, display all 3 buttons; + // For remote tabs page, only display new tab button. + if (self.page == TabGridPageRemoteTabs) { + [_toolbar setItems:@[ _spaceItem, self.trailingButton ]]; + } else { + [_toolbar setItems:@[ + self.leadingButton, _spaceItem, _newTabButtonItem, _spaceItem, + self.trailingButton + ]]; + } + + [NSLayoutConstraint deactivateConstraints:_floatingConstraints]; + [_largeNewTabButton removeFromSuperview]; + [self addSubview:_toolbar]; + [NSLayoutConstraint activateConstraints:_compactConstraints]; + } else { + [NSLayoutConstraint deactivateConstraints:_compactConstraints]; + [_toolbar removeFromSuperview]; + + if (self.page == TabGridPageRemoteTabs) { + [NSLayoutConstraint deactivateConstraints:_floatingConstraints]; + [_largeNewTabButton removeFromSuperview]; + } else { + [self addSubview:_largeNewTabButton]; + [NSLayoutConstraint activateConstraints:_floatingConstraints]; + } + } } // Returns YES if should use compact bottom toolbar layout. @@ -139,8 +190,7 @@ // contradict the keyWindow's |traitCollection| because UIView's // |-traitCollectionDidChange:| is not properly called when the view rotates // while it is in a ViewController deeper in the ViewController hierarchy. Use - // self.traitCollection once this is fixed by UIKit, or remove this function - // if TabGridBottomToolbar is turned into a view controller. + // self.traitCollection since iOS 13 where the bug is fixed in UIKit. return UIApplication.sharedApplication.keyWindow.traitCollection .verticalSizeClass == UIUserInterfaceSizeClassRegular && UIApplication.sharedApplication.keyWindow.traitCollection
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_new_tab_button.h b/ios/chrome/browser/ui/tab_grid/tab_grid_new_tab_button.h index b55b3b5..c82ae31c 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_new_tab_button.h +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_new_tab_button.h
@@ -9,19 +9,18 @@ #import "ios/chrome/browser/ui/tab_grid/tab_grid_paging.h" -// The size class determines the intrinsic size of the button. -typedef NS_ENUM(NSUInteger, TabGridNewTabButtonSizeClass) { - TabGridNewTabButtonSizeClassSmall = 1, - TabGridNewTabButtonSizeClassLarge, -}; +@interface TabGridNewTabButton : UIButton -// The "new tab" button is a button that the user taps when they want to create -// a new tab. Every combination of |sizeClass| and |page| results in a -// differently configured button. -@interface TabGridNewTabButton : UIBarButtonItem -@property(nonatomic, strong, readonly) UIButton* button; @property(nonatomic, assign) TabGridPage page; -@property(nonatomic, assign) TabGridNewTabButtonSizeClass sizeClass; + +// Init with image for regular/incognito page. +- (instancetype)initWithRegularImage:(UIImage*)regularImage + incognitoImage:(UIImage*)incognitoImage + NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE; +- (instancetype)initWithCoder:(NSCoder*)coder NS_UNAVAILABLE; + @end #endif // IOS_CHROME_BROWSER_UI_TAB_GRID_TAB_GRID_NEW_TAB_BUTTON_H_
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_new_tab_button.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_new_tab_button.mm index ad3f021..0e9b01c 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_new_tab_button.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_new_tab_button.mm
@@ -13,66 +13,19 @@ #endif @interface TabGridNewTabButton () { - UIView* _container; - UIImage* _regularImage; UIImage* _incognitoImage; - UIImage* _smallRegularImage; - UIImage* _smallIncognitoImage; - UIImage* _largeRegularImage; - UIImage* _largeIncognitoImage; - - NSArray* _smallButtonConstraints; - NSArray* _largeButtonConstraints; } @end @implementation TabGridNewTabButton -- (instancetype)init { - self = [super init]; +- (instancetype)initWithRegularImage:(UIImage*)regularImage + incognitoImage:(UIImage*)incognitoImage { + self = [super initWithFrame:CGRectZero]; if (self) { - _smallRegularImage = [UIImage imageNamed:@"new_tab_toolbar_button"]; - _smallIncognitoImage = - [UIImage imageNamed:@"new_tab_toolbar_button_incognito"]; - _largeRegularImage = [UIImage imageNamed:@"new_tab_floating_button"]; - _largeIncognitoImage = - [UIImage imageNamed:@"new_tab_floating_button_incognito"]; - // Set UIBarButtonItem.image to get a built-in accessibility modal panel. - // The panel will be shown when user long press on the button, under - // accessibility font size. The image will be normalized into a bi-color - // image, so the incognito image is suitable because it has a transparent - // "+". Use the larger image for higher resolution. - self.image = _largeIncognitoImage; - - _container = [[UIView alloc] init]; - _container.translatesAutoresizingMaskIntoConstraints = NO; - self.customView = _container; - - _button = [[UIButton alloc] init]; - _button.translatesAutoresizingMaskIntoConstraints = NO; - // Set a high compression resistance priority otherwise the button will be - // compressed by UIToolbar's height constraint. - [_button - setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh + 1 - forAxis:UILayoutConstraintAxisVertical]; - [_container addSubview:_button]; - - _smallButtonConstraints = @[ - [_button.topAnchor constraintEqualToAnchor:_container.topAnchor], - [_button.bottomAnchor constraintEqualToAnchor:_container.bottomAnchor], - [_button.leadingAnchor constraintEqualToAnchor:_container.leadingAnchor], - [_button.trailingAnchor constraintEqualToAnchor:_container.trailingAnchor] - ]; - - _largeButtonConstraints = @[ - [_button.topAnchor constraintEqualToAnchor:_container.topAnchor], - [_button.bottomAnchor - constraintEqualToAnchor:_container.bottomAnchor - constant:-kTabGridFloatingButtonVerticalInset], - [_button.leadingAnchor constraintEqualToAnchor:_container.leadingAnchor], - [_button.trailingAnchor constraintEqualToAnchor:_container.trailingAnchor] - ]; + _regularImage = regularImage; + _incognitoImage = incognitoImage; } return self; } @@ -82,61 +35,25 @@ - (void)setPage:(TabGridPage)page { if (page == _page) return; + UIImage* renderedImage; switch (page) { case TabGridPageIncognitoTabs: - self.button.accessibilityLabel = + self.accessibilityLabel = l10n_util::GetNSString(IDS_IOS_TAB_GRID_CREATE_NEW_INCOGNITO_TAB); - break; - case TabGridPageRegularTabs: - self.button.accessibilityLabel = - l10n_util::GetNSString(IDS_IOS_TAB_GRID_CREATE_NEW_TAB); - break; - case TabGridPageRemoteTabs: - break; - } - self.title = self.button.accessibilityLabel; - _page = page; - [self updateButtonImage]; -} - -- (void)setSizeClass:(TabGridNewTabButtonSizeClass)sizeClass { - if (sizeClass == _sizeClass) - return; - switch (sizeClass) { - case TabGridNewTabButtonSizeClassSmall: - _regularImage = _smallRegularImage; - _incognitoImage = _smallIncognitoImage; - [NSLayoutConstraint deactivateConstraints:_largeButtonConstraints]; - [NSLayoutConstraint activateConstraints:_smallButtonConstraints]; - break; - case TabGridNewTabButtonSizeClassLarge: - _regularImage = _largeRegularImage; - _incognitoImage = _largeIncognitoImage; - [NSLayoutConstraint deactivateConstraints:_smallButtonConstraints]; - [NSLayoutConstraint activateConstraints:_largeButtonConstraints]; - break; - } - _sizeClass = sizeClass; - [self updateButtonImage]; -} - -#pragma mark - Private - -- (void)updateButtonImage { - UIImage* renderedImage; - switch (self.page) { - case TabGridPageIncognitoTabs: renderedImage = [_incognitoImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; break; case TabGridPageRegularTabs: + self.accessibilityLabel = + l10n_util::GetNSString(IDS_IOS_TAB_GRID_CREATE_NEW_TAB); renderedImage = [_regularImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; break; - default: + case TabGridPageRemoteTabs: break; } - [self.button setImage:renderedImage forState:UIControlStateNormal]; + _page = page; + [self setImage:renderedImage forState:UIControlStateNormal]; } @end
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm index 3b9b835d..8655386 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -99,8 +99,8 @@ } } // namespace -@interface TabGridViewController ()<GridViewControllerDelegate, - UIScrollViewAccessibilityDelegate> +@interface TabGridViewController () <GridViewControllerDelegate, + UIScrollViewAccessibilityDelegate> // It is programmer error to broadcast incognito content visibility when the // view is not visible. Bookkeeping is based on |-viewWillAppear:| and // |-viewWillDisappear methods. Note that the |Did| methods are not reliably @@ -744,9 +744,16 @@ // Adds the bottom toolbar and sets constraints. - (void)setupBottomToolbar { TabGridBottomToolbar* bottomToolbar = [[TabGridBottomToolbar alloc] init]; + self.bottomToolbar = bottomToolbar; bottomToolbar.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:bottomToolbar]; - self.bottomToolbar = bottomToolbar; + [NSLayoutConstraint activateConstraints:@[ + [bottomToolbar.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + [bottomToolbar.leadingAnchor + constraintEqualToAnchor:self.view.leadingAnchor], + [bottomToolbar.trailingAnchor + constraintEqualToAnchor:self.view.trailingAnchor], + ]]; bottomToolbar.leadingButton.target = self; bottomToolbar.leadingButton.action = @selector(closeAllButtonTapped:); @@ -757,18 +764,8 @@ bottomToolbar.trailingButton.target = self; bottomToolbar.trailingButton.action = @selector(doneButtonTapped:); - [bottomToolbar.newTabButton.button addTarget:self - action:@selector(newTabButtonTapped:) - forControlEvents:UIControlEventTouchUpInside]; - - [NSLayoutConstraint activateConstraints:@[ - [bottomToolbar.bottomAnchor - constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], - [bottomToolbar.leadingAnchor - constraintEqualToAnchor:self.view.leadingAnchor], - [bottomToolbar.trailingAnchor - constraintEqualToAnchor:self.view.trailingAnchor], - ]]; + [bottomToolbar setNewTabButtonTarget:self + action:@selector(newTabButtonTapped:)]; } - (void)configureViewControllerForCurrentSizeClassesAndPage {
diff --git a/ios/chrome/browser/ui/webui/BUILD.gn b/ios/chrome/browser/ui/webui/BUILD.gn index 447abb7..6a0cae91 100644 --- a/ios/chrome/browser/ui/webui/BUILD.gn +++ b/ios/chrome/browser/ui/webui/BUILD.gn
@@ -37,6 +37,7 @@ deps = [ "//base", "//base:i18n", + "//build:branding_buildflags", "//components/autofill/core/browser", "//components/crash/core/browser", "//components/flags_ui",
diff --git a/ios/chrome/browser/ui/webui/flags_ui.cc b/ios/chrome/browser/ui/webui/flags_ui.cc index f852803..70fb2f84 100644 --- a/ios/chrome/browser/ui/webui/flags_ui.cc +++ b/ios/chrome/browser/ui/webui/flags_ui.cc
@@ -14,6 +14,7 @@ #include "base/memory/ptr_util.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" +#include "build/branding_buildflags.h" #include "components/flags_ui/flags_ui_constants.h" #include "components/flags_ui/flags_ui_pref_names.h" #include "components/flags_ui/pref_service_flags_storage.h" @@ -170,9 +171,9 @@ } void FlagsDOMHandler::HandleRestartBrowser(const base::ListValue* args) { -#if CHROMIUM_BUILD +#if BUILDFLAG(CHROMIUM_BRANDING) CHECK(false); -#endif // CHROMIUM_BUILD +#endif // BUILDFLAG(CHROMIUM_BRANDING) } void FlagsDOMHandler::HandleResetAllFlags(const base::ListValue* args) {
diff --git a/ios/chrome/browser/web/web_state_delegate_tab_helper.h b/ios/chrome/browser/web/web_state_delegate_tab_helper.h index 9d768db..528da58 100644 --- a/ios/chrome/browser/web/web_state_delegate_tab_helper.h +++ b/ios/chrome/browser/web/web_state_delegate_tab_helper.h
@@ -6,6 +6,7 @@ #define IOS_CHROME_BROWSER_WEB_WEB_STATE_DELEGATE_TAB_HELPER_H_ #include "base/memory/weak_ptr.h" +#import "ios/chrome/browser/ui/dialogs/overlay_java_script_dialog_presenter.h" #import "ios/web/public/web_state/web_state_delegate.h" #include "ios/web/public/web_state/web_state_user_data.h" @@ -22,6 +23,8 @@ // into this tab helper. // web::WebStateDelegate: + web::JavaScriptDialogPresenter* GetJavaScriptDialogPresenter( + web::WebState* source) override; void OnAuthRequired( web::WebState* source, NSURLProtectionSpace* protection_space, @@ -37,6 +40,7 @@ void OnHTTPAuthOverlayFinished(web::WebStateDelegate::AuthCallback callback, OverlayResponse* response); + OverlayJavaScriptDialogPresenter java_script_dialog_presenter_; base::WeakPtrFactory<WebStateDelegateTabHelper> weak_factory_; };
diff --git a/ios/chrome/browser/web/web_state_delegate_tab_helper.mm b/ios/chrome/browser/web/web_state_delegate_tab_helper.mm index 935851c..6abae5e 100644 --- a/ios/chrome/browser/web/web_state_delegate_tab_helper.mm +++ b/ios/chrome/browser/web/web_state_delegate_tab_helper.mm
@@ -23,6 +23,11 @@ WebStateDelegateTabHelper::~WebStateDelegateTabHelper() = default; +web::JavaScriptDialogPresenter* +WebStateDelegateTabHelper::GetJavaScriptDialogPresenter(web::WebState* source) { + return &java_script_dialog_presenter_; +} + void WebStateDelegateTabHelper::OnAuthRequired( web::WebState* source, NSURLProtectionSpace* protection_space,
diff --git a/ios/chrome/browser/web/web_state_delegate_tab_helper_unittest.mm b/ios/chrome/browser/web/web_state_delegate_tab_helper_unittest.mm index b01450e6..d96710a 100644 --- a/ios/chrome/browser/web/web_state_delegate_tab_helper_unittest.mm +++ b/ios/chrome/browser/web/web_state_delegate_tab_helper_unittest.mm
@@ -7,6 +7,9 @@ #include "ios/chrome/browser/overlays/public/overlay_request.h" #import "ios/chrome/browser/overlays/public/overlay_request_queue.h" #import "ios/chrome/browser/overlays/public/web_content_area/http_auth_overlay.h" +#import "ios/chrome/browser/overlays/public/web_content_area/java_script_alert_overlay.h" +#include "ios/web/public/java_script_dialog_presenter.h" +#include "ios/web/public/java_script_dialog_type.h" #import "ios/web/public/test/fakes/test_web_state.h" #include "testing/gtest/include/gtest/gtest.h" #import "testing/gtest_mac.h" @@ -60,3 +63,30 @@ EXPECT_TRUE(request); EXPECT_TRUE(request->GetConfig<HTTPAuthOverlayRequestConfig>()); } + +// Tests that GetJavaScriptDialogPresenter() returns an overlay-based JavaScript +// dialog presenter. +TEST_F(WebStateDelegateTabHelperTest, GetJavaScriptDialogPresenter) { + // Verify that the delegate returns a non-null presenter. + web::JavaScriptDialogPresenter* presenter = + delegate()->GetJavaScriptDialogPresenter(web_state()); + EXPECT_TRUE(presenter); + + // Present a JavaScript alert. + GURL kOriginUrl("http://chromium.test"); + web::DialogClosedCallback callback = + base::BindOnce(^(bool success, NSString* user_input){ + }); + presenter->RunJavaScriptDialog(web_state(), kOriginUrl, + web::JAVASCRIPT_DIALOG_TYPE_ALERT, @"", @"", + std::move(callback)); + + // Verify that JavaScript alert OverlayRequest has been added to the + // WebState's queue. + OverlayRequestQueue* queue = OverlayRequestQueue::FromWebState( + web_state(), OverlayModality::kWebContentArea); + ASSERT_TRUE(queue); + OverlayRequest* request = queue->front_request(); + EXPECT_TRUE(request); + EXPECT_TRUE(request->GetConfig<JavaScriptAlertOverlayRequestConfig>()); +}
diff --git a/ios/web/common/features.h b/ios/web/common/features.h index 0ec2ce4..0e0bcca4 100644 --- a/ios/web/common/features.h +++ b/ios/web/common/features.h
@@ -23,10 +23,6 @@ // https://crbug.com/841105. extern const base::Feature kCrashOnUnexpectedURLChange; -// Used to disconnect the scroll proxy during slimnav restore. This is a -// speculative change to mitigate the crashes in https://crbug.com/959499. -extern const base::Feature kDisconnectScrollProxyDuringRestore; - // Used to enable the workaround for WKWebView history clobber bug // (crbug.com/887497). extern const base::Feature kHistoryClobberWorkaround;
diff --git a/ios/web/common/features.mm b/ios/web/common/features.mm index 754563d..fdc2dda 100644 --- a/ios/web/common/features.mm +++ b/ios/web/common/features.mm
@@ -23,9 +23,6 @@ const base::Feature kCrashOnUnexpectedURLChange{ "CrashOnUnexpectedURLChange", base::FEATURE_ENABLED_BY_DEFAULT}; -const base::Feature kDisconnectScrollProxyDuringRestore{ - "DisconnectScrollProxyDuringRestore", base::FEATURE_DISABLED_BY_DEFAULT}; - const base::Feature kHistoryClobberWorkaround{ "WKWebViewHistoryClobberWorkaround", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index d15ba18..e0886c3f 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -974,8 +974,7 @@ web::WKNavigationState::FINISHED) return; - // Restore allowsBackForwardNavigationGestures and the scroll proxy once - // restoration is complete. + // Restore allowsBackForwardNavigationGestures once restoration is complete. if (web::GetWebClient()->IsSlimNavigationManagerEnabled() && !self.navigationManagerImpl->IsRestoreSessionInProgress()) { if (_webView.allowsBackForwardNavigationGestures != @@ -983,11 +982,6 @@ _webView.allowsBackForwardNavigationGestures = _allowsBackForwardNavigationGestures; } - - if (base::FeatureList::IsEnabled( - web::features::kDisconnectScrollProxyDuringRestore)) { - [_containerView reconnectScrollProxy]; - } } BOOL success = !context || !context->GetError(); @@ -1660,13 +1654,6 @@ [[CRWWebViewContentView alloc] initWithWebView:self.webView scrollView:self.webScrollView]; [_containerView displayWebViewContentView:webViewContentView]; - - if (web::GetWebClient()->IsSlimNavigationManagerEnabled() && - self.navigationManagerImpl->IsRestoreSessionInProgress() && - base::FeatureList::IsEnabled( - web::features::kDisconnectScrollProxyDuringRestore)) { - [_containerView disconnectScrollProxy]; - } } - (void)removeWebView { @@ -2149,17 +2136,12 @@ [self loadCompleteWithSuccess:loadSuccess forContext:context]; } -- (void)webRequestControllerDisconnectScrollViewProxy: +- (void)webRequestControllerDisableNavigationGesturesUntilFinishNavigation: (CRWWebRequestController*)requestController { // Disable |allowsBackForwardNavigationGestures| during restore. Otherwise, // WebKit will trigger a snapshot for each (blank) page, and quickly - // overload system memory. Also disables the scroll proxy during session - // restoration. + // overload system memory. self.webView.allowsBackForwardNavigationGestures = NO; - if (base::FeatureList::IsEnabled( - web::features::kDisconnectScrollProxyDuringRestore)) { - [_containerView disconnectScrollProxy]; - } } - (web::UserInteractionState*)webRequestControllerUserInteractionState:
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.h b/ios/web/web_state/ui/crw_web_controller_container_view.h index e32a523..a2579996 100644 --- a/ios/web/web_state/ui/crw_web_controller_container_view.h +++ b/ios/web/web_state/ui/crw_web_controller_container_view.h
@@ -76,11 +76,6 @@ // Removes all subviews and resets state to default. - (void)resetContent; -// Disconnects and reconnects the scroll proxy to prevent extra calls to -// WKebView. -- (void)disconnectScrollProxy; -- (void)reconnectScrollProxy; - // Replaces the currently displayed content with |webViewContentView|. - (void)displayWebViewContentView:(CRWWebViewContentView*)webViewContentView;
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.mm b/ios/web/web_state/ui/crw_web_controller_container_view.mm index f6ead8f..61cb492 100644 --- a/ios/web/web_state/ui/crw_web_controller_container_view.mm +++ b/ios/web/web_state/ui/crw_web_controller_container_view.mm
@@ -219,14 +219,6 @@ self.contentViewProxy.contentView = self.webViewContentView; } -- (void)disconnectScrollProxy { - [self.contentViewProxy disconnectScrollProxy]; -} - -- (void)reconnectScrollProxy { - [self.contentViewProxy reconnectScrollProxy]; -} - #pragma mark UIView (printing) // Only print the web view by returning the web view printformatter.
diff --git a/ios/web/web_state/ui/crw_web_request_controller.h b/ios/web/web_state/ui/crw_web_request_controller.h index 8d09224..aa1a10b 100644 --- a/ios/web/web_state/ui/crw_web_request_controller.h +++ b/ios/web/web_state/ui/crw_web_request_controller.h
@@ -42,8 +42,11 @@ didCompleteLoadWithSuccess:(BOOL)loadSuccess forContext:(web::NavigationContextImpl*)context; -// Asks proxy to disconnect scroll proxy if needed. -- (void)webRequestControllerDisconnectScrollViewProxy: +// Asks proxy to disable back forward navigation gestures until the current (in +// this case restore) navigation is complete. This is necessary as restore +// can trigger a large number of navigations, and when back/forward is enabled +// this can lead to an unbounded memory spike. +- (void)webRequestControllerDisableNavigationGesturesUntilFinishNavigation: (CRWWebRequestController*)requestController; // Asks the delegate for the associated |UserInteractionState|.
diff --git a/ios/web/web_state/ui/crw_web_request_controller.mm b/ios/web/web_state/ui/crw_web_request_controller.mm index 682fbde7..d2ca2b8 100644 --- a/ios/web/web_state/ui/crw_web_request_controller.mm +++ b/ios/web/web_state/ui/crw_web_request_controller.mm
@@ -657,7 +657,9 @@ if (web::GetWebClient()->IsSlimNavigationManagerEnabled() && self.navigationManagerImpl->IsRestoreSessionInProgress()) { - [_delegate webRequestControllerDisconnectScrollViewProxy:self]; + [_delegate + webRequestControllerDisableNavigationGesturesUntilFinishNavigation: + self]; } WKNavigation* navigation = nil;
diff --git a/ios/web/web_state/ui/crw_web_view_proxy_impl.h b/ios/web/web_state/ui/crw_web_view_proxy_impl.h index 4dae7ee..fb4323a0 100644 --- a/ios/web/web_state/ui/crw_web_view_proxy_impl.h +++ b/ios/web/web_state/ui/crw_web_view_proxy_impl.h
@@ -23,11 +23,6 @@ // Init with a weak reference of web controller, used for passing through calls. - (instancetype)initWithWebController:(CRWWebController*)webController; -// Disconnects and reconnects the scroll proxy to prevent extra calls to -// WKebView. -- (void)disconnectScrollProxy; -- (void)reconnectScrollProxy; - @end #endif // IOS_WEB_WEB_STATE_UI_CRW_WEB_VIEW_PROXY_IMPL_H_
diff --git a/ios/web/web_state/ui/crw_web_view_proxy_impl.mm b/ios/web/web_state/ui/crw_web_view_proxy_impl.mm index 0d472985..5e55401 100644 --- a/ios/web/web_state/ui/crw_web_view_proxy_impl.mm +++ b/ios/web/web_state/ui/crw_web_view_proxy_impl.mm
@@ -170,14 +170,6 @@ [_contentViewScrollViewProxy setScrollView:contentView.scrollView]; } -- (void)disconnectScrollProxy { - [_contentViewScrollViewProxy setScrollView:nil]; -} - -- (void)reconnectScrollProxy { - [_contentViewScrollViewProxy setScrollView:self.contentView.scrollView]; -} - - (void)addSubview:(UIView*)view { return [_contentView addSubview:view]; }
diff --git a/media/gpu/android/shared_image_video.cc b/media/gpu/android/shared_image_video.cc index 2ac3775..4908964 100644 --- a/media/gpu/android/shared_image_video.cc +++ b/media/gpu/android/shared_image_video.cc
@@ -229,16 +229,7 @@ static_cast<GLenum>(GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM)); auto* video_backing = static_cast<SharedImageVideo*>(backing()); - DCHECK(video_backing); - auto* codec_image = video_backing->codec_image_.get(); - auto* texture_owner = codec_image->texture_owner().get(); - - // Render the codec image. - codec_image->RenderToFrontBuffer(); - - // Bind the tex image if it's not already bound. - if (!texture_owner->binds_texture_on_update()) - texture_owner->EnsureTexImageBound(); + video_backing->BeginGLReadAccess(); return true; } @@ -250,6 +241,43 @@ DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureVideo); }; +// Representation of SharedImageVideo as a GL Texture. +class SharedImageRepresentationGLTexturePassthroughVideo + : public gpu::SharedImageRepresentationGLTexturePassthrough { + public: + SharedImageRepresentationGLTexturePassthroughVideo( + gpu::SharedImageManager* manager, + SharedImageVideo* backing, + gpu::MemoryTypeTracker* tracker, + scoped_refptr<gpu::gles2::TexturePassthrough> texture) + : gpu::SharedImageRepresentationGLTexturePassthrough(manager, + backing, + tracker), + texture_(std::move(texture)) {} + + const scoped_refptr<gpu::gles2::TexturePassthrough>& GetTexturePassthrough() + override { + return texture_; + } + + bool BeginAccess(GLenum mode) override { + // This representation should only be called for read. + DCHECK_EQ(mode, + static_cast<GLenum>(GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM)); + + auto* video_backing = static_cast<SharedImageVideo*>(backing()); + video_backing->BeginGLReadAccess(); + return true; + } + + void EndAccess() override {} + + private: + scoped_refptr<gpu::gles2::TexturePassthrough> texture_; + + DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTexturePassthroughVideo); +}; + // Vulkan backed Skia representation of SharedImageVideo. class SharedImageRepresentationVideoSkiaVk : public gpu::SharedImageRepresentationSkia { @@ -427,6 +455,29 @@ manager, this, tracker, texture); } +// TODO(vikassoni): Currently GLRenderer doesn't support overlays with shared +// image. Add support for overlays in GLRenderer as well as overlay +// representations of shared image. +std::unique_ptr<gpu::SharedImageRepresentationGLTexturePassthrough> +SharedImageVideo::ProduceGLTexturePassthrough(gpu::SharedImageManager* manager, + gpu::MemoryTypeTracker* tracker) { + // For (old) overlays, we don't have a texture owner, but overlay promotion + // might not happen for some reasons. In that case, it will try to draw + // which should result in no image. + if (!codec_image_->texture_owner()) + return nullptr; + // TODO(vikassoni): We would want to give the TextureOwner's underlying + // Texture, but it was not set with the correct size. The AbstractTexture, + // that we use for legacy mailbox, is correctly set. + scoped_refptr<gpu::gles2::TexturePassthrough> texture = + gpu::gles2::TexturePassthrough::CheckedCast( + abstract_texture_->GetTextureBase()); + DCHECK(texture); + + return std::make_unique<SharedImageRepresentationGLTexturePassthroughVideo>( + manager, this, tracker, std::move(texture)); +} + // Currently SkiaRenderer doesn't support overlays. std::unique_ptr<gpu::SharedImageRepresentationSkia> SharedImageVideo::ProduceSkia( @@ -460,4 +511,14 @@ std::move(gl_representation), nullptr, manager, this, tracker); } +void SharedImageVideo::BeginGLReadAccess() { + // Render the codec image. + codec_image_->RenderToFrontBuffer(); + + // Bind the tex image if it's not already bound. + auto* texture_owner = codec_image_->texture_owner().get(); + if (!texture_owner->binds_texture_on_update()) + texture_owner->EnsureTexImageBound(); +} + } // namespace media
diff --git a/media/gpu/android/shared_image_video.h b/media/gpu/android/shared_image_video.h index 42407ed..cffd661 100644 --- a/media/gpu/android/shared_image_video.h +++ b/media/gpu/android/shared_image_video.h
@@ -64,6 +64,10 @@ gpu::SharedImageManager* manager, gpu::MemoryTypeTracker* tracker) override; + std::unique_ptr<gpu::SharedImageRepresentationGLTexturePassthrough> + ProduceGLTexturePassthrough(gpu::SharedImageManager* manager, + gpu::MemoryTypeTracker* tracker) override; + std::unique_ptr<gpu::SharedImageRepresentationSkia> ProduceSkia( gpu::SharedImageManager* manager, gpu::MemoryTypeTracker* tracker, @@ -74,9 +78,12 @@ private: friend class SharedImageRepresentationGLTextureVideo; + friend class SharedImageRepresentationGLTexturePassthroughVideo; friend class SharedImageRepresentationVideoSkiaGL; friend class SharedImageRepresentationVideoSkiaVk; + void BeginGLReadAccess(); + scoped_refptr<CodecImage> codec_image_; // |abstract_texture_| is only used for legacy mailbox.
diff --git a/media/gpu/linux/dmabuf_video_frame_pool.h b/media/gpu/linux/dmabuf_video_frame_pool.h index cf920376..3ff360e8 100644 --- a/media/gpu/linux/dmabuf_video_frame_pool.h +++ b/media/gpu/linux/dmabuf_video_frame_pool.h
@@ -6,6 +6,7 @@ #define MEDIA_GPU_LINUX_DMABUF_VIDEO_FRAME_POOL_H_ #include "base/memory/scoped_refptr.h" +#include "base/optional.h" #include "base/sequenced_task_runner.h" #include "media/base/video_frame.h" #include "media/base/video_frame_layout.h" @@ -35,11 +36,13 @@ // Used to prevent client from draining all memory. virtual void SetMaxNumFrames(size_t max_num_frames) = 0; - // Sets the parameters of allocating frames. + // Sets the parameters of allocating frames and returns a valid + // VideoFrameLayout that VideoFrame will be created by GetFrame() has. // This method must be called before GetFrame() is called. - virtual void SetFrameFormat(VideoFrameLayout layout, - gfx::Rect visible_rect, - gfx::Size natural_size) = 0; + virtual base::Optional<VideoFrameLayout> NegotiateFrameFormat( + const VideoFrameLayout& layout, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size) = 0; // Returns a frame from the pool with the parameters assigned by // SetFrameFormat(). Returns nullptr if the pool is exhausted.
diff --git a/media/gpu/linux/platform_video_frame_pool.cc b/media/gpu/linux/platform_video_frame_pool.cc index cc8b8a1..ddaacfb 100644 --- a/media/gpu/linux/platform_video_frame_pool.cc +++ b/media/gpu/linux/platform_video_frame_pool.cc
@@ -65,7 +65,6 @@ const base::TickClock* tick_clock) : create_frame_cb_(std::move(cb)), tick_clock_(tick_clock), - format_(PIXEL_FORMAT_UNKNOWN), max_num_frames_(kDefaultMaxNumFrames), weak_this_factory_(this) { DVLOGF(4); @@ -88,11 +87,13 @@ DVLOGF(4); base::AutoLock auto_lock(lock_); - if (coded_size_.IsEmpty()) { - VLOGF(1) << "Please call SetFrameFormat() first."; + if (!frame_layout_) { + VLOGF(1) << "Please call NegotiateFrameFormat() first."; return nullptr; } + VideoPixelFormat format = frame_layout_->format(); + const gfx::Size& coded_size = frame_layout_->coded_size(); if (free_frames_.empty()) { if (GetTotalNumFrames_Locked() >= max_num_frames_) return nullptr; @@ -101,8 +102,8 @@ // is sub rect of the original visible_rect. Therefore we set visible_rect // as large as coded_size to guarantee this condition. scoped_refptr<VideoFrame> new_frame = - create_frame_cb_.Run(format_, coded_size_, gfx::Rect(coded_size_), - coded_size_, base::TimeDelta()); + create_frame_cb_.Run(format, coded_size, gfx::Rect(coded_size), + coded_size, base::TimeDelta()); if (!new_frame) return nullptr; @@ -112,11 +113,11 @@ DCHECK(!free_frames_.empty()); scoped_refptr<VideoFrame> origin_frame = std::move(free_frames_.back().frame); free_frames_.pop_back(); - DCHECK_EQ(origin_frame->format(), format_); - DCHECK_EQ(origin_frame->coded_size(), coded_size_); + DCHECK_EQ(origin_frame->format(), format); + DCHECK_EQ(origin_frame->coded_size(), coded_size); scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame( - *origin_frame, format_, visible_rect_, natural_size_); + *origin_frame, format, visible_rect_, natural_size_); DCHECK(wrapped_frame); frames_in_use_.emplace(GetDmabufId(*wrapped_frame), origin_frame.get()); wrapped_frame->AddDestructionObserver( @@ -167,9 +168,10 @@ std::move(frame_available_cb_).Run(); } -void PlatformVideoFramePool::SetFrameFormat(VideoFrameLayout layout, - gfx::Rect visible_rect, - gfx::Size natural_size) { +base::Optional<VideoFrameLayout> PlatformVideoFramePool::NegotiateFrameFormat( + const VideoFrameLayout& layout, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size) { DVLOGF(4); base::AutoLock auto_lock(lock_); @@ -177,17 +179,27 @@ // the pool here. If only the visible or natural size changed we don't need to // allocate new frames, but will just update the properties of wrapped frames // returned by GetFrame(). - if (!IsSameLayout_Locked(layout.format(), layout.coded_size())) { + // NOTE: It is assumed layout is determined by |format| and |coded_size|. + if (!IsSameLayout_Locked(layout)) { DVLOGF(4) << "The video frame format is changed. Clearing the pool."; free_frames_.clear(); } - format_ = layout.format(); - coded_size_ = layout.coded_size(); visible_rect_ = visible_rect; natural_size_ = natural_size; - DCHECK_LE(visible_rect_.right(), coded_size_.width()); - DCHECK_LE(visible_rect_.bottom(), coded_size_.height()); + + // Create a temporary frame in order to know VideoFrameLayout that VideoFrame + // that will be allocated in GetFrame() has. + auto frame = + create_frame_cb_.Run(layout.format(), layout.coded_size(), visible_rect, + natural_size_, base::TimeDelta()); + if (!frame) { + VLOGF(1) << "Failed to create video frame"; + return base::nullopt; + } + frame_layout_ = base::make_optional<VideoFrameLayout>(frame->layout()); + + return frame_layout_; } bool PlatformVideoFramePool::IsExhausted() { @@ -249,7 +261,7 @@ DCHECK(it != frames_in_use_.end()); frames_in_use_.erase(it); - if (IsSameLayout_Locked(origin_frame->format(), origin_frame->coded_size())) { + if (IsSameLayout_Locked(origin_frame->layout())) { InsertFreeFrame_Locked(std::move(origin_frame)); } @@ -274,12 +286,13 @@ return free_frames_.size() + frames_in_use_.size(); } -bool PlatformVideoFramePool::IsSameLayout_Locked(VideoPixelFormat format, - gfx::Size coded_size) const { +bool PlatformVideoFramePool::IsSameLayout_Locked( + const VideoFrameLayout& layout) const { DVLOGF(4); lock_.AssertAcquired(); - return format_ == format && coded_size_ == coded_size; + return frame_layout_ && frame_layout_->format() == layout.format() && + frame_layout_->coded_size() == layout.coded_size(); } size_t PlatformVideoFramePool::GetPoolSizeForTesting() {
diff --git a/media/gpu/linux/platform_video_frame_pool.h b/media/gpu/linux/platform_video_frame_pool.h index be8e03a..47df14dc 100644 --- a/media/gpu/linux/platform_video_frame_pool.h +++ b/media/gpu/linux/platform_video_frame_pool.h
@@ -17,6 +17,7 @@ #include "base/synchronization/lock.h" #include "base/thread_annotations.h" #include "media/base/video_frame.h" +#include "media/base/video_frame_layout.h" #include "media/gpu/linux/dmabuf_video_frame_pool.h" #include "media/gpu/media_gpu_export.h" @@ -32,10 +33,10 @@ // the memory is returned to the pool for use by a subsequent GetFrame() // call. The memory in the pool is retained for the life of the // PlatformVideoFramePool object. Before calling GetFrame(), the client should -// call SetFrameFormat(). If the parameters passed to SetFrameFormat() are -// changed, then the memory used by frames with the old parameter values will be -// purged from the pool. Frames which are not used for a certain period -// will be purged. +// call NegotiateFrameFormat(). If the parameters passed to +// NegotiateFrameFormat() are changed, then the memory used by frames with the +// old parameter values will be purged from the pool. Frames which are not used +// for a certain period will be purged. class MEDIA_GPU_EXPORT PlatformVideoFramePool : public DmabufVideoFramePool { public: using DmabufId = const std::vector<base::ScopedFD>*; @@ -47,9 +48,10 @@ void set_parent_task_runner( scoped_refptr<base::SequencedTaskRunner> parent_task_runner) override; void SetMaxNumFrames(size_t max_num_frames) override; - void SetFrameFormat(VideoFrameLayout layout, - gfx::Rect visible_rect, - gfx::Size natural_size) override; + base::Optional<VideoFrameLayout> NegotiateFrameFormat( + const VideoFrameLayout& layout, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size) override; scoped_refptr<VideoFrame> GetFrame() override; bool IsExhausted() override; VideoFrame* UnwrapFrame(const VideoFrame& wrapped_frame) override; @@ -92,7 +94,7 @@ void InsertFreeFrame_Locked(scoped_refptr<VideoFrame> frame) EXCLUSIVE_LOCKS_REQUIRED(lock_); size_t GetTotalNumFrames_Locked() const EXCLUSIVE_LOCKS_REQUIRED(lock_); - bool IsSameLayout_Locked(VideoPixelFormat format, gfx::Size coded_size) const + bool IsSameLayout_Locked(const VideoFrameLayout& layout) const EXCLUSIVE_LOCKS_REQUIRED(lock_); bool IsExhausted_Locked() EXCLUSIVE_LOCKS_REQUIRED(lock_); @@ -110,11 +112,10 @@ // Every public method and OnFrameReleased() should acquire this lock. base::Lock lock_; - // The arguments of current frame. We allocate new frames only with |format_| - // and |coded_size_|. When calling GetFrame(), we update |visible_rect_| and - // |natural_size_| of wrapped frames. - VideoPixelFormat format_ GUARDED_BY(lock_); - gfx::Size coded_size_ GUARDED_BY(lock_); + // The arguments of current frame. We allocate new frames only if a pixel + // format or coded size in |frame_layout_| is changed. When GetFrame() is + // called, we update |visible_rect_| and |natural_size_| of wrapped frames. + base::Optional<VideoFrameLayout> frame_layout_ GUARDED_BY(lock_); gfx::Rect visible_rect_ GUARDED_BY(lock_); gfx::Size natural_size_ GUARDED_BY(lock_);
diff --git a/media/gpu/linux/platform_video_frame_pool_unittest.cc b/media/gpu/linux/platform_video_frame_pool_unittest.cc index aa223ff..f01b489 100644 --- a/media/gpu/linux/platform_video_frame_pool_unittest.cc +++ b/media/gpu/linux/platform_video_frame_pool_unittest.cc
@@ -68,7 +68,7 @@ layout_ = VideoFrameLayout::Create(format, coded_size); DCHECK(layout_); - pool_->SetFrameFormat(*layout_, visible_rect_, natural_size_); + pool_->NegotiateFrameFormat(*layout_, visible_rect_, natural_size_); } scoped_refptr<VideoFrame> GetFrame(int timestamp_ms) {
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.cc b/media/gpu/v4l2/v4l2_slice_video_decoder.cc index aada606c..57048f19 100644 --- a/media/gpu/v4l2/v4l2_slice_video_decoder.cc +++ b/media/gpu/v4l2/v4l2_slice_video_decoder.cc
@@ -339,7 +339,9 @@ base::BindOnce(std::move(init_cb), false)); return; } + needs_bitstream_conversion_ = (config.codec() == kCodecH264); + pixel_aspect_ratio_ = config.GetPixelAspectRatio(); // Setup input format. if (!SetupInputFormat(input_format_fourcc)) { @@ -350,29 +352,13 @@ } // Setup output format. - uint32_t output_format_fourcc = NegotiateOutputFormat(); - num_output_planes_ = - V4L2Device::GetNumPlanesOfV4L2PixFmt(output_format_fourcc); - if (!SetupOutputFormat(output_format_fourcc)) { + if (!SetupOutputFormat(config.coded_size(), config.visible_rect())) { VLOGF(1) << "Failed to setup output format."; client_task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(init_cb), false)); return; } - // Setup frame pool. - VideoPixelFormat output_format = - V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc); - frame_layout_ = VideoFrameLayout::Create(output_format, config.coded_size()); - if (!frame_layout_) { - VLOGF(1) << "Failed to create video frame layout."; - client_task_runner_->PostTask(FROM_HERE, - base::BindOnce(std::move(init_cb), false)); - return; - } - pixel_aspect_ratio_ = config.GetPixelAspectRatio(); - UpdateVideoFramePoolFormat(config.visible_rect()); - // Create Input/Output V4L2Queue input_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); output_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); @@ -433,48 +419,81 @@ return true; } -uint32_t V4L2SliceVideoDecoder::NegotiateOutputFormat() { +base::Optional<struct v4l2_format> +V4L2SliceVideoDecoder::SetFormatOnOutputQueue(uint32_t format_fourcc, + const gfx::Size& size) { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); + + struct v4l2_format format = {}; + format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + format.fmt.pix_mp.pixelformat = format_fourcc; + format.fmt.pix_mp.width = size.width(); + format.fmt.pix_mp.height = size.height(); + format.fmt.pix_mp.num_planes = + V4L2Device::GetNumPlanesOfV4L2PixFmt(format_fourcc); + if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0 || + format.fmt.pix_mp.pixelformat != format_fourcc) { + VPLOGF(2) << "Failed to set output format. format_fourcc=" << format_fourcc; + return base::nullopt; + } + return format; +} + +base::Optional<VideoFrameLayout> V4L2SliceVideoDecoder::SetupOutputFormat( + const gfx::Size& size, + const gfx::Rect& visible_rect) { DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); const std::vector<uint32_t> formats = device_->EnumerateSupportedPixelformats( V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); DCHECK(!formats.empty()); - for (const auto format : formats) { - if (device_->CanCreateEGLImageFrom(format)) { - return format; + for (const auto format_fourcc : formats) { + if (!device_->CanCreateEGLImageFrom(format_fourcc)) + continue; + + // Make sure VFPool can allocate video frames with width and height. + auto frame_layout = + UpdateVideoFramePoolFormat(format_fourcc, size, visible_rect); + if (!frame_layout) { + continue; + } + + // Next S_FMT with the size adjusted by VFPool. + gfx::Size adjusted_size(frame_layout->planes()[0].stride, + frame_layout->coded_size().height()); + base::Optional<struct v4l2_format> format = + SetFormatOnOutputQueue(format_fourcc, adjusted_size); + if (!format) { + num_output_planes_ = format->fmt.pix_mp.num_planes; + return frame_layout; } } // TODO(akahuang): Use ImageProcessor in this case. VLOGF(2) << "WARNING: Cannot find format that can create EGL image. " << "We need ImageProcessor to convert pixel format."; - return formats[0]; + NOTIMPLEMENTED(); + return base::nullopt; } -bool V4L2SliceVideoDecoder::SetupOutputFormat(uint32_t output_format_fourcc) { - DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); - DVLOGF(3) << "output_format_fourcc = " << output_format_fourcc; - - // Only set fourcc for output; resolution, etc., will come from the - // driver once surface_it extracts surface_it from the stream. - struct v4l2_format format; - memset(&format, 0, sizeof(format)); - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - format.fmt.pix_mp.pixelformat = output_format_fourcc; - format.fmt.pix_mp.num_planes = num_output_planes_; - if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0) { - VPLOGF(1) << "Failed to call IOCTL to set output format."; - return false; - } - DCHECK_EQ(format.fmt.pix_mp.pixelformat, output_format_fourcc); - - return true; -} - -void V4L2SliceVideoDecoder::UpdateVideoFramePoolFormat( +base::Optional<VideoFrameLayout> +V4L2SliceVideoDecoder::UpdateVideoFramePoolFormat( + uint32_t output_format_fourcc, + const gfx::Size& size, const gfx::Rect& visible_rect) { + VideoPixelFormat output_format = + V4L2Device::V4L2PixFmtToVideoPixelFormat(output_format_fourcc); + if (output_format == PIXEL_FORMAT_UNKNOWN) { + return base::nullopt; + } + auto layout = VideoFrameLayout::Create(output_format, size); + if (!layout) { + VLOGF(1) << "Failed to create video frame layout."; + return base::nullopt; + } + gfx::Size natural_size = GetNaturalSize(visible_rect, pixel_aspect_ratio_); - frame_pool_->SetFrameFormat(*frame_layout_, visible_rect, natural_size); + return frame_pool_->NegotiateFrameFormat(*layout, visible_rect, natural_size); } void V4L2SliceVideoDecoder::Reset(base::OnceClosure closure) { @@ -705,38 +724,24 @@ if (!StopStreamV4L2Queue()) return false; - // Set the new resolution. + // Set output format with the new resolution. gfx::Size pic_size = avd_->GetPicSize(); DCHECK(!pic_size.IsEmpty()); DVLOGF(3) << "Change resolution to " << pic_size.width() << "x" << pic_size.height(); - struct v4l2_format format; - memset(&format, 0, sizeof(format)); - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - if (device_->Ioctl(VIDIOC_G_FMT, &format) != 0) { - VLOGF(1) << "Failed getting output format."; - return false; - } - format.fmt.pix_mp.width = pic_size.width(); - format.fmt.pix_mp.height = pic_size.height(); - if (device_->Ioctl(VIDIOC_S_FMT, &format) != 0) { - VLOGF(1) << "Failed setting resolution."; + auto frame_layout = SetupOutputFormat(pic_size, avd_->GetVisibleRect()); + if (!frame_layout) { + VLOGF(1) << "No format is available with thew new resolution"; return false; } - // Update frame layout. - gfx::Size coded_size(base::checked_cast<int>(format.fmt.pix_mp.width), - base::checked_cast<int>(format.fmt.pix_mp.height)); + auto coded_size = frame_layout->coded_size(); DCHECK_EQ(coded_size.width() % 16, 0); DCHECK_EQ(coded_size.height() % 16, 0); if (!gfx::Rect(coded_size).Contains(gfx::Rect(pic_size))) { VLOGF(1) << "Got invalid adjusted coded size: " << coded_size.ToString(); return false; } - frame_layout_ = VideoFrameLayout::Create(frame_layout_->format(), coded_size); - DCHECK(frame_layout_); - - UpdateVideoFramePoolFormat(avd_->GetVisibleRect()); // Allocate new output buffers. if (!output_queue_->DeallocateBuffers())
diff --git a/media/gpu/v4l2/v4l2_slice_video_decoder.h b/media/gpu/v4l2/v4l2_slice_video_decoder.h index 571d0c6..a552e4b1 100644 --- a/media/gpu/v4l2/v4l2_slice_video_decoder.h +++ b/media/gpu/v4l2/v4l2_slice_video_decoder.h
@@ -5,6 +5,8 @@ #ifndef MEDIA_GPU_V4L2_V4L2_SLICE_VIDEO_DECODER_H_ #define MEDIA_GPU_V4L2_V4L2_SLICE_VIDEO_DECODER_H_ +#include <linux/videodev2.h> + #include <map> #include <memory> #include <string> @@ -135,15 +137,30 @@ void InitializeTask(const VideoDecoderConfig& config, InitCB init_cb, const OutputCB& output_cb); - // Setup format for V4L2 input buffers. + // Setup format for input queue. bool SetupInputFormat(uint32_t input_format_fourcc); - // Negotiate the pixel output format with V4L2 device. Return fourcc of the - // pixel format that is supported by V4L2 device. - uint32_t NegotiateOutputFormat(); - // Setup format for V4L2 output buffers. - bool SetupOutputFormat(uint32_t output_format_fourcc); - // Update the format of frames in |frame_pool_|. - void UpdateVideoFramePoolFormat(const gfx::Rect& visible_rect); + + // Call VIDIOC_S_FMT with |format_fourcc| and |size|. Returns v4l2_format + // returned by VIDIOC_S_FMT on success, otherwise returns base::nullopt. + // This should be called only from SetupOutputFormat(). + base::Optional<struct v4l2_format> SetFormatOnOutputQueue( + uint32_t format_fourcc, + const gfx::Size& size); + // Setup format for output queue. This function sets output format on output + // queue that is supported by a v4l2 driver, can be allocatable by + // VideoFramePool and can be composited by chrome. This also updates format + // in VideoFramePool. The returned VideoFrameLayout is one of VideoFrame that + // VideoFramePool will allocate. Returns base::nullopt on failure of if there + // is no format that satisfies the above conditions. + base::Optional<VideoFrameLayout> SetupOutputFormat( + const gfx::Size& size, + const gfx::Rect& visible_rect); + // Update the format of frames in |frame_pool_| with |output_format_fourcc|, + // |size| and |visible_rect|. + base::Optional<VideoFrameLayout> UpdateVideoFramePoolFormat( + uint32_t output_format_fourcc, + const gfx::Size& size, + const gfx::Rect& visible_rect); // Destroy on decoder thread. void DestroyTask();
diff --git a/media/gpu/v4l2/v4l2_vp8_accelerator.cc b/media/gpu/v4l2/v4l2_vp8_accelerator.cc index 90a4a38d..4cf4b3e 100644 --- a/media/gpu/v4l2/v4l2_vp8_accelerator.cc +++ b/media/gpu/v4l2/v4l2_vp8_accelerator.cc
@@ -217,7 +217,7 @@ memset(&ctrl, 0, sizeof(ctrl)); ctrl.id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HDR; ctrl.size = sizeof(v4l2_frame_hdr); - ctrl.p_vp8_frame_hdr = &v4l2_frame_hdr; + ctrl.ptr = &v4l2_frame_hdr; struct v4l2_ext_controls ext_ctrls; memset(&ext_ctrls, 0, sizeof(ext_ctrls));
diff --git a/media/gpu/vaapi/vaapi_video_decoder.cc b/media/gpu/vaapi/vaapi_video_decoder.cc index 5364cd3..55ec03e7 100644 --- a/media/gpu/vaapi/vaapi_video_decoder.cc +++ b/media/gpu/vaapi/vaapi_video_decoder.cc
@@ -468,7 +468,8 @@ if (visible_rect_ != visible_rect) { visible_rect_ = visible_rect; gfx::Size natural_size = GetNaturalSize(visible_rect_, pixel_aspect_ratio_); - frame_pool_->SetFrameFormat(*frame_layout_, visible_rect_, natural_size); + frame_pool_->NegotiateFrameFormat(*frame_layout_, visible_rect_, + natural_size); } auto it = buffer_id_to_timestamp_.find(buffer_id); @@ -527,7 +528,8 @@ GfxBufferFormatToVideoPixelFormat(GetBufferFormat()); frame_layout_ = VideoFrameLayout::Create(format, pic_size); DCHECK(frame_layout_); - frame_pool_->SetFrameFormat(*frame_layout_, visible_rect_, natural_size); + frame_pool_->NegotiateFrameFormat(*frame_layout_, visible_rect_, + natural_size); frame_pool_->SetMaxNumFrames(decoder_->GetRequiredNumOfPictures()); // All pending decode operations will be completed before triggering a
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc index 67ba27c..4d6c534c 100644 --- a/media/gpu/video_encode_accelerator_unittest.cc +++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -112,10 +112,6 @@ const double kDefaultSubsequentFramerateRatio = 0.1; // Tolerance factor for how encoded bitrate can differ from requested bitrate. const double kBitrateTolerance = 0.1; -// Minimum required FPS throughput for the basic performance test. -const uint32_t kMinPerfFPS = 30; -// The frame size for 2160p (UHD 4K) video in pixels. -const int k2160PSizeInPixels = 3840 * 2160; // Minimum (arbitrary) number of frames required to enforce bitrate requirements // over. Streams shorter than this may be too short to realistically require // an encoder to be able to converge to the requested bitrate over. @@ -1523,7 +1519,6 @@ bool save_to_file, unsigned int keyframe_period, bool force_bitrate, - bool test_perf, bool mid_stream_bitrate_switch, bool mid_stream_framerate_switch, bool verify_output, @@ -1577,9 +1572,6 @@ // short period. void FlushTimeout(); - // Verify the minimum FPS requirement. - void VerifyMinFPS(); - // Verify that stream bitrate has been close to current_requested_bitrate_, // assuming current_framerate_ since the last time VerifyStreamProperties() // was called. Fail the test if |force_bitrate_| is true and the bitrate @@ -1683,9 +1675,6 @@ // time we checked bitrate. size_t encoded_stream_size_since_last_check_; - // If true, verify performance at the end of the test. - bool test_perf_; - // Check the output frame quality of the encoder. bool verify_output_; @@ -1734,7 +1723,6 @@ bool save_to_file, unsigned int keyframe_period, bool force_bitrate, - bool test_perf, bool mid_stream_bitrate_switch, bool mid_stream_framerate_switch, bool verify_output, @@ -1757,7 +1745,6 @@ current_requested_bitrate_(0), current_framerate_(0), encoded_stream_size_since_last_check_(0), - test_perf_(test_perf), verify_output_(verify_output), verify_output_timestamp_(verify_output_timestamp), requested_bitrate_(0), @@ -2291,7 +2278,6 @@ } } else if (num_encoded_frames_ == num_frames_to_encode_) { LogPerf(); - VerifyMinFPS(); VerifyStreamProperties(); // We might receive the last frame before calling Flush(). In this case we // set the state to CS_FLUSHING first to bypass the state transition check. @@ -2382,23 +2368,6 @@ SetState(CS_ERROR); } -void VEAClient::VerifyMinFPS() { - DCHECK(thread_checker_.CalledOnValidThread()); - if (test_perf_) { - if (input_coded_size_.GetArea() >= k2160PSizeInPixels) { - // When |input_coded_size_| is 2160p or more, it is expected that the - // calculated FPS might be lower than kMinPerfFPS. Log as warning instead - // of failing the test in this case. - if (frames_per_second() < kMinPerfFPS) { - LOG(WARNING) << "Measured FPS: " << frames_per_second() - << " is below min required: " << kMinPerfFPS << " FPS."; - } - } else { - EXPECT_GE(frames_per_second(), kMinPerfFPS); - } - } -} - void VEAClient::VerifyStreamProperties() { DCHECK(thread_checker_.CalledOnValidThread()); LOG_ASSERT(num_frames_since_last_check_ > 0UL); @@ -2707,7 +2676,6 @@ // - Force a keyframe every n frames. // - Force bitrate; the actual required value is provided as a property // of the input stream, because it depends on stream type/resolution/etc. -// - If true, measure performance. // - If true, switch bitrate mid-stream. // - If true, switch framerate mid-stream. // - If true, verify the output frames of encoder. @@ -2716,22 +2684,19 @@ // available for H264 encoder for now. class VideoEncodeAcceleratorTest : public ::testing::TestWithParam< - std:: - tuple<int, bool, int, bool, bool, bool, bool, bool, bool, bool>> { -}; + std::tuple<int, bool, int, bool, bool, bool, bool, bool, bool>> {}; TEST_P(VideoEncodeAcceleratorTest, TestSimpleEncode) { size_t num_concurrent_encoders = std::get<0>(GetParam()); const bool save_to_file = std::get<1>(GetParam()); const unsigned int keyframe_period = std::get<2>(GetParam()); const bool force_bitrate = std::get<3>(GetParam()); - const bool test_perf = std::get<4>(GetParam()); - const bool mid_stream_bitrate_switch = std::get<5>(GetParam()); - const bool mid_stream_framerate_switch = std::get<6>(GetParam()); + const bool mid_stream_bitrate_switch = std::get<4>(GetParam()); + const bool mid_stream_framerate_switch = std::get<5>(GetParam()); const bool verify_output = - std::get<7>(GetParam()) || g_env->verify_all_output(); - const bool verify_output_timestamp = std::get<8>(GetParam()); - const bool force_level = std::get<9>(GetParam()); + std::get<6>(GetParam()) || g_env->verify_all_output(); + const bool verify_output_timestamp = std::get<7>(GetParam()); + const bool force_level = std::get<8>(GetParam()); #if defined(OS_CHROMEOS) if (ShouldSkipTest()) @@ -2783,7 +2748,7 @@ std::make_unique<media::test::ClientStateNotification<ClientState>>()); clients.push_back(std::make_unique<VEAClient>( g_env->test_streams_[test_stream_index].get(), notes.back().get(), - encoder_save_to_file, keyframe_period, force_bitrate, test_perf, + encoder_save_to_file, keyframe_period, force_bitrate, mid_stream_bitrate_switch, mid_stream_framerate_switch, verify_output, verify_output_timestamp, force_level)); @@ -2888,7 +2853,6 @@ false, false, false, - false, false))); INSTANTIATE_TEST_SUITE_P(EncoderPerf, @@ -2897,7 +2861,6 @@ false, 0, false, - true, false, false, false, @@ -2914,7 +2877,6 @@ false, false, false, - false, false))); INSTANTIATE_TEST_SUITE_P(ForceBitrate, @@ -2927,7 +2889,6 @@ false, false, false, - false, false))); INSTANTIATE_TEST_SUITE_P(MidStreamParamSwitchBitrate, @@ -2936,7 +2897,6 @@ false, 0, true, - false, true, false, false, @@ -2951,7 +2911,6 @@ 0, true, false, - false, true, false, false, @@ -2967,13 +2926,11 @@ false, false, false, - false, false), std::make_tuple(3, false, 0, true, - false, true, false, false, @@ -2989,7 +2946,6 @@ false, false, false, - false, true, false))); @@ -3003,7 +2959,6 @@ false, false, false, - false, true))); INSTANTIATE_TEST_SUITE_P(NoInputTest, @@ -3025,7 +2980,6 @@ false, false, false, - false, false), std::make_tuple(1, true, @@ -3033,7 +2987,6 @@ false, false, false, - false, true, false, false))); @@ -3044,7 +2997,6 @@ false, 0, false, - true, false, false, false, @@ -3061,7 +3013,6 @@ false, false, false, - false, false))); INSTANTIATE_TEST_SUITE_P(VerifyTimestamp, @@ -3073,7 +3024,6 @@ false, false, false, - false, true, false))); @@ -3088,7 +3038,6 @@ false, false, false, - false, false))); #endif // defined(OS_WIN)
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc index 4d39c9ae..2d470bae 100644 --- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc +++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -58,6 +58,7 @@ #include "third_party/angle/include/EGL/eglext.h" #include "ui/display/display_switches.h" #include "ui/gfx/color_space_win.h" +#include "ui/gl/direct_composition_surface_win.h" #include "ui/gl/gl_angle_util_win.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" @@ -1558,9 +1559,8 @@ RETURN_ON_HR_FAILURE(hr, "Failed to get stream attributes", false); out_attributes->SetUINT32(MF_SA_D3D11_BINDFLAGS, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DECODER); - // TODO(sunnyps): Find if we can always set resource sharing to disabled. - if (base::FeatureList::IsEnabled( - features::kDirectCompositionUseNV12DecodeSwapChain)) { + // TODO(sunnyps): Find if we can always set resource sharing to disabled + if (gl::DirectCompositionSurfaceWin::IsDecodeSwapChainSupported()) { // Decode swap chains do not support shared resources. out_attributes->SetUINT32(MF_SA_D3D11_SHARED, FALSE); } else {
diff --git a/media/test/data/eme_player.html b/media/test/data/eme_player.html index fb7fe54c..929e71a 100644 --- a/media/test/data/eme_player.html +++ b/media/test/data/eme_player.html
@@ -59,13 +59,39 @@ var player; var heartbeatCount = 0; + function getTimeRanges(range) { + const result = []; + for (let i = 0; i < range.length; i++) { + result.push(`[${range.start(i)},${range.end(i)}]`); + } + return '[' + result.join(', ') + ']'; + } + + function getVideoStatus(video) { + if (video == null) { + return 'null'; + } + const result = []; + result.push(`paused: ${video.paused}`); + result.push(`ended: ${video.ended}`); + result.push(`currentTime: ${video.currentTime}`); + result.push(`duration: ${video.duration}`); + result.push(`buffered: ${getTimeRanges(video.buffered)}`); + result.push(`played: ${getTimeRanges(video.played)}`); + if (video.error) { + result.push(`error: {${video.error.code},${video.error.message}}`); + } + return result.join(', '); + } + function initApp() { testConfig = new TestConfig(); testConfig.loadQueryParams(); // Update document with test configuration values. emeApp = new EMEApp(testConfig); setInterval(function () { - Utils.timeLog('heartbeat #' + ++heartbeatCount); + Utils.timeLog('heartbeat #' + ++heartbeatCount + + ' video: ' + getVideoStatus(player.video)); }, 1000); } @@ -117,13 +143,12 @@ if (playTwice) { // Wait for the first play to complete. video.addEventListener('ended', onFirstPlayEnded); - video.play(); - return; + return video.play(); } // Ended should not fire before onTimeUpdate. video.addEventListener('ended', Utils.failTest); video.addEventListener('timeupdate', onTimeUpdate); - video.play(); + return video.play(); } function toggleDisplay(id) { @@ -143,7 +168,7 @@ emeApp.createPlayer() .then(function(p) { player = p; - play(player.video, testConfig.playTwice); + return play(player.video, testConfig.playTwice); }).catch(function(error) { Utils.timeLog(error); Utils.failTest('Unable to play video.');
diff --git a/media/test/data/eme_player_js/player_utils.js b/media/test/data/eme_player_js/player_utils.js index bec9b91..5e2afa2 100644 --- a/media/test/data/eme_player_js/player_utils.js +++ b/media/test/data/eme_player_js/player_utils.js
@@ -62,6 +62,15 @@ } player.onMessage(message); }); + mediaKeySession.addEventListener('keystatuseschange', function(e) { + const result = []; + for (let item of mediaKeySession.keyStatuses) { + result.push(`{kid:${ + Utils.base64urlEncode( + Utils.convertToUint8Array(item[0]))},status:${item[1]}}`); + } + Utils.timeLog('KeyStatusesChange: ' + result.join(',')); + }); } // Calls getStatusForPolicy() and returns a resolved promise if the result
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc index c1b8d1a..ee2d5721 100644 --- a/net/dns/dns_config_service_posix.cc +++ b/net/dns/dns_config_service_posix.cc
@@ -422,14 +422,6 @@ hosts_reader_->WorkNow(); } -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) -bool DnsConfigServicePosix::StartWatching() { - CreateReaders(); - // DNS config changes are handled and notified by the network - // state handlers. - return true; -} -#else // defined(OS_ANDROID) || defined(OS_CHROMEOS) bool DnsConfigServicePosix::StartWatching() { CreateReaders(); // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139 @@ -438,7 +430,6 @@ DNS_CONFIG_WATCH_MAX); return watcher_->Watch(); } -#endif // defined(OS_ANDROID) || defined(OS_CHROMEOS) void DnsConfigServicePosix::OnConfigChanged(bool succeeded) { InvalidateConfig();
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn index 0f71a13..c3ab224 100644 --- a/remoting/host/BUILD.gn +++ b/remoting/host/BUILD.gn
@@ -305,6 +305,7 @@ deps = [ "//base:i18n", + "//build:branding_buildflags", "//components/policy/core/common", "//crypto", "//google_apis",
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc index 565e088..428da182 100644 --- a/remoting/host/client_session.cc +++ b/remoting/host/client_session.cc
@@ -586,6 +586,17 @@ void ClientSession::OnDesktopDisplayChanged( std::unique_ptr<protocol::VideoLayout> displays) { LOG(INFO) << "ClientSession::OnDesktopDisplayChanged"; + +#if defined(OS_MACOSX) + // Don't send pixel based TrackLayout info to the client. There are several + // bugs related to cursor position and desktop selection (for multi-mon) which + // prevent the user from interacting with their machine. For now, we return + // early which will provide the same experience as the Chrome app used to and + // the iOS and Android apps currently do. + // TODO(crbug.com/987513): Investigate to figure out why the cursor offset and + // display selection issues are occurring and then re-enable this for MacOS. + return; +#else // Scan display list to calculate the full desktop size. int min_x = 0; int max_x = 0; @@ -676,6 +687,7 @@ } connection_->client_stub()->SetVideoLayout(layout); +#endif // defined(OS_MACOSX) } void ClientSession::CreateFileTransferMessageHandler(
diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc index c813625..2cfa4c16 100644 --- a/remoting/host/client_session_unittest.cc +++ b/remoting/host/client_session_unittest.cc
@@ -48,6 +48,15 @@ #define MAYBE_RestoreEventState DISABLED_RestoreEventState #define MAYBE_MultiMonMouseMove DISABLED_MultiMonMouseMove #define MAYBE_DisconnectOnLocalInputTest DISABLED_DisconnectOnLocalInputTest +#elif OS_MACOSX +// TODO(crbug.com/987513): Reenable tests for MacOS. +#define MAYBE_MultiMonMouseMove_SameSize DISABLED_MultiMonMouseMove_SameSize +#define MAYBE_MultiMonMouseMove DISABLED_MultiMonMouseMove +#define MAYBE_ClampMouseEvents DISABLED_ClampMouseEvents +#define MAYBE_DisableInputs DISABLED_DisableInputs +#define MAYBE_DisconnectOnLocalInputTest DISABLED_DisconnectOnLocalInputTest +#define MAYBE_LocalInputTest DISABLED_LocalInputTest +#define MAYBE_RestoreEventState DISABLED_RestoreEventState #else #define MAYBE_LocalInputTest LocalInputTest #define MAYBE_ClampMouseEvents ClampMouseEvents
diff --git a/remoting/host/host_attributes.cc b/remoting/host/host_attributes.cc index 985c423..4922af35 100644 --- a/remoting/host/host_attributes.cc +++ b/remoting/host/host_attributes.cc
@@ -13,6 +13,7 @@ #include "base/stl_util.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" +#include "build/branding_buildflags.h" #include "build/build_config.h" #if defined(OS_WIN) @@ -45,7 +46,7 @@ inline constexpr bool IsChromeBranded() { #if defined(GOOGLE_CHROME_BUILD) return true; -#elif defined(CHROMIUM_BUILD) +#elif BUILDFLAG(CHROMIUM_BRANDING) return false; #else #error Only Chrome and Chromium brands are supported.
diff --git a/services/media_session/media_controller.cc b/services/media_session/media_controller.cc index 6f8b54a6..80160c51 100644 --- a/services/media_session/media_controller.cc +++ b/services/media_session/media_controller.cc
@@ -147,6 +147,7 @@ media_controller_observer->MediaSessionInfoChanged(session_info_.Clone()); media_controller_observer->MediaSessionMetadataChanged(session_metadata_); media_controller_observer->MediaSessionActionsChanged(session_actions_); + media_controller_observer->MediaSessionPositionChanged(session_position_); observers_.Add(std::move(media_controller_observer)); } @@ -180,6 +181,16 @@ session_actions_ = actions; } +void MediaController::MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + for (auto& observer : observers_) + observer->MediaSessionPositionChanged(position); + + session_position_ = position; +} + void MediaController::MediaSessionImagesChanged( const base::flat_map<mojom::MediaSessionImageType, std::vector<MediaImage>>& images) { @@ -295,6 +306,7 @@ observer->MediaSessionMetadataChanged(base::nullopt); observer->MediaSessionActionsChanged( std::vector<mojom::MediaSessionAction>()); + observer->MediaSessionPositionChanged(base::nullopt); } for (auto& holder : image_observers_) @@ -323,6 +335,7 @@ session_metadata_.reset(); session_actions_.clear(); session_images_.clear(); + session_position_.reset(); } } // namespace media_session
diff --git a/services/media_session/media_controller.h b/services/media_session/media_controller.h index 1f57285..62d68f35 100644 --- a/services/media_session/media_controller.h +++ b/services/media_session/media_controller.h
@@ -62,6 +62,8 @@ void MediaSessionImagesChanged( const base::flat_map<mojom::MediaSessionImageType, std::vector<MediaImage>>& images) override; + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override; void SetMediaSession(AudioFocusRequest* session); void ClearMediaSession(); @@ -91,6 +93,9 @@ // The current actions for |session_|. std::vector<mojom::MediaSessionAction> session_actions_; + // The current position for |session_|. + base::Optional<MediaPosition> session_position_; + // The current images for |session_|. base::flat_map<mojom::MediaSessionImageType, std::vector<MediaImage>> session_images_;
diff --git a/services/media_session/media_controller_unittest.cc b/services/media_session/media_controller_unittest.cc index 3411d89..d937247 100644 --- a/services/media_session/media_controller_unittest.cc +++ b/services/media_session/media_controller_unittest.cc
@@ -892,6 +892,117 @@ } } +TEST_F(MediaControllerTest, ActiveController_Position_Observer_Empty) { + test::MockMediaSession media_session; + media_session.SetIsControllable(true); + + base::Optional<MediaPosition> test_position; + + { + test::MockMediaSessionMojoObserver observer(media_session); + RequestAudioFocus(media_session, mojom::AudioFocusType::kGain); + observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); + } + + { + test::TestMediaControllerObserver observer(controller()); + media_session.SimulatePositionChanged(test_position); + observer.WaitForEmptyPosition(); + } +} + +TEST_F(MediaControllerTest, ActiveController_Position_Observer_WithInfo) { + MediaPosition position(1 /* playback_rate */, + base::TimeDelta::FromSeconds(600) /* duration */, + base::TimeDelta::FromSeconds(300) /* position */); + + test::MockMediaSession media_session; + media_session.SetIsControllable(true); + + base::Optional<MediaPosition> test_position(position); + + { + test::MockMediaSessionMojoObserver observer(media_session); + RequestAudioFocus(media_session, mojom::AudioFocusType::kGain); + observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); + } + + { + test::TestMediaControllerObserver observer(controller()); + media_session.SimulatePositionChanged(test_position); + observer.WaitForNonEmptyPosition(); + } +} + +TEST_F(MediaControllerTest, ActiveController_Position_AddObserver_Empty) { + test::MockMediaSession media_session; + media_session.SetIsControllable(true); + + base::Optional<MediaPosition> test_position; + + { + test::MockMediaSessionMojoObserver observer(media_session); + RequestAudioFocus(media_session, mojom::AudioFocusType::kGain); + observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); + } + + media_session.SimulatePositionChanged(test_position); + + { + test::TestMediaControllerObserver observer(controller()); + observer.WaitForEmptyPosition(); + } +} + +TEST_F(MediaControllerTest, ActiveController_Position_AddObserver_WithInfo) { + MediaPosition position(1 /* playback_rate */, + base::TimeDelta::FromSeconds(600) /* duration */, + base::TimeDelta::FromSeconds(300) /* position */); + + test::MockMediaSession media_session; + media_session.SetIsControllable(true); + + base::Optional<MediaPosition> test_position(position); + + { + test::MockMediaSessionMojoObserver observer(media_session); + RequestAudioFocus(media_session, mojom::AudioFocusType::kGain); + observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); + } + + media_session.SimulatePositionChanged(test_position); + + { + test::TestMediaControllerObserver observer(controller()); + observer.WaitForNonEmptyPosition(); + } +} + +TEST_F(MediaControllerTest, ActiveController_Position_Observer_Abandoned) { + MediaPosition position(1 /* playback_rate */, + base::TimeDelta::FromSeconds(600) /* duration */, + base::TimeDelta::FromSeconds(300) /* position */); + + test::MockMediaSession media_session; + media_session.SetIsControllable(true); + + base::Optional<MediaPosition> test_position(position); + + { + test::MockMediaSessionMojoObserver observer(media_session); + RequestAudioFocus(media_session, mojom::AudioFocusType::kGain); + observer.WaitForState(mojom::MediaSessionInfo::SessionState::kActive); + } + + media_session.SimulatePositionChanged(test_position); + media_session.AbandonAudioFocusFromClient(); + + { + test::TestMediaControllerObserver observer(controller()); + observer.WaitForEmptyPosition(); + } +} + TEST_F(MediaControllerTest, ActiveController_Observer_Abandoned) { test::MockMediaSession media_session; media_session.SetIsControllable(true); @@ -906,11 +1017,12 @@ test::TestMediaControllerObserver observer(controller()); media_session.AbandonAudioFocusFromClient(); - // We should see empty info, metadata and actions flushed since the active - // controller is no longer bound to a media session. + // We should see empty info, metadata, actions, and position flushed since + // the active controller is no longer bound to a media session. observer.WaitForEmptyInfo(); observer.WaitForEmptyMetadata(); observer.WaitForEmptyActions(); + observer.WaitForEmptyPosition(); } } @@ -929,11 +1041,12 @@ { test::TestMediaControllerObserver observer(controller()); - // We should see empty info, metadata and actions since the active - // controller is no longer bound to a media session. + // We should see empty info, metadata, actions, and position since the + // active controller is no longer bound to a media session. observer.WaitForEmptyInfo(); observer.WaitForEmptyMetadata(); observer.WaitForEmptyActions(); + observer.WaitForEmptyPosition(); } }
diff --git a/services/media_session/public/cpp/media_position.h b/services/media_session/public/cpp/media_position.h index 6bbabc6..f59467f6 100644 --- a/services/media_session/public/cpp/media_position.h +++ b/services/media_session/public/cpp/media_position.h
@@ -9,6 +9,16 @@ #include "base/gtest_prod_util.h" #include "base/time/time.h" +namespace IPC { +template <class P> +struct ParamTraits; +} + +namespace ipc_fuzzer { +template <class T> +struct FuzzTraits; +} // namespace ipc_fuzzer + namespace mojo { template <typename DataViewType, typename T> struct StructTraits; @@ -50,6 +60,8 @@ std::string ToString() const; private: + friend struct IPC::ParamTraits<media_session::MediaPosition>; + friend struct ipc_fuzzer::FuzzTraits<media_session::MediaPosition>; friend struct mojo::StructTraits<mojom::MediaPositionDataView, MediaPosition>; friend class MediaPositionTest; FRIEND_TEST_ALL_PREFIXES(MediaPositionTest, TestPositionUpdated);
diff --git a/services/media_session/public/cpp/test/mock_media_session.cc b/services/media_session/public/cpp/test/mock_media_session.cc index c960a9ee..d8c3e21a 100644 --- a/services/media_session/public/cpp/test/mock_media_session.cc +++ b/services/media_session/public/cpp/test/mock_media_session.cc
@@ -75,6 +75,19 @@ } } +void MockMediaSessionMojoObserver::MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) { + session_position_ = position; + + if (waiting_for_empty_position_ && !position.has_value()) { + run_loop_->Quit(); + waiting_for_empty_position_ = false; + } else if (waiting_for_non_empty_position_ && position.has_value()) { + run_loop_->Quit(); + waiting_for_non_empty_position_ = false; + } +} + void MockMediaSessionMojoObserver::WaitForState( mojom::MediaSessionInfo::SessionState wanted_state) { if (session_info_ && session_info_->state == wanted_state) @@ -144,6 +157,24 @@ StartWaiting(); } +void MockMediaSessionMojoObserver::WaitForEmptyPosition() { + // |session_position_| is doubly wrapped in base::Optional so we must check + // both values. + if (session_position_.has_value() && !session_position_->has_value()) + return; + + waiting_for_empty_position_ = true; + StartWaiting(); +} + +void MockMediaSessionMojoObserver::WaitForNonEmptyPosition() { + if (session_position_.has_value() && session_position_->has_value()) + return; + + waiting_for_non_empty_position_ = true; + StartWaiting(); +} + void MockMediaSessionMojoObserver::StartWaiting() { DCHECK(!run_loop_); @@ -340,6 +371,13 @@ } } +void MockMediaSession::SimulatePositionChanged( + const base::Optional<MediaPosition>& position) { + for (auto& observer : observers_) { + observer->MediaSessionPositionChanged(position); + } +} + void MockMediaSession::ClearAllImages() { images_.clear();
diff --git a/services/media_session/public/cpp/test/mock_media_session.h b/services/media_session/public/cpp/test/mock_media_session.h index ea3675b..995a65a 100644 --- a/services/media_session/public/cpp/test/mock_media_session.h +++ b/services/media_session/public/cpp/test/mock_media_session.h
@@ -46,6 +46,8 @@ void MediaSessionImagesChanged( const base::flat_map<mojom::MediaSessionImageType, std::vector<MediaImage>>& images) override; + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override; void WaitForState(mojom::MediaSessionInfo::SessionState wanted_state); void WaitForPlaybackState(mojom::MediaPlaybackState wanted_state); @@ -61,6 +63,9 @@ void WaitForExpectedImagesOfType(mojom::MediaSessionImageType type, const std::vector<MediaImage>& images); + void WaitForEmptyPosition(); + void WaitForNonEmptyPosition(); + const mojom::MediaSessionInfoPtr& session_info() const { return session_info_; } @@ -74,6 +79,10 @@ return *session_actions_; } + const base::Optional<base::Optional<MediaPosition>>& session_position() { + return session_position_; + } + private: void StartWaiting(); @@ -83,6 +92,9 @@ base::Optional< base::flat_map<mojom::MediaSessionImageType, std::vector<MediaImage>>> session_images_; + base::Optional<base::Optional<MediaPosition>> session_position_; + bool waiting_for_empty_position_ = false; + bool waiting_for_non_empty_position_ = false; base::Optional<MediaMetadata> expected_metadata_; base::Optional<std::set<mojom::MediaSessionAction>> expected_actions_; @@ -152,6 +164,7 @@ void FlushForTesting(); void SimulateMetadataChanged(const base::Optional<MediaMetadata>& metadata); + void SimulatePositionChanged(const base::Optional<MediaPosition>& position); void ClearAllImages(); void SetImagesOfType(mojom::MediaSessionImageType type,
diff --git a/services/media_session/public/cpp/test/test_media_controller.cc b/services/media_session/public/cpp/test/test_media_controller.cc index 11b3462..7d3fb8c 100644 --- a/services/media_session/public/cpp/test/test_media_controller.cc +++ b/services/media_session/public/cpp/test/test_media_controller.cc
@@ -106,6 +106,19 @@ } } +void TestMediaControllerObserver::MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) { + session_position_ = position; + + if (waiting_for_empty_position_ && !position.has_value()) { + run_loop_->Quit(); + waiting_for_empty_position_ = false; + } else if (waiting_for_non_empty_position_ && position.has_value()) { + run_loop_->Quit(); + waiting_for_non_empty_position_ = false; + } +} + void TestMediaControllerObserver::WaitForState( mojom::MediaSessionInfo::SessionState wanted_state) { if (session_info_ && session_info()->state == wanted_state) @@ -162,6 +175,24 @@ StartWaiting(); } +void TestMediaControllerObserver::WaitForEmptyPosition() { + // |session_position_| is doubly wrapped in base::Optional so we must check + // both values. + if (session_position_.has_value() && !session_position_->has_value()) + return; + + waiting_for_empty_position_ = true; + StartWaiting(); +} + +void TestMediaControllerObserver::WaitForNonEmptyPosition() { + if (session_position_.has_value() && session_position_->has_value()) + return; + + waiting_for_non_empty_position_ = true; + StartWaiting(); +} + void TestMediaControllerObserver::WaitForSession( const base::Optional<base::UnguessableToken>& request_id) { if (session_request_id_.has_value() && session_request_id_ == request_id) @@ -197,6 +228,10 @@ ++resume_count_; } +void TestMediaController::Stop() { + ++stop_count_; +} + void TestMediaController::ToggleSuspendResume() { ++toggle_suspend_resume_count_; }
diff --git a/services/media_session/public/cpp/test/test_media_controller.h b/services/media_session/public/cpp/test/test_media_controller.h index 66fe8e9..b4680b5 100644 --- a/services/media_session/public/cpp/test/test_media_controller.h +++ b/services/media_session/public/cpp/test/test_media_controller.h
@@ -66,6 +66,8 @@ const std::vector<mojom::MediaSessionAction>& actions) override; void MediaSessionChanged( const base::Optional<base::UnguessableToken>& request_id) override; + void MediaSessionPositionChanged( + const base::Optional<media_session::MediaPosition>& position) override; void WaitForState(mojom::MediaSessionInfo::SessionState wanted_state); void WaitForPlaybackState(mojom::MediaPlaybackState wanted_state); @@ -78,6 +80,9 @@ void WaitForExpectedActions( const std::set<mojom::MediaSessionAction>& actions); + void WaitForEmptyPosition(); + void WaitForNonEmptyPosition(); + void WaitForSession(const base::Optional<base::UnguessableToken>& request_id); const mojom::MediaSessionInfoPtr& session_info() const { @@ -93,6 +98,10 @@ return *session_actions_; } + const base::Optional<base::Optional<MediaPosition>>& session_position() { + return session_position_; + } + private: void StartWaiting(); @@ -100,6 +109,9 @@ base::Optional<base::Optional<MediaMetadata>> session_metadata_; base::Optional<std::set<mojom::MediaSessionAction>> session_actions_; base::Optional<base::Optional<base::UnguessableToken>> session_request_id_; + base::Optional<base::Optional<MediaPosition>> session_position_; + bool waiting_for_empty_position_ = false; + bool waiting_for_non_empty_position_ = false; base::Optional<MediaMetadata> expected_metadata_; base::Optional<std::set<mojom::MediaSessionAction>> expected_actions_; @@ -128,7 +140,7 @@ // mojom::MediaController: void Suspend() override; void Resume() override; - void Stop() override {} + void Stop() override; void ToggleSuspendResume() override; void AddObserver( mojo::PendingRemote<mojom::MediaControllerObserver> observer) override; @@ -149,6 +161,7 @@ int suspend_count() const { return suspend_count_; } int resume_count() const { return resume_count_; } + int stop_count() const { return stop_count_; } int add_observer_count() const { return add_observer_count_; } int previous_track_count() const { return previous_track_count_; } int next_track_count() const { return next_track_count_; } @@ -164,6 +177,7 @@ int toggle_suspend_resume_count_ = 0; int suspend_count_ = 0; int resume_count_ = 0; + int stop_count_ = 0; int add_observer_count_ = 0; int previous_track_count_ = 0; int next_track_count_ = 0;
diff --git a/services/media_session/public/mojom/media_controller.mojom b/services/media_session/public/mojom/media_controller.mojom index 1c810d10..6c6c413 100644 --- a/services/media_session/public/mojom/media_controller.mojom +++ b/services/media_session/public/mojom/media_controller.mojom
@@ -100,6 +100,13 @@ // Called when the bound media session changes. This tells the observer the // |request_id| of the new session of null if it is not bound to a session. MediaSessionChanged(mojo_base.mojom.UnguessableToken? request_id); + + // Called when the position of the bound media session has changed. If + // |position| is empty then the media session does not have a position or + // the controller is no longer bound to a media session. Position is updated + // anytime the position state (playback rate, duration) is changed or the + // media is seeked. + MediaSessionPositionChanged(MediaPosition? position); }; // The observer for observing when images associated with a media controller
diff --git a/services/media_session/public/mojom/media_session.mojom b/services/media_session/public/mojom/media_session.mojom index ae3e243..ab3bbfb 100644 --- a/services/media_session/public/mojom/media_session.mojom +++ b/services/media_session/public/mojom/media_session.mojom
@@ -127,7 +127,7 @@ }; // The observer for observing media session events. -// Next Method ID: 4 +// Next Method ID: 5 interface MediaSessionObserver { // Call when the info associated with the session changed. MediaSessionInfoChanged@0(MediaSessionInfo info); @@ -144,6 +144,9 @@ // Called when the images associated with a media session change. MediaSessionImagesChanged@3( map<MediaSessionImageType, array<MediaImage>> images); + + // Called when the position associated with the session has changed. + MediaSessionPositionChanged@4(MediaPosition? position); }; // A MediaSession manages the media session and audio focus for a given
diff --git a/services/metrics/public/cpp/ukm_recorder.h b/services/metrics/public/cpp/ukm_recorder.h index b4cb17e..239643d4 100644 --- a/services/metrics/public/cpp/ukm_recorder.h +++ b/services/metrics/public/cpp/ukm_recorder.h
@@ -18,6 +18,7 @@ #include "url/gurl.h" class PermissionUmaUtil; +class WebApkUkmRecorder; namespace blink { class Document; @@ -75,6 +76,13 @@ friend metrics::UkmRecorderInterface; friend PermissionUmaUtil; + // WebApkUkmRecorder records metrics about installed Webapps. Instead of using + // the current main frame URL, we want to record the URL of the Webapp + // manifest which identifies the current app. Therefore, WebApkUkmRecorder + // needs to be a friend so that it can access the private UpdateSourceURL() + // method. + friend WebApkUkmRecorder; + // Associates the SourceId with a URL. Most UKM recording code should prefer // to use a shared SourceId that is already associated with a URL, rather // than using this API directly. New uses of this API must be audited to
diff --git a/services/shape_detection/OWNERS b/services/shape_detection/OWNERS index 4009628..aee8252f 100644 --- a/services/shape_detection/OWNERS +++ b/services/shape_detection/OWNERS
@@ -1,7 +1,4 @@ -reillyg@chromium.org - -# Original (legacy) owner. -mcasas@chromium.org +file://third_party/blink/renderer/modules/shapedetection/OWNERS # COMPONENT: Blink>ShapeDetection # TEAM: device-dev@chromium.org
diff --git a/services/tracing/BUILD.gn b/services/tracing/BUILD.gn index 0dfdb64d..35d81a8 100644 --- a/services/tracing/BUILD.gn +++ b/services/tracing/BUILD.gn
@@ -115,21 +115,23 @@ "coordinator_test_util.cc", "coordinator_test_util.h", "coordinator_unittest.cc", + "perfetto/consumer_host_unittest.cc", + "perfetto/json_trace_exporter_unittest.cc", + "perfetto/perfetto_integration_unittest.cc", + "perfetto/perfetto_tracing_coordinator_unittest.cc", + "perfetto/test_utils.cc", + "perfetto/test_utils.h", + "perfetto/track_event_json_exporter_unittest.cc", + "public/cpp/perfetto/task_runner_unittest.cc", + "public/cpp/perfetto/trace_event_data_source_unittest.cc", + "public/cpp/perfetto/traced_value_proto_writer_unittest.cc", + "public/cpp/stack_sampling/tracing_sampler_profiler_unittest.cc", "public/cpp/trace_event_agent_unittest.cc", "recorder_unittest.cc", "test_util.cc", "test_util.h", ] - if (is_mac || is_linux || is_android || is_fuchsia) { - sources += [ - "public/cpp/perfetto/task_runner_unittest.cc", - "public/cpp/perfetto/trace_event_data_source_unittest.cc", - "public/cpp/perfetto/traced_value_proto_writer_unittest.cc", - "public/cpp/stack_sampling/tracing_sampler_profiler_unittest.cc", - ] - } - if (!is_android) { sources += [ "tracing_service_unittest.cc" ] } @@ -145,29 +147,14 @@ "//services/tracing:lib", "//testing/gmock", "//testing/gtest", + "//third_party/perfetto/include/perfetto/protozero:protozero", + "//third_party/perfetto/protos/perfetto/common:lite", + "//third_party/perfetto/protos/perfetto/trace:lite", + "//third_party/perfetto/protos/perfetto/trace/chrome:lite", + "//third_party/perfetto/protos/perfetto/trace/interned_data:lite", + "//third_party/perfetto/protos/perfetto/trace/track_event:lite", ] - if (is_mac || is_linux || is_android || is_fuchsia) { - sources += [ - "perfetto/consumer_host_unittest.cc", - "perfetto/json_trace_exporter_unittest.cc", - "perfetto/perfetto_integration_unittest.cc", - "perfetto/perfetto_tracing_coordinator_unittest.cc", - "perfetto/test_utils.cc", - "perfetto/test_utils.h", - "perfetto/track_event_json_exporter_unittest.cc", - ] - - deps += [ - "//third_party/perfetto/include/perfetto/protozero:protozero", - "//third_party/perfetto/protos/perfetto/common:lite", - "//third_party/perfetto/protos/perfetto/trace:lite", - "//third_party/perfetto/protos/perfetto/trace/chrome:lite", - "//third_party/perfetto/protos/perfetto/trace/interned_data:lite", - "//third_party/perfetto/protos/perfetto/trace/track_event:lite", - ] - } - if (is_android) { sources += [ "perfetto/system_perfetto_unittest.cc",
diff --git a/services/tracing/perfetto/system_perfetto_unittest.cc b/services/tracing/perfetto/system_perfetto_unittest.cc index 34e6051..524ed797 100644 --- a/services/tracing/perfetto/system_perfetto_unittest.cc +++ b/services/tracing/perfetto/system_perfetto_unittest.cc
@@ -220,9 +220,11 @@ // Set up the producer to talk to the system. base::RunLoop system_data_source_enabled_runloop; + base::RunLoop system_data_source_disabled_runloop; auto system_producer = CreateMockAndroidSystemProducer( system_service.get(), - /* num_data_sources = */ 1, &system_data_source_enabled_runloop); + /* num_data_sources = */ 1, &system_data_source_enabled_runloop, + &system_data_source_disabled_runloop); // Start a system trace, and wait on the Data Source being started. base::RunLoop system_no_more_packets_runloop; @@ -236,9 +238,15 @@ system_data_source_enabled_runloop.Run(); // Post a task to ensure we stop the trace after the data is written. + base::RunLoop stop_tracing; PerfettoTracedProcess::GetTaskRunner()->PostTask( - [&]() { system_consumer.StopTracing(); }); + [&system_consumer, &stop_tracing]() { + system_consumer.StopTracing(); + stop_tracing.Quit(); + }); + stop_tracing.Run(); + system_data_source_disabled_runloop.Run(); system_no_more_packets_runloop.Run(); EXPECT_EQ(1u, system_consumer.received_packets()); @@ -447,9 +455,9 @@ system_data_source_disabled_runloop.Run(); system_no_more_packets_runloop.Run(); - // Once we StopTracing() on the local trace the system tracing system will - // come back. So set new enabled and disabled RunLoops for the system - // producer. + // Once we StopTracing() on the system trace the we want to make sure a new + // local trace can start smoothly. So set new enabled and disabled RunLoops + // for the system producer. base::RunLoop local_data_source_reenabled_runloop; base::RunLoop local_data_source_redisabled_runloop; local_producer_client->SetAgentEnabledCallback( @@ -678,10 +686,11 @@ }); base::RunLoop system_data_source_enabled_runloop; + base::RunLoop system_data_source_disabled_runloop; auto system_producer = CreateMockAndroidSystemProducer( system_ptr, /* num_data_sources = */ 1, &system_data_source_enabled_runloop, - /* system_data_source_disabled_runloop = */ nullptr, check_sdk_level); + &system_data_source_disabled_runloop, check_sdk_level); if (!check_sdk_level) { system_data_source_enabled_runloop.Run(); @@ -689,9 +698,19 @@ // Post the task to ensure that the data will have been written and // committed if any tracing is being done. + base::RunLoop stop_tracing; PerfettoTracedProcess::GetTaskRunner()->PostTask( - [&system_consumer]() { system_consumer.StopTracing(); }); + [&system_consumer, &stop_tracing]() { + system_consumer.StopTracing(); + stop_tracing.Quit(); + }); + stop_tracing.Run(); + + if (!check_sdk_level) { + system_data_source_disabled_runloop.Run(); + } system_no_more_packets_runloop.Run(); + PerfettoProducer::DeleteSoonForTesting(std::move(system_producer)); return system_consumer.received_packets(); };
diff --git a/services/tracing/perfetto/system_test_utils.cc b/services/tracing/perfetto/system_test_utils.cc index 830adfb..df1689f 100644 --- a/services/tracing/perfetto/system_test_utils.cc +++ b/services/tracing/perfetto/system_test_utils.cc
@@ -21,11 +21,11 @@ task_runner_(std::make_unique<PerfettoTaskRunner>( base::SequencedTaskRunnerHandle::Get())) { service_ = perfetto::ServiceIPCHost::CreateInstance(task_runner_.get()); - DCHECK(service_); + CHECK(service_); unlink(producer_socket.c_str()); unlink(consumer_socket.c_str()); bool succeeded = service_->Start(producer_.c_str(), consumer_.c_str()); - DCHECK(succeeded); + CHECK(succeeded); } MockSystemService::~MockSystemService() { @@ -73,7 +73,7 @@ // See comment in the constructor. auto client = PerfettoTracedProcess::Get()->SetSystemProducerForTesting( std::move(old_producer_)); - DCHECK(client.get() == this); + CHECK(client.get() == this); client.release(); } @@ -81,7 +81,7 @@ perfetto::DataSourceInstanceID id, const perfetto::DataSourceConfig& data_source_config) { AndroidSystemProducer::StartDataSource(id, data_source_config); - DCHECK_LT(num_data_sources_active_, num_data_sources_expected_); + CHECK_LT(num_data_sources_active_, num_data_sources_expected_); if (data_source_enabled_callback_ && ++num_data_sources_active_ == num_data_sources_expected_) { std::move(data_source_enabled_callback_).Run(); @@ -91,7 +91,7 @@ void MockAndroidSystemProducer::StopDataSource( perfetto::DataSourceInstanceID id) { AndroidSystemProducer::StopDataSource(id); - DCHECK_GT(num_data_sources_active_, 0u); + CHECK_GT(num_data_sources_active_, 0u); if (data_source_disabled_callback_ && --num_data_sources_active_ == 0) { std::move(data_source_disabled_callback_).Run(); }
diff --git a/services/tracing/perfetto/test_utils.cc b/services/tracing/perfetto/test_utils.cc index 8f54932..ffa0e51 100644 --- a/services/tracing/perfetto/test_utils.cc +++ b/services/tracing/perfetto/test_utils.cc
@@ -69,7 +69,7 @@ } void TestDataSource::StopTracing(base::OnceClosure stop_complete_callback) { - DCHECK(producer_); + CHECK(producer_); producer_ = nullptr; std::move(stop_complete_callback).Run(); } @@ -118,7 +118,7 @@ ProducerClient::StartDataSource(id, std::move(data_source_config), std::move(callback)); - DCHECK_LT(num_data_sources_active_, num_data_sources_expected_); + CHECK_LT(num_data_sources_active_, num_data_sources_expected_); if (client_enabled_callback_ && ++num_data_sources_active_ == num_data_sources_expected_) { std::move(client_enabled_callback_).Run(); @@ -129,7 +129,7 @@ StopDataSourceCallback callback) { ProducerClient::StopDataSource(id, std::move(callback)); - DCHECK_GT(num_data_sources_active_, 0u); + CHECK_GT(num_data_sources_active_, 0u); if (client_disabled_callback_ && --num_data_sources_active_ == 0) { std::move(client_disabled_callback_).Run(); } @@ -165,18 +165,21 @@ PacketReceivedCallback packet_received_callback) : packet_received_callback_(packet_received_callback), data_source_names_(data_source_names) { - DCHECK(!data_source_names_.empty()); + CHECK(!data_source_names_.empty()); consumer_endpoint_ = service->ConnectConsumer(this, /*uid=*/0); + CHECK(consumer_endpoint_); } MockConsumer::~MockConsumer() = default; void MockConsumer::ReadBuffers() { + CHECK(consumer_endpoint_); consumer_endpoint_->ReadBuffers(); } void MockConsumer::StopTracing() { ReadBuffers(); + CHECK(consumer_endpoint_); consumer_endpoint_->DisableTracing(); } @@ -189,10 +192,12 @@ ds_config->set_target_buffer(0); } + CHECK(consumer_endpoint_); consumer_endpoint_->EnableTracing(trace_config); } void MockConsumer::FreeBuffers() { + CHECK(consumer_endpoint_); consumer_endpoint_->FreeBuffers(); }
diff --git a/services/tracing/public/cpp/perfetto/perfetto_traced_process.h b/services/tracing/public/cpp/perfetto/perfetto_traced_process.h index 1738cef..68fc96a 100644 --- a/services/tracing/public/cpp/perfetto/perfetto_traced_process.h +++ b/services/tracing/public/cpp/perfetto/perfetto_traced_process.h
@@ -29,7 +29,7 @@ // in PerfettoProducer::StartDataSource. class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final { public: - class DataSourceBase { + class COMPONENT_EXPORT(TRACING_CPP) DataSourceBase { public: explicit DataSourceBase(const std::string& name); virtual ~DataSourceBase();
diff --git a/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.cc b/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.cc index bf334e0..d6045e05 100644 --- a/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.cc +++ b/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.cc
@@ -14,6 +14,7 @@ #include "base/process/process.h" #include "base/process/process_handle.h" #include "base/profiler/stack_sampling_profiler.h" +#include "base/strings/strcat.h" #include "base/task/thread_pool/thread_pool.h" #include "base/threading/thread_local.h" #include "build/build_config.h" @@ -60,25 +61,41 @@ void RegisterProfiler(TracingSamplerProfiler* profiler) { base::AutoLock lock(lock_); - if (!profilers_.insert(profiler).second || !is_started_) { + if (!profilers_.insert(profiler).second) { return; } - profiler->StartTracing( - perfetto_producer_->CreateTraceWriter( - data_source_config_.target_buffer()), - data_source_config_.chrome_config().privacy_filtering_enabled()); + if (is_started_) { + profiler->StartTracing( + perfetto_producer_->CreateTraceWriter( + data_source_config_.target_buffer()), + data_source_config_.chrome_config().privacy_filtering_enabled()); + } else if (is_startup_tracing_) { + profiler->StartTracing(nullptr, /*should_enable_filtering=*/true); + } } void UnregisterProfiler(TracingSamplerProfiler* profiler) { base::AutoLock lock(lock_); - if (!profilers_.erase(profiler) || !is_started_) { + if (!profilers_.erase(profiler) || !(is_started_ || is_startup_tracing_)) { return; } profiler->StopTracing(); } + void SetupStartupTracing() { + base::AutoLock lock(lock_); + if (is_started_) { + return; + } + is_startup_tracing_ = true; + for (auto* profiler : profilers_) { + // Enable filtering for startup tracing always to be safe. + profiler->StartTracing(nullptr, /*should_enable_filtering=*/true); + } + } + // PerfettoTracedProcess::DataSourceBase implementation, called by // ProducerClient. void StartTracing( @@ -87,6 +104,7 @@ base::AutoLock lock(lock_); DCHECK(!is_started_); is_started_ = true; + is_startup_tracing_ = false; perfetto_producer_ = producer; data_source_config_ = data_source_config; @@ -104,6 +122,7 @@ base::AutoLock lock(lock_); DCHECK(is_started_); is_started_ = false; + is_startup_tracing_ = false; perfetto_producer_ = nullptr; for (auto* profiler : profilers_) { @@ -128,6 +147,7 @@ private: base::Lock lock_; // Protects subsequent members. std::set<TracingSamplerProfiler*> profilers_; + bool is_startup_tracing_ = false; bool is_started_ = false; PerfettoProducer* perfetto_producer_ = nullptr; perfetto::DataSourceConfig data_source_config_; @@ -150,6 +170,18 @@ } // namespace +TracingSamplerProfiler::TracingProfileBuilder::BufferedSample::BufferedSample( + base::TimeTicks ts, + std::vector<base::Frame>&& s) + : timestamp(ts), sample(std::move(s)) {} + +TracingSamplerProfiler::TracingProfileBuilder::BufferedSample:: + ~BufferedSample() = default; + +TracingSamplerProfiler::TracingProfileBuilder::BufferedSample::BufferedSample( + TracingSamplerProfiler::TracingProfileBuilder::BufferedSample&& other) + : BufferedSample(other.timestamp, std::move(other.sample)) {} + TracingSamplerProfiler::TracingProfileBuilder::TracingProfileBuilder( base::PlatformThreadId sampled_thread_id, std::unique_ptr<perfetto::TraceWriter> trace_writer, @@ -181,6 +213,27 @@ void TracingSamplerProfiler::TracingProfileBuilder::OnSampleCompleted( std::vector<base::Frame> frames) { + base::AutoLock l(trace_writer_lock_); + if (!trace_writer_) { + if (buffered_samples_.size() < kMaxBufferedSamples) { + buffered_samples_.emplace_back( + BufferedSample(TRACE_TIME_TICKS_NOW(), std::move(frames))); + } + return; + } + if (!buffered_samples_.empty()) { + for (const auto& sample : buffered_samples_) { + WriteSampleToTrace(sample); + } + buffered_samples_.clear(); + } + WriteSampleToTrace(BufferedSample(TRACE_TIME_TICKS_NOW(), std::move(frames))); +} + +void TracingSamplerProfiler::TracingProfileBuilder::WriteSampleToTrace( + const TracingSamplerProfiler::TracingProfileBuilder::BufferedSample& + sample) { + const auto& frames = sample.sample; auto reset_id = TracingSamplerProfilerDataSource::GetIncrementalStateResetID(); if (reset_id != last_incremental_state_reset_id_) { @@ -205,13 +258,12 @@ auto* thread_descriptor = trace_packet->set_thread_descriptor(); thread_descriptor->set_pid(base::GetCurrentProcId()); thread_descriptor->set_tid(sampled_thread_id_); - last_timestamp_ = TRACE_TIME_TICKS_NOW(); + last_timestamp_ = sample.timestamp; thread_descriptor->set_reference_timestamp_us( last_timestamp_.since_origin().InMicroseconds()); reset_incremental_state_ = false; } - auto time_now = TRACE_TIME_TICKS_NOW(); int32_t current_process_priority = base::Process::Current().GetPriority(); if (current_process_priority != last_emitted_process_priority_) { last_emitted_process_priority_ = current_process_priority; @@ -226,8 +278,14 @@ auto* streaming_profile_packet = trace_packet->set_streaming_profile_packet(); streaming_profile_packet->add_callstack_iid(callstack_id); streaming_profile_packet->add_timestamp_delta_us( - (time_now - last_timestamp_).InMicroseconds()); - last_timestamp_ = time_now; + (sample.timestamp - last_timestamp_).InMicroseconds()); + last_timestamp_ = sample.timestamp; +} + +void TracingSamplerProfiler::TracingProfileBuilder::SetTraceWriter( + std::unique_ptr<perfetto::TraceWriter> writer) { + base::AutoLock l(trace_writer_lock_); + trace_writer_ = std::move(writer); } InterningID @@ -301,6 +359,22 @@ } #endif +#if defined(OS_ANDROID) || defined(OS_LINUX) + // Linux ELF module IDs are 160bit integers, which we need to mangle + // down to 128bit integers to match the id that Breakpad outputs. + // Example on version '66.0.3359.170' x64: + // Build-ID: "7f0715c2 86f8 b16c 10e4ad349cda3b9b 56c7a773 + // Debug-ID "C215077F F886 6CB1 10E4AD349CDA3B9B 0" + if (module_id.size() >= 32) { + module_id = + base::StrCat({module_id.substr(6, 2), module_id.substr(4, 2), + module_id.substr(2, 2), module_id.substr(0, 2), + module_id.substr(10, 2), module_id.substr(8, 2), + module_id.substr(14, 2), module_id.substr(12, 2), + module_id.substr(16, 16), "0"}); + } +#endif + // We never emit frame names in privacy filtered mode. bool should_emit_frame_names = !frame_name.empty() && !should_enable_filtering_; @@ -419,6 +493,11 @@ } // static +void TracingSamplerProfiler::SetupStartupTracing() { + TracingSamplerProfilerDataSource::Get()->SetupStartupTracing(); +} + +// static void TracingSamplerProfiler::StopTracingForTesting() { TracingSamplerProfilerDataSource::Get()->StopTracing(base::DoNothing()); } @@ -438,7 +517,12 @@ std::unique_ptr<perfetto::TraceWriter> trace_writer, bool should_enable_filtering) { base::AutoLock lock(lock_); - DCHECK(!profiler_.get()); + if (profiler_) { + if (trace_writer) { + profile_builder_->SetTraceWriter(std::move(trace_writer)); + } + return; + } #if defined(OS_ANDROID) // The sampler profiler would conflict with the reached code profiler if they @@ -455,11 +539,12 @@ // metrics when looking at traces. params.keep_consistent_sampling_interval = false; + auto profile_builder = std::make_unique<TracingProfileBuilder>( + sampled_thread_id_, std::move(trace_writer), should_enable_filtering); + profile_builder_ = profile_builder.get(); // Create and start the stack sampling profiler. #if defined(OS_ANDROID) && BUILDFLAG(CAN_UNWIND_WITH_CFI_TABLE) && \ defined(OFFICIAL_BUILD) - auto profile_builder = std::make_unique<TracingProfileBuilder>( - sampled_thread_id_, std::move(trace_writer), should_enable_filtering); auto* module_cache = profile_builder->GetModuleCache(); profiler_ = std::make_unique<base::StackSamplingProfiler>( sampled_thread_id_, params, std::move(profile_builder), @@ -467,10 +552,7 @@ #else profiler_ = std::make_unique<base::StackSamplingProfiler>( - sampled_thread_id_, params, - std::make_unique<TracingProfileBuilder>(sampled_thread_id_, - std::move(trace_writer), - should_enable_filtering)); + sampled_thread_id_, params, std::move(profile_builder)); #endif profiler_->Start(); @@ -478,10 +560,13 @@ void TracingSamplerProfiler::StopTracing() { base::AutoLock lock(lock_); - DCHECK(profiler_.get()); + if (!profiler_) { + return; + } // Stop and release the stack sampling profiler. profiler_->Stop(); + profile_builder_ = nullptr; profiler_.reset(); }
diff --git a/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h b/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h index fe003fc..85714ac 100644 --- a/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h +++ b/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h
@@ -50,13 +50,33 @@ void OnProfileCompleted(base::TimeDelta profile_duration, base::TimeDelta sampling_period) override {} + void SetTraceWriter(std::unique_ptr<perfetto::TraceWriter> trace_writer); + private: + struct BufferedSample { + BufferedSample(base::TimeTicks, std::vector<base::Frame>&&); + BufferedSample(BufferedSample&& other); + ~BufferedSample(); + + base::TimeTicks timestamp; + std::vector<base::Frame> sample; + + DISALLOW_COPY_AND_ASSIGN(BufferedSample); + }; + InterningID GetCallstackIDAndMaybeEmit( const std::vector<base::Frame>& frames, perfetto::TraceWriter::TracePacketHandle* trace_packet); + void WriteSampleToTrace(const BufferedSample& sample); + + // We usually sample at 50ms, and expect that tracing should have started in + // 10s. + constexpr static size_t kMaxBufferedSamples = 200; + std::vector<BufferedSample> buffered_samples_; base::ModuleCache module_cache_; const base::PlatformThreadId sampled_thread_id_; + base::Lock trace_writer_lock_; std::unique_ptr<perfetto::TraceWriter> trace_writer_; InterningIndex<size_t> interned_callstacks_{1000}; InterningIndex<std::pair<std::string, std::string>, @@ -79,6 +99,8 @@ static void CreateForCurrentThread(); static void RegisterDataSource(); + static void SetupStartupTracing(); + // For tests. static void DeleteForCurrentThreadForTesting(); static void StartTracingForTesting(tracing::PerfettoProducer* producer); @@ -97,6 +119,7 @@ base::Lock lock_; std::unique_ptr<base::StackSamplingProfiler> profiler_; // under |lock_| + TracingProfileBuilder* profile_builder_ = nullptr; DISALLOW_COPY_AND_ASSIGN(TracingSamplerProfiler); };
diff --git a/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler_unittest.cc b/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler_unittest.cc index 9f0012bd..9c0ad98 100644 --- a/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler_unittest.cc +++ b/services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler_unittest.cc
@@ -3,14 +3,17 @@ // found in the LICENSE file. #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h" +#include <limits> #include "base/at_exit.h" #include "base/bind.h" #include "base/json/json_reader.h" #include "base/memory/ref_counted_memory.h" #include "base/run_loop.h" +#include "base/test/bind_test_util.h" #include "base/test/scoped_task_environment.h" #include "base/threading/thread.h" +#include "base/time/time.h" #include "base/trace_event/trace_buffer.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" @@ -172,20 +175,6 @@ #endif } - static void TraceDataCallback( - const base::RepeatingCallback<void()>& callback, - std::string* output, - const scoped_refptr<base::RefCountedString>& json_events_str, - bool has_more_events) { - if (output->size() > 1 && !json_events_str->data().empty()) { - output->append(","); - } - output->append(json_events_str->data()); - if (!has_more_events) { - callback.Run(); - } - } - void EndTracing() { TracingSamplerProfiler::StopTracingForTesting(); base::RunLoop().RunUntilIdle(); @@ -206,13 +195,27 @@ } } + uint32_t FindProfilerSequenceId() { + uint32_t profile_sequence_id = std::numeric_limits<uint32_t>::max(); + auto& packets = producer_->finalized_packets(); + for (auto& packet : packets) { + if (packet->has_streaming_profile_packet()) { + profile_sequence_id = packet->trusted_packet_sequence_id(); + break; + } + } + EXPECT_NE(profile_sequence_id, std::numeric_limits<uint32_t>::max()); + return profile_sequence_id; + } + + const MockPerfettoProducer* producer() const { return producer_.get(); } + private: base::test::ScopedTaskEnvironment scoped_task_environment_; // We want our singleton torn down after each test. base::ShadowingAtExitManager at_exit_manager_; base::trace_event::TraceResultBuffer trace_buffer_; - base::trace_event::TraceResultBuffer::SimpleOutput json_output_; std::unique_ptr<MockPerfettoProducer> producer_; @@ -230,11 +233,15 @@ TestModule(const TestModule&) = delete; TestModule& operator=(const TestModule&) = delete; + void set_id(const std::string& id) { id_ = id; } uintptr_t GetBaseAddress() const override { return 0; } - std::string GetId() const override { return ""; } + std::string GetId() const override { return id_; } base::FilePath GetDebugBasename() const override { return base::FilePath(); } size_t GetSize() const override { return 0; } bool IsNative() const override { return true; } + + private: + std::string id_; }; } // namespace @@ -261,6 +268,76 @@ TracingSamplerProfiler::DeleteForCurrentThreadForTesting(); } +TEST_F(TracingSampleProfilerTest, TestStartupTracing) { + TracingSamplerProfiler::CreateForCurrentThread(); + TracingSamplerProfiler::SetupStartupTracing(); + base::RunLoop().RunUntilIdle(); + WaitForEvents(); + auto start_tracing_ts = TRACE_TIME_TICKS_NOW(); + BeginTrace(); + base::RunLoop().RunUntilIdle(); + WaitForEvents(); + EndTracing(); + base::RunLoop().RunUntilIdle(); + if (IsStackUnwindingSupported()) { + uint32_t seq_id = FindProfilerSequenceId(); + auto& packets = producer()->finalized_packets(); + int64_t reference_ts = 0; + int64_t first_profile_ts = 0; + for (auto& packet : packets) { + if (packet->trusted_packet_sequence_id() == seq_id) { + if (packet->has_thread_descriptor()) { + reference_ts = packet->thread_descriptor().reference_timestamp_us(); + } else if (packet->has_streaming_profile_packet()) { + first_profile_ts = + reference_ts + + packet->streaming_profile_packet().timestamp_delta_us(0); + break; + } + } + } + // Expect first sample before tracing started. + EXPECT_LT(first_profile_ts, + start_tracing_ts.since_origin().InMicroseconds()); + } + TracingSamplerProfiler::DeleteForCurrentThreadForTesting(); +} + +TEST_F(TracingSampleProfilerTest, JoinStartupTracing) { + TracingSamplerProfiler::SetupStartupTracing(); + base::RunLoop().RunUntilIdle(); + TracingSamplerProfiler::CreateForCurrentThread(); + WaitForEvents(); + auto start_tracing_ts = TRACE_TIME_TICKS_NOW(); + BeginTrace(); + base::RunLoop().RunUntilIdle(); + WaitForEvents(); + EndTracing(); + base::RunLoop().RunUntilIdle(); + if (IsStackUnwindingSupported()) { + uint32_t seq_id = FindProfilerSequenceId(); + auto& packets = producer()->finalized_packets(); + int64_t reference_ts = 0; + int64_t first_profile_ts = 0; + for (auto& packet : packets) { + if (packet->trusted_packet_sequence_id() == seq_id) { + if (packet->has_thread_descriptor()) { + reference_ts = packet->thread_descriptor().reference_timestamp_us(); + } else if (packet->has_streaming_profile_packet()) { + first_profile_ts = + reference_ts + + packet->streaming_profile_packet().timestamp_delta_us(0); + break; + } + } + } + // Expect first sample before tracing started. + EXPECT_LT(first_profile_ts, + start_tracing_ts.since_origin().InMicroseconds()); + } + TracingSamplerProfiler::DeleteForCurrentThreadForTesting(); +} + TEST_F(TracingSampleProfilerTest, SamplingChildThread) { base::Thread sampled_thread("sampling_profiler_test"); sampled_thread.Start(); @@ -294,4 +371,34 @@ profile_builder.OnSampleCompleted({base::Frame(0x1010, nullptr)}); } +#if defined(OS_ANDROID) || defined(OS_LINUX) +TEST(TracingProfileBuilderTest, MangleELFModuleID) { + TestModule module; + // See explanation for the module_id mangling in + // TracingSamplerProfiler::TracingProfileBuilder::GetCallstackIDAndMaybeEmit. + module.set_id("7F0715C286F8B16C10E4AD349CDA3B9B56C7A773"); + + bool found_build_id = false; + auto on_packet_callback = base::BindLambdaForTesting( + [&found_build_id](std::unique_ptr<perfetto::protos::TracePacket> packet) { + if (!packet->has_interned_data() || + packet->interned_data().build_ids_size() == 0) { + return; + } + + found_build_id = true; + EXPECT_EQ(packet->interned_data().build_ids(0).str(), + "C215077FF8866CB110E4AD349CDA3B9B0"); + }); + + auto trace_writer = std::make_unique<MockTraceWriter>(on_packet_callback); + auto* raw_trace_writer = trace_writer.get(); + TracingSamplerProfiler::TracingProfileBuilder profile_builder( + base::PlatformThreadId(), std::move(trace_writer), false); + profile_builder.OnSampleCompleted({base::Frame(0x1010, &module)}); + raw_trace_writer->FlushPacketIfPossible(); + EXPECT_TRUE(found_build_id); +} +#endif + } // namespace tracing
diff --git a/services/tracing/public/cpp/trace_startup.cc b/services/tracing/public/cpp/trace_startup.cc index b2e5f9c..5b02671 100644 --- a/services/tracing/public/cpp/trace_startup.cc +++ b/services/tracing/public/cpp/trace_startup.cc
@@ -11,6 +11,7 @@ #include "components/tracing/common/trace_to_console.h" #include "components/tracing/common/tracing_switches.h" #include "services/tracing/public/cpp/perfetto/trace_event_data_source.h" +#include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h" #include "services/tracing/public/cpp/tracing_features.h" namespace tracing { @@ -37,6 +38,7 @@ if (startup_config->IsEnabled()) { if (TracingUsesPerfettoBackend()) { + TracingSamplerProfiler::SetupStartupTracing(); TraceEventDataSource::GetInstance()->SetupStartupTracing( startup_config->GetSessionOwner() == TraceStartupConfig::SessionOwner::kBackgroundTracing);
diff --git a/services/viz/public/cpp/compositing/render_pass_struct_traits.h b/services/viz/public/cpp/compositing/render_pass_struct_traits.h index a33c429b..72b8788 100644 --- a/services/viz/public/cpp/compositing/render_pass_struct_traits.h +++ b/services/viz/public/cpp/compositing/render_pass_struct_traits.h
@@ -51,9 +51,9 @@ return input->backdrop_filters; } - static gfx::RRectF backdrop_filter_bounds( + static base::Optional<gfx::RRectF> backdrop_filter_bounds( const std::unique_ptr<viz::RenderPass>& input) { - return input->backdrop_filter_bounds.value_or(gfx::RRectF()); + return input->backdrop_filter_bounds; } static const gfx::ColorSpace& color_space(
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc index c382fa53..7f74ad6 100644 --- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc +++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -885,9 +885,10 @@ TEST_F(StructTraitsTest, RenderPassWithEmptySharedQuadStateList) { const RenderPassId render_pass_id = 3u; const gfx::Rect output_rect(45, 22, 120, 13); + const gfx::Rect damage_rect(56, 123, 19, 43); const gfx::Transform transform_to_root = gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0); - const gfx::Rect damage_rect(56, 123, 19, 43); + const base::Optional<gfx::RRectF> backdrop_filter_bounds; skcms_Matrix3x3 to_XYZD50 = SkNamedGamut::kXYZ; skcms_TransferFunction fn = {1, 0, 1, 0, 0, 0, 1}; gfx::ColorSpace color_space = gfx::ColorSpace::CreateCustom(to_XYZD50, fn); @@ -898,9 +899,9 @@ std::unique_ptr<RenderPass> input = RenderPass::Create(); input->SetAll(render_pass_id, output_rect, damage_rect, transform_to_root, cc::FilterOperations(), cc::FilterOperations(), - base::Optional<gfx::RRectF>(), color_space, - has_transparent_background, cache_render_pass, - has_damage_from_contributing_content, generate_mipmap); + backdrop_filter_bounds, color_space, has_transparent_background, + cache_render_pass, has_damage_from_contributing_content, + generate_mipmap); // Unlike the previous test, don't add any quads to the list; we need to // verify that the serialization code can deal with that. @@ -914,6 +915,7 @@ EXPECT_EQ(output_rect, output->output_rect); EXPECT_EQ(damage_rect, output->damage_rect); EXPECT_EQ(transform_to_root, output->transform_to_root_target); + EXPECT_EQ(backdrop_filter_bounds, output->backdrop_filter_bounds); EXPECT_EQ(has_transparent_background, output->has_transparent_background); EXPECT_EQ(color_space, output->color_space); }
diff --git a/storage/browser/fileapi/plugin_private_file_system_backend.cc b/storage/browser/fileapi/plugin_private_file_system_backend.cc index 01b440062..d13dc733 100644 --- a/storage/browser/fileapi/plugin_private_file_system_backend.cc +++ b/storage/browser/fileapi/plugin_private_file_system_backend.cc
@@ -26,7 +26,9 @@ #include "storage/browser/fileapi/file_system_operation_context.h" #include "storage/browser/fileapi/isolated_context.h" #include "storage/browser/fileapi/obfuscated_file_util.h" +#include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h" #include "storage/browser/fileapi/quota/quota_reservation.h" +#include "storage/browser/fileapi/sandbox_file_stream_writer.h" #include "storage/common/fileapi/file_system_util.h" namespace storage { @@ -187,12 +189,15 @@ } bool PluginPrivateFileSystemBackend::SupportsStreaming( - const storage::FileSystemURL& url) const { - return false; + const FileSystemURL& url) const { + // Streaming is required for incognito file systems in order to access + // memory-backed files. + DCHECK(CanHandleType(url.type())); + return file_system_options_.is_incognito(); } bool PluginPrivateFileSystemBackend::HasInplaceCopyImplementation( - storage::FileSystemType type) const { + FileSystemType type) const { return false; } @@ -203,6 +208,7 @@ int64_t max_bytes_to_read, const base::Time& expected_modification_time, FileSystemContext* context) const { + DCHECK(CanHandleType(url.type())); return FileStreamReader::CreateForFileSystemFile(context, url, offset, expected_modification_time); } @@ -212,7 +218,11 @@ const FileSystemURL& url, int64_t offset, FileSystemContext* context) const { - return std::unique_ptr<FileStreamWriter>(); + DCHECK(CanHandleType(url.type())); + + // Observers not supported by PluginPrivateFileSystemBackend. + return std::make_unique<SandboxFileStreamWriter>(context, url, offset, + UpdateObserverList()); } FileSystemQuotaUtil* PluginPrivateFileSystemBackend::GetQuotaUtil() { @@ -374,4 +384,11 @@ static_cast<AsyncFileUtilAdapter*>(file_util_.get())->sync_file_util()); } +ObfuscatedFileUtilMemoryDelegate* +PluginPrivateFileSystemBackend::obfuscated_file_util_memory_delegate() { + auto* file_util = obfuscated_file_util(); + DCHECK(file_util->is_incognito()); + return static_cast<ObfuscatedFileUtilMemoryDelegate*>(file_util->delegate()); +} + } // namespace storage
diff --git a/storage/browser/fileapi/plugin_private_file_system_backend.h b/storage/browser/fileapi/plugin_private_file_system_backend.h index 6fab28d..c85bfb9 100644 --- a/storage/browser/fileapi/plugin_private_file_system_backend.h +++ b/storage/browser/fileapi/plugin_private_file_system_backend.h
@@ -35,6 +35,7 @@ namespace storage { class ObfuscatedFileUtil; +class ObfuscatedFileUtilMemoryDelegate; class SpecialStoragePolicy; class WatcherManager; @@ -134,8 +135,10 @@ private: friend class content::PluginPrivateFileSystemBackendTest; + friend class SandboxFileStreamWriter; ObfuscatedFileUtil* obfuscated_file_util(); + ObfuscatedFileUtilMemoryDelegate* obfuscated_file_util_memory_delegate(); const base::FilePath& base_path() const { return base_path_; } scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
diff --git a/storage/browser/fileapi/sandbox_file_stream_writer.cc b/storage/browser/fileapi/sandbox_file_stream_writer.cc index ecf0040b..cf734fc1 100644 --- a/storage/browser/fileapi/sandbox_file_stream_writer.cc +++ b/storage/browser/fileapi/sandbox_file_stream_writer.cc
@@ -11,6 +11,7 @@ #include <utility> #include "base/bind.h" +#include "base/memory/weak_ptr.h" #include "base/sequenced_task_runner.h" #include "net/base/io_buffer.h" #include "net/base/net_errors.h" @@ -19,6 +20,8 @@ #include "storage/browser/fileapi/file_system_context.h" #include "storage/browser/fileapi/file_system_features.h" #include "storage/browser/fileapi/file_system_operation_runner.h" +#include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h" +#include "storage/browser/fileapi/plugin_private_file_system_backend.h" #include "storage/browser/quota/quota_manager_proxy.h" #include "storage/common/fileapi/file_system_util.h" @@ -143,9 +146,21 @@ if (file_system_context_->is_incognito() && base::FeatureList::IsEnabled(features::kEnableFilesystemInIncognito)) { + base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_delegate; + if (url_.type() == kFileSystemTypePluginPrivate) { + auto* backend = static_cast<PluginPrivateFileSystemBackend*>( + file_system_context_->GetFileSystemBackend( + kFileSystemTypePluginPrivate)); + memory_file_util_delegate = + backend->obfuscated_file_util_memory_delegate()->GetWeakPtr(); + } else { + memory_file_util_delegate = + file_system_context_->sandbox_delegate()->memory_file_util_delegate(); + } file_writer_ = FileStreamWriter::CreateForMemoryFile( - file_system_context_->sandbox_delegate()->memory_file_util_delegate(), - platform_path, initial_offset_, FileStreamWriter::OPEN_EXISTING_FILE); + memory_file_util_delegate, platform_path, initial_offset_, + FileStreamWriter::OPEN_EXISTING_FILE); + } else { file_writer_ = FileStreamWriter::CreateForLocalFile( file_system_context_->default_file_task_runner(), platform_path,
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json index 419480b6..3d30f2c 100644 --- a/testing/buildbot/chromium.gpu.fyi.json +++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -4460,52 +4460,6 @@ "isolated_scripts": [ { "args": [ - "pixel", - "--show-stdout", - "--browser=android-webview-instrumentation", - "--passthrough", - "-v", - "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc", - "--dont-restore-color-profile-after-test", - "--os-type", - "android", - "--build-revision", - "${got_revision}", - "--test-machine-name", - "${buildername}" - ], - "isolate_name": "telemetry_gpu_integration_test", - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "android_webview_pixel_skia_gold_test", - "precommit_args": [ - "--review-patch-issue", - "${patch_issue}", - "--review-patch-set", - "${patch_set}", - "--buildbucket-build-id", - "${buildbucket_build_id}" - ], - "should_retry_with_patch": false, - "swarming": { - "can_use_on_swarming_builders": true, - "containment_type": "AUTO", - "dimension_sets": [ - { - "device_os": "MMB29Q", - "device_os_type": "userdebug", - "device_type": "bullhead", - "os": "Android" - } - ], - "idempotent": false, - "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com" - } - }, - { - "args": [ "--gtest-benchmark-name=angle_perftests", "-v", "--one-frame-only",
diff --git a/testing/buildbot/chromium.webrtc.fyi.json b/testing/buildbot/chromium.webrtc.fyi.json index 30a7203..14b8accda 100644 --- a/testing/buildbot/chromium.webrtc.fyi.json +++ b/testing/buildbot/chromium.webrtc.fyi.json
@@ -146,7 +146,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -167,7 +167,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -186,7 +186,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -208,7 +208,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -227,7 +227,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -243,7 +243,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -262,7 +262,7 @@ "dimension_sets": [ { "cpu": "x86-64", - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] },
diff --git a/testing/buildbot/chromium.webrtc.json b/testing/buildbot/chromium.webrtc.json index a27c8db..dd27644 100644 --- a/testing/buildbot/chromium.webrtc.json +++ b/testing/buildbot/chromium.webrtc.json
@@ -107,7 +107,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -127,7 +127,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -161,7 +161,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -182,7 +182,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -203,7 +203,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -221,7 +221,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -236,7 +236,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] }, @@ -254,7 +254,7 @@ "can_use_on_swarming_builders": true, "dimension_sets": [ { - "os": "Ubuntu-14.04" + "os": "Ubuntu-16.04" } ] },
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json index 9d86511..f6fc2cd6 100644 --- a/testing/buildbot/chromium.win.json +++ b/testing/buildbot/chromium.win.json
@@ -1151,6 +1151,18 @@ } }, { + "experiment_percentage": 100, + "isolate_name": "polymer_tools_python_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "polymer_tools_python_unittests", + "swarming": { + "can_use_on_swarming_builders": true + } + }, + { "isolate_name": "telemetry_gpu_unittests", "merge": { "args": [], @@ -2968,6 +2980,24 @@ } }, { + "experiment_percentage": 100, + "isolate_name": "polymer_tools_python_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "polymer_tools_python_unittests", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "cpu": "x86-64", + "os": "Windows-10-15063" + } + ] + } + }, + { "isolate_name": "telemetry_gpu_unittests", "merge": { "args": [], @@ -6044,6 +6074,18 @@ } }, { + "experiment_percentage": 100, + "isolate_name": "polymer_tools_python_unittests", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "polymer_tools_python_unittests", + "swarming": { + "can_use_on_swarming_builders": true + } + }, + { "isolate_name": "telemetry_gpu_unittests", "merge": { "args": [],
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index 2db217c7..0f33a31b 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -2209,6 +2209,14 @@ "label": "//chrome/test:pixel_browser_tests", "type": "console_test_launcher", }, + "polymer_tools_python_unittests": { + "args": [ + "../../tools/polymer/run_polymer_tools_tests.py", + ], + "label": "//tools/polymer:polymer_tools_python_unittests", + "script": "//testing/scripts/run_isolated_script_test.py", + "type": "script", + }, "postmortem-metadata": { "label": "//v8:postmortem-metadata", "type": "additional_compile_target",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 169db18..ff7c9dca 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -154,35 +154,37 @@ }, }, - 'android_webview_gpu_telemetry_tests': { - 'pixel_skia': { - 'name': 'android_webview_pixel_skia_gold_test', - 'args': [ - '--dont-restore-color-profile-after-test', - '--os-type', - '${os_type}', - '--build-revision', - '${got_revision}', - '--test-machine-name', - '${buildername}', - ], - 'precommit_args': [ - # Gerrit issue ID - '--review-patch-issue', - '${patch_issue}', - # Patch set number - '--review-patch-set', - '${patch_set}', - # Buildbucket ID - '--buildbucket-build-id', - '${buildbucket_build_id}', - ], - 'swarming': { - 'service_account': 'chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com' - }, - 'telemetry_test_name': 'pixel', - }, - }, + # Temporarily disabled due to timeouts causing invalid test results. + # TODO(jmadill): Re-enable once timeout is resolved. http://crbug.com/987623 + # 'android_webview_gpu_telemetry_tests': { + # 'pixel_skia': { + # 'name': 'android_webview_pixel_skia_gold_test', + # 'args': [ + # '--dont-restore-color-profile-after-test', + # '--os-type', + # '${os_type}', + # '--build-revision', + # '${got_revision}', + # '--test-machine-name', + # '${buildername}', + # ], + # 'precommit_args': [ + # # Gerrit issue ID + # '--review-patch-issue', + # '${patch_issue}', + # # Patch set number + # '--review-patch-set', + # '${patch_set}', + # # Buildbucket ID + # '--buildbucket-build-id', + # '${buildbucket_build_id}', + # ], + # 'swarming': { + # 'service_account': 'chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com' + # }, + # 'telemetry_test_name': 'pixel', + # }, + # }, 'aura_gtests': { 'aura_unittests': {}, @@ -4845,6 +4847,9 @@ ], }, }, + 'polymer_tools_python_unittests': { + 'experiment_percentage': 100, + }, }, 'win_specific_xr_perf_tests': {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index 10f414ef..1ea6c721 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -2420,7 +2420,9 @@ 'gtest_tests': 'gpu_fyi_android_and_mac_gtests', 'isolated_scripts': 'gpu_angle_and_mobile_representative_perf_fyi_isolated_scripts', 'gpu_telemetry_tests': 'gpu_nexus5x_telemetry_tests', - 'android_webview_gpu_telemetry_tests': 'android_webview_gpu_telemetry_tests', + # Temporarily disabled due to timeouts causing invalid test results. + # TODO(jmadill): Re-enable once timeout is resolved. http://crbug.com/987623 + # 'android_webview_gpu_telemetry_tests': 'android_webview_gpu_telemetry_tests', }, }, 'Android FYI Release (Nexus 6)': { @@ -3898,7 +3900,7 @@ }, 'WebRTC Chromium Linux Tester': { 'mixins': [ - 'linux-trusty', + 'linux-xenial', ], 'test_suites': { 'gtest_tests': 'webrtc_chromium_tests_with_baremetal_tests', @@ -3997,7 +3999,7 @@ 'WebRTC Chromium FYI Linux Tester': { 'mixins': [ 'x86-64', - 'linux-trusty', + 'linux-xenial', ], 'test_suites': { 'gtest_tests': 'webrtc_chromium_gtests',
diff --git a/testing/scripts/run_isolated_script_test.py b/testing/scripts/run_isolated_script_test.py index f0d3e5e..faa0cad 100755 --- a/testing/scripts/run_isolated_script_test.py +++ b/testing/scripts/run_isolated_script_test.py
@@ -58,6 +58,7 @@ 'run_blinkpy_tests.py', 'metrics_python_tests.py', 'run_mac_signing_tests.py', + 'run_polymer_tools_tests.py', }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index d637d37..a0a69a3 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -610,26 +610,6 @@ ] } ], - "AutofillDoNotUploadSaveUnsupportedCards": [ - { - "platforms": [ - "android", - "chromeos", - "ios", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "AutofillDoNotUploadSaveUnsupportedCards" - ] - } - ] - } - ], "AutofillDynamicForms": [ { "platforms": [ @@ -5254,6 +5234,7 @@ "android", "chromeos", "ios", + "linux", "mac", "windows" ],
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index ec924c7..aee815d 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -326,7 +326,7 @@ "BlinkHeapConcurrentMarking", base::FEATURE_DISABLED_BY_DEFAULT}; // Enables concurrently sweeping Blink's heap. const base::Feature kBlinkHeapConcurrentSweeping{ - "BlinkHeapConcurrentSweeping", base::FEATURE_ENABLED_BY_DEFAULT}; + "BlinkHeapConcurrentSweeping", base::FEATURE_DISABLED_BY_DEFAULT}; // Enables incrementally marking Blink's heap. const base::Feature kBlinkHeapIncrementalMarking{ "BlinkHeapIncrementalMarking", base::FEATURE_ENABLED_BY_DEFAULT}; @@ -352,5 +352,16 @@ "VerifyHTMLFetchedFromAppCacheBeforeDelay", base::FEATURE_DISABLED_BY_DEFAULT}; +// Controls whether we use ThreadPriority::DISPLAY for renderer +// compositor & IO threads. +const base::Feature kBlinkCompositorUseDisplayThreadPriority { + "BlinkCompositorUseDisplayThreadPriority", +#if defined(OS_ANDROID) || defined(OS_CHROMEOS) + base::FEATURE_ENABLED_BY_DEFAULT +#else + base::FEATURE_DISABLED_BY_DEFAULT +#endif +}; + } // namespace features } // namespace blink
diff --git a/third_party/blink/common/messaging/transferable_message_struct_traits.cc b/third_party/blink/common/messaging/transferable_message_struct_traits.cc index e629d98..e82adb89 100644 --- a/third_party/blink/common/messaging/transferable_message_struct_traits.cc +++ b/third_party/blink/common/messaging/transferable_message_struct_traits.cc
@@ -28,6 +28,7 @@ blink::MessagePortChannel::CreateFromHandles(std::move(stream_channels)); out->has_user_gesture = data.has_user_gesture(); out->transfer_user_activation = data.transfer_user_activation(); + out->allow_autoplay = data.allow_autoplay(); return true; }
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 1a1cd29f..7ea1cd7 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -112,6 +112,9 @@ BLINK_COMMON_EXPORT extern const base::Feature kVerifyHTMLFetchedFromAppCacheBeforeDelay; +BLINK_COMMON_EXPORT extern const base::Feature + kBlinkCompositorUseDisplayThreadPriority; + } // namespace features } // namespace blink
diff --git a/third_party/blink/public/common/messaging/transferable_message.h b/third_party/blink/public/common/messaging/transferable_message.h index e532eadb..4ac7bd1 100644 --- a/third_party/blink/public/common/messaging/transferable_message.h +++ b/third_party/blink/public/common/messaging/transferable_message.h
@@ -47,6 +47,9 @@ // destination frame. bool transfer_user_activation = false; + // Whether the destination frame is allowed to autoplay. + bool allow_autoplay = false; + private: DISALLOW_COPY_AND_ASSIGN(TransferableMessage); };
diff --git a/third_party/blink/public/common/messaging/transferable_message_struct_traits.h b/third_party/blink/public/common/messaging/transferable_message_struct_traits.h index 0fd5213..21712cad 100644 --- a/third_party/blink/public/common/messaging/transferable_message_struct_traits.h +++ b/third_party/blink/public/common/messaging/transferable_message_struct_traits.h
@@ -54,6 +54,10 @@ return input.transfer_user_activation; } + static bool allow_autoplay(blink::TransferableMessage& input) { + return input.allow_autoplay; + } + static bool Read(blink::mojom::TransferableMessage::DataView data, blink::TransferableMessage* out); };
diff --git a/third_party/blink/public/mojom/messaging/transferable_message.mojom b/third_party/blink/public/mojom/messaging/transferable_message.mojom index 5cd699fb..585d6bd 100644 --- a/third_party/blink/public/mojom/messaging/transferable_message.mojom +++ b/third_party/blink/public/mojom/messaging/transferable_message.mojom
@@ -38,4 +38,6 @@ // Whether the state of user activation should be transferred to the // destination frame. bool transfer_user_activation; + // Whether the destination frame is allowed to autoplay. + bool allow_autoplay; };
diff --git a/third_party/blink/public/mojom/service_worker/controller_service_worker.mojom b/third_party/blink/public/mojom/service_worker/controller_service_worker.mojom index fa5b930..cfc0a85 100644 --- a/third_party/blink/public/mojom/service_worker/controller_service_worker.mojom +++ b/third_party/blink/public/mojom/service_worker/controller_service_worker.mojom
@@ -45,7 +45,7 @@ // TODO(kinuko): Add DispatchExtendableMessageEvent() as well. // Connects a new pipe to this controller instance. - Clone(ControllerServiceWorker& controller); + Clone(pending_receiver<ControllerServiceWorker> receiver); }; // A convenient struct that packs necessary information for a service worker @@ -58,7 +58,7 @@ blink.mojom.ControllerServiceWorkerMode.kNoController; // Non-null iff there is a controller and it has a fetch event handler. - ControllerServiceWorker? endpoint; + pending_remote<ControllerServiceWorker>? remote_controller; // The client being controlled, used for FetchEvent#clientId. The ID is // issued by the browser process for this receiving client, and would @@ -89,5 +89,5 @@ // Resets the controller connection with the given |controller|, this // can be called when a new controller is given, e.g. due to claim(). // |controller| can be null if it gets no controller. - UpdateController(ControllerServiceWorker? controller); + UpdateController(pending_remote<ControllerServiceWorker>? controller); };
diff --git a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom index 6044db6..612b97e7 100644 --- a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom +++ b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
@@ -76,7 +76,7 @@ // Cloned and passed to each controllee to directly dispatch events from the // controllees. - ControllerServiceWorker& controller_request; + pending_receiver<ControllerServiceWorker> controller_receiver; // Information to transfer installed scripts from the browser to the renderer. ServiceWorkerInstalledScriptsInfo? installed_scripts_info;
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_container.mojom b/third_party/blink/public/mojom/service_worker/service_worker_container.mojom index 3e73835a..5c07350 100644 --- a/third_party/blink/public/mojom/service_worker/service_worker_container.mojom +++ b/third_party/blink/public/mojom/service_worker/service_worker_container.mojom
@@ -82,8 +82,9 @@ // reported to the controllees, but the browser process is responsible for // properly handling the failure and recording the reasons. // |purpose| is used for UMA. - EnsureControllerServiceWorker(ControllerServiceWorker& controller, - ControllerServiceWorkerPurpose purpose); + EnsureControllerServiceWorker( + pending_receiver<ControllerServiceWorker> receiver, + ControllerServiceWorkerPurpose purpose); // Makes a new endpoint to this ServiceWorkerContainerHost. CloneContainerHost(ServiceWorkerContainerHost& container_host);
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index 55c2727..cb490ad 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2049,7 +2049,6 @@ kOpenerNavigationDownloadCrossOrigin = 2649, kV8RegExpMatchIsTrueishOnNonJSRegExp = 2650, kV8RegExpMatchIsFalseishOnJSRegExp = 2651, - kDownloadInAdFrameWithUserGesture = 2652, kDownloadInAdFrameWithoutUserGesture = 2653, kNavigatorAppVersion = 2654, kNavigatorDoNotTrack = 2655, @@ -2330,9 +2329,7 @@ kWebkitMarginAfterCollapseDiscard = 2945, kWebkitMarginAfterCollapseSeparate = 2946, kWebkitMarginAfterCollapseSeparateMaybeDoesSomething = 2947, - kCredentialManagerCreateWithUVM = 2948, kCredentialManagerGetWithUVM = 2949, - kCredentialManagerCreateSuccessWithUVM = 2950, kCredentialManagerGetSuccessWithUVM = 2951, kDiscardInputEventToMovingIframe = 2952, kSignedExchangeSubresourcePrefetch = 2953, @@ -2356,6 +2353,10 @@ kV8PointerEvent_GetPredictedEvents_Method = 2971, kScrollSnapOnViewportBreaks = 2972, kScrollPaddingOnViewportBreaks = 2973, + kDownloadInAdFrame = 2974, + kDownloadInSandbox = 2975, + kDownloadWithoutUserGesture = 2976, + kAutoplayDynamicDelegation = 2977, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/mojom/webauthn/authenticator.mojom b/third_party/blink/public/mojom/webauthn/authenticator.mojom index e18dded..d5dd46b5 100644 --- a/third_party/blink/public/mojom/webauthn/authenticator.mojom +++ b/third_party/blink/public/mojom/webauthn/authenticator.mojom
@@ -59,8 +59,8 @@ array<uint8> client_data_json; }; -// Content of user verification method extension returned by both -// Authenticator::MakeCredential and Authenticator::GetAssertion. +// Content of user verification method extension returned by +// Authenticator::GetAssertion. // See https://w3c.github.io/webauthn/#sctn-uvm-extension // Registry of the available values, see // https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-registry-v2.0-id-20180227.html#user-verification-methods
diff --git a/third_party/blink/public/platform/web_rtc_peer_connection_handler.h b/third_party/blink/public/platform/web_rtc_peer_connection_handler.h index 115a2953..f3481bf 100644 --- a/third_party/blink/public/platform/web_rtc_peer_connection_handler.h +++ b/third_party/blink/public/platform/web_rtc_peer_connection_handler.h
@@ -120,6 +120,7 @@ scoped_refptr<WebRTCICECandidate>) { return false; } + virtual void RestartIce() = 0; virtual void GetStats(const WebRTCStatsRequest&) = 0; // Gets stats using the new stats collection API, see // third_party/webrtc/api/stats/. These will replace the old stats collection
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h index 2000984..4566274 100644 --- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h +++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
@@ -52,7 +52,7 @@ // A handle for mojom::ServiceWorkerRequest. mojo::ScopedMessagePipeHandle request) = 0; virtual void BindControllerServiceWorker( - // A handle for mojom::ControllerServiceWorkerRequest. + // A handle for mojo::PendingReceiver<mojom::ControllerServiceWorker>. mojo::ScopedMessagePipeHandle request) = 0; virtual void OnNavigationPreloadResponse(
diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h index c3c23c3..ea92c27 100644 --- a/third_party/blink/public/web/web_local_frame.h +++ b/third_party/blink/public/web/web_local_frame.h
@@ -42,7 +42,7 @@ class WebContentSettingsClient; class WebDocument; class WebDoubleSize; -class WebDOMEvent; +class WebDOMMessageEvent; class WebLocalFrameClient; class WebFrameWidget; class WebInputMethodController; @@ -609,7 +609,7 @@ // Dispatches a message event on the current DOMWindow in this WebFrame. virtual void DispatchMessageEventWithOriginCheck( const WebSecurityOrigin& intended_target_origin, - const WebDOMEvent&, + const WebDOMMessageEvent&, bool has_user_gesture) = 0; // TEMP: Usage count for chrome.loadtimes deprecation.
diff --git a/third_party/blink/renderer/DEPS b/third_party/blink/renderer/DEPS index 0f1550d..cbce2d3 100644 --- a/third_party/blink/renderer/DEPS +++ b/third_party/blink/renderer/DEPS
@@ -17,9 +17,9 @@ "+base/macros.h", "+base/memory/ptr_util.h", "+base/memory/weak_ptr.h", + "+base/metrics/field_trial_params.h", "+base/metrics/histogram_functions.h", "+base/metrics/histogram_macros.h", - "+base/metrics/field_trial_params.h", "+base/metrics/single_sample_metrics.h", "+base/numerics/checked_math.h", "+base/numerics/clamped_math.h", @@ -42,10 +42,11 @@ "+base/time/default_tick_clock.h", "+base/time/time.h", "+base/timer/elapsed_timer.h", + "+base/timer/timer.h", "+base/trace_event/memory_dump_manager.h", "+base/trace_event/memory_dump_provider.h", "+base/trace_event/trace_event.h", - "+base/timer/timer.h", + "+base/util/type_safety/pass_key.h", "+build", "+components/crash/core/common/crash_key.h", "+services/network/public/mojom",
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc index f8b129f..8e6a54e2 100644 --- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc +++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
@@ -1474,10 +1474,10 @@ // when the checker was constructed, according to WTF::currentTime. class TimeIntervalChecker { public: - TimeIntervalChecker() : start_time_(WTF::CurrentTime()) {} + TimeIntervalChecker() : start_time_(base::Time::Now().ToDoubleT()) {} bool WasAliveAt(double time_in_milliseconds) { double time = time_in_milliseconds / kMsPerSecond; - return start_time_ <= time && time <= WTF::CurrentTime(); + return start_time_ <= time && time <= base::Time::Now().ToDoubleT(); } private:
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc b/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc index 300688e..5e25d58 100644 --- a/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc +++ b/third_party/blink/renderer/bindings/core/v8/v8_gc_for_context_dispose.cc
@@ -69,7 +69,7 @@ bool is_main_frame, WindowProxy::FrameReuseStatus frame_reuse_status) { did_dispose_context_for_main_frame_ = is_main_frame; - last_context_disposal_time_ = WTF::CurrentTime(); + last_context_disposal_time_ = base::Time::Now().ToDoubleT(); #if defined(OS_ANDROID) // When a low end device is in a low memory situation we should prioritize // memory use and trigger a V8+Blink GC. However, on Android, if the frame @@ -101,7 +101,7 @@ double max_time_since_last_context_disposal = .2; if (!did_dispose_context_for_main_frame_ && !pseudo_idle_timer_.IsActive() && last_context_disposal_time_ + max_time_since_last_context_disposal >= - WTF::CurrentTime()) { + base::Time::Now().ToDoubleT()) { pseudo_idle_timer_.StartOneShot(base::TimeDelta(), FROM_HERE); } }
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc index 75fd7fa7..f4f489e 100644 --- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc +++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_deserializer_for_modules.cc
@@ -13,10 +13,12 @@ #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/modules/crypto/crypto_key.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h" +#include "third_party/blink/renderer/modules/imagecapture/point_2d.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_certificate.h" #include "third_party/blink/renderer/modules/shapedetection/detected_barcode.h" #include "third_party/blink/renderer/modules/shapedetection/detected_face.h" #include "third_party/blink/renderer/modules/shapedetection/detected_text.h" +#include "third_party/blink/renderer/modules/shapedetection/landmark.h" namespace blink { @@ -81,8 +83,8 @@ return nullptr; corner_points.push_back(point); } - return DetectedBarcode::Create(raw_value, bounding_box, format, - corner_points); + return MakeGarbageCollected<DetectedBarcode>(raw_value, bounding_box, + format, corner_points); } case kDetectedFaceTag: { DOMRectReadOnly* bounding_box = ReadDOMRectReadOnly(); @@ -98,7 +100,7 @@ return nullptr; landmarks.push_back(landmark); } - return DetectedFace::Create(bounding_box, landmarks); + return MakeGarbageCollected<DetectedFace>(bounding_box, landmarks); } case kDetectedTextTag: { String raw_value; @@ -117,7 +119,8 @@ return nullptr; corner_points.push_back(point); } - return DetectedText::Create(raw_value, bounding_box, corner_points); + return MakeGarbageCollected<DetectedText>(raw_value, bounding_box, + corner_points); } default: break;
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc index 58f2d68..baf987bc 100644 --- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc +++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules.cc
@@ -16,6 +16,8 @@ #include "third_party/blink/renderer/bindings/modules/v8/v8_detected_text.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_dom_file_system.h" #include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_certificate.h" +#include "third_party/blink/renderer/modules/imagecapture/point_2d.h" +#include "third_party/blink/renderer/modules/shapedetection/landmark.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" namespace blink {
diff --git a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc index 5548998..6b54dd83 100644 --- a/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc +++ b/third_party/blink/renderer/bindings/modules/v8/serialization/v8_script_value_serializer_for_modules_test.cc
@@ -28,7 +28,9 @@ #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h" #include "third_party/blink/renderer/modules/crypto/crypto_result_impl.h" #include "third_party/blink/renderer/modules/filesystem/dom_file_system.h" +#include "third_party/blink/renderer/modules/imagecapture/point_2d.h" #include "third_party/blink/renderer/modules/peerconnection/rtc_certificate.h" +#include "third_party/blink/renderer/modules/shapedetection/landmark.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
diff --git a/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py b/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py index bac570c..8fc3a77 100644 --- a/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py +++ b/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py
@@ -30,7 +30,14 @@ def main(): options, filepaths = parse_options() - database = web_idl.build_database(filepaths) + # Incomplete IDL compiler produces a lot of errors, which break trybots. + # So, we ignore all the errors for the time being. + # TODO(bindings-team): Replace |report_error| with sys.exit once IDL + # compiler completes. + report_error = lambda message: None + + database = web_idl.build_database(filepaths=filepaths, + report_error=report_error) utilities.write_pickle_file(options.output, database)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/argument.py b/third_party/blink/renderer/bindings/scripts/web_idl/argument.py index d614068..4cd1651 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/argument.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/argument.py
@@ -33,6 +33,15 @@ self.idl_type = idl_type self.default_value = default_value + def make_copy(self): + return Argument.IR( + identifier=self.identifier, + index=self.index, + idl_type=self.idl_type, + default_value=self.default_value, + extended_attributes=self.extended_attributes.make_copy(), + code_generator_info=self.code_generator_info.make_copy()) + @property def idl_type(self): """
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py b/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py index 43d641e7..4ab3e8a 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/attribute.py
@@ -28,6 +28,7 @@ exposures=None, code_generator_info=None, component=None, + components=None, debug_info=None): assert isinstance(idl_type, IdlType) assert isinstance(is_static, bool) @@ -38,7 +39,8 @@ WithExtendedAttributes.__init__(self, extended_attributes) WithExposure.__init__(self, exposures) WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__(self, component) + WithComponent.__init__( + self, component=component, components=components) WithDebugInfo.__init__(self, debug_info) self.idl_type = idl_type @@ -46,6 +48,18 @@ self.is_readonly = is_readonly self.does_inherit_getter = does_inherit_getter + def make_copy(self): + return Attribute.IR( + identifier=self.identifier, + idl_type=self.idl_type, + is_static=self.is_static, + is_readonly=self.is_readonly, + does_inherit_getter=self.does_inherit_getter, + extended_attributes=self.extended_attributes.make_copy(), + code_generator_info=self.code_generator_info.make_copy(), + components=self.components, + debug_info=self.debug_info.make_copy()) + @property def idl_type(self): """
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/common.py b/third_party/blink/renderer/bindings/scripts/web_idl/common.py index 0cb07cd..c721703c 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/common.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/common.py
@@ -138,27 +138,25 @@ class Location(object): - def __init__(self, filepath=None, line_number=None, column_number=None): + def __init__(self, filepath=None, line_number=None, position=None): assert filepath is None or isinstance(filepath, str) assert line_number is None or isinstance(line_number, int) - assert column_number is None or isinstance(column_number, int) + assert position is None or isinstance(position, int) self._filepath = filepath self._line_number = line_number - self._column_number = column_number + self._position = position # Position number in a file def __str__(self): text = '{}'.format(self._filepath or '<<unknown path>>') if self._line_number: text += ':{}'.format(self._line_number) - if self._column_number: - text += ':{}'.format(self._column_number) return text def make_copy(self): return Location( filepath=self._filepath, line_number=self._line_number, - column_number=self._column_number) + position=self._position) @property def filepath(self): @@ -169,8 +167,8 @@ return self._line_number @property - def column_number(self): - return self._column_number + def position_in_file(self): + return self._position class DebugInfo(object):
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/constant.py b/third_party/blink/renderer/bindings/scripts/web_idl/constant.py index d7e14252..7dfa6796 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/constant.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/constant.py
@@ -26,6 +26,7 @@ exposures=None, code_generator_info=None, component=None, + components=None, debug_info=None): assert isinstance(value, ConstantValue) assert isinstance(idl_type, IdlType) @@ -34,12 +35,23 @@ WithExtendedAttributes.__init__(self, extended_attributes) WithExposure.__init__(self, exposures) WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__(self, component) + WithComponent.__init__( + self, component=component, components=components) WithDebugInfo.__init__(self, debug_info) self.value = value self.idl_type = idl_type + def make_copy(self): + return Constant.IR( + identifier=self.identifier, + value=self.value, + idl_type=self.idl_type, + extended_attributes=self.extended_attributes.make_copy(), + code_generator_info=self.code_generator_info.make_copy(), + components=self.components, + debug_info=self.debug_info.make_copy()) + @property def idl_type(self): """
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/database_builder.py b/third_party/blink/renderer/bindings/scripts/web_idl/database_builder.py index 8abc27d..4581612 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/database_builder.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/database_builder.py
@@ -9,16 +9,32 @@ from .reference import RefByIdFactory -def build_database(filepaths): - """Compiles IDL definitions in |filepaths| and builds a database.""" +def build_database(filepaths, report_error): + """ + Compiles IDL definitions in |filepaths| and builds a database. + + Args: + filepaths: Paths to files of AstGroup. + report_error: A callback that will be invoked when an error occurs due + to inconsistent/invalid IDL definitions. This callback takes an + error message of type str and return value is not used. It's okay + to terminate the program in this callback. + """ ir_map = IdentifierIRMap() ref_to_idl_type_factory = RefByIdFactory() ref_to_idl_def_factory = RefByIdFactory() idl_type_factory = IdlTypeFactory() load_and_register_idl_definitions( - filepaths, ir_map.register, ref_to_idl_type_factory.create, - ref_to_idl_def_factory.create, idl_type_factory) - compiler = IdlCompiler(ir_map, ref_to_idl_type_factory, - ref_to_idl_def_factory, idl_type_factory) + filepaths=filepaths, + register_ir=ir_map.register, + create_ref_to_idl_def=ref_to_idl_def_factory.create, + create_ref_to_idl_type=ref_to_idl_type_factory.create, + idl_type_factory=idl_type_factory) + compiler = IdlCompiler( + ir_map=ir_map, + ref_to_idl_def_factory=ref_to_idl_def_factory, + ref_to_idl_type_factory=ref_to_idl_type_factory, + idl_type_factory=idl_type_factory, + report_error=report_error) return compiler.build_database()
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py index 5211afb2..5cd456d6 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
@@ -9,6 +9,7 @@ from .idl_type import IdlTypeFactory from .reference import RefByIdFactory from .typedef import Typedef +from .user_defined_type import UserDefinedType class IdlCompiler(object): @@ -32,27 +33,33 @@ the details. """ - def __init__(self, ir_map, ref_to_idl_type_factory, ref_to_idl_def_factory, - idl_type_factory): + def __init__(self, ir_map, ref_to_idl_def_factory, ref_to_idl_type_factory, + idl_type_factory, report_error): """ Args: ir_map: IdentifierIRMap filled with the initial IRs of IDL definitions. - ref_to_idl_type_factory: RefByIdFactory that created all references - to IdlType. ref_to_idl_def_factory: RefByIdFactory that created all references to UserDefinedType. + ref_to_idl_type_factory: RefByIdFactory that created all references + to IdlType. idl_type_factory: IdlTypeFactory that created all instances of IdlType. + report_error: A callback that will be invoked when an error occurs + due to inconsistent/invalid IDL definitions. This callback + takes an error message of type str and return value is not used. + It's okay to terminate the program in this callback. """ assert isinstance(ir_map, IdentifierIRMap) - assert isinstance(ref_to_idl_type_factory, RefByIdFactory) assert isinstance(ref_to_idl_def_factory, RefByIdFactory) + assert isinstance(ref_to_idl_type_factory, RefByIdFactory) assert isinstance(idl_type_factory, IdlTypeFactory) + assert callable(report_error) self._ir_map = ir_map - self._ref_to_idl_type_factory = ref_to_idl_type_factory self._ref_to_idl_def_factory = ref_to_idl_def_factory + self._ref_to_idl_type_factory = ref_to_idl_type_factory self._idl_type_factory = idl_type_factory + self._report_error = report_error self._db = DatabaseBody() self._did_run = False # Run only once. @@ -68,13 +75,45 @@ self._create_public_objects() # Resolve references. - self._resolve_references_to_idl_type() self._resolve_references_to_idl_def() + self._resolve_references_to_idl_type() return Database(self._db) def _merge_partial_interfaces(self): - pass + def merge_partials(old_interfaces, partial_interfaces): + for identifier, old_interface in old_interfaces.iteritems(): + new_interface = old_interface.make_copy() + for partial in partial_interfaces.get(identifier, []): + new_interface.add_components(partial.components) + new_interface.debug_info.add_locations( + partial.debug_info.all_locations) + new_interface.attributes.extend([ + attribute.make_copy() + for attribute in partial.attributes + ]) + new_interface.constants.extend([ + constant.make_copy() for constant in partial.constants + ]) + new_interface.operations.extend([ + operation.make_copy() + for operation in partial.operations + ]) + + self._ir_map.add(new_interface) + + old_interfaces = self._ir_map.find_by_kind( + IdentifierIRMap.IR.Kind.INTERFACE) + partial_interfaces = self._ir_map.find_by_kind( + IdentifierIRMap.IR.Kind.PARTIAL_INTERFACE) + old_mixins = self._ir_map.find_by_kind( + IdentifierIRMap.IR.Kind.INTERFACE_MIXIN) + partial_mixins = self._ir_map.find_by_kind( + IdentifierIRMap.IR.Kind.PARTIAL_INTERFACE_MIXIN) + + self._ir_map.move_to_new_phase() + merge_partials(old_interfaces, partial_interfaces) + merge_partials(old_mixins, partial_mixins) def _merge_partial_dictionaries(self): old_dictionaries = self._ir_map.find_by_kind( @@ -109,20 +148,33 @@ for ir in typedef_irs.itervalues(): self._db.register(DatabaseBody.Kind.TYPEDEF, Typedef(ir)) - def _resolve_references_to_idl_type(self): - def resolve(ref): - # Resolve to stubs for the time being. - ref.set_target_object(False) - - self._ref_to_idl_type_factory.for_each(resolve) - def _resolve_references_to_idl_def(self): def resolve(ref): try: - ref.set_target_object( - self._db.find_by_identifier(ref.identifier)) + idl_def = self._db.find_by_identifier(ref.identifier) except KeyError: - # Resolve to stubs for the time being. - ref.set_target_object(False) + self._report_error("{}: Unresolved reference to {}".format( + ref.ref_own_debug_info.location, ref.identifier)) + idl_def = UserDefinedType(ref.identifier) # dummy stub + ref.set_target_object(idl_def) self._ref_to_idl_def_factory.for_each(resolve) + + def _resolve_references_to_idl_type(self): + def resolve(ref): + try: + idl_def = self._db.find_by_identifier(ref.identifier) + except KeyError: + self._report_error("{}: Unresolved reference to {}".format( + ref.ref_own_debug_info.location, ref.identifier)) + idl_def = UserDefinedType(ref.identifier) # dummy stub + if isinstance(idl_def, UserDefinedType): + idl_type = self._idl_type_factory.definition_type( + user_defined_type=idl_def) + elif isinstance(idl_def, Typedef): + idl_type = self._idl_type_factory.typedef_type(typedef=idl_def) + else: + assert False + ref.set_target_object(idl_type) + + self._ref_to_idl_type_factory.for_each(resolve)
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py b/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py index 360ed34..b5e1d713 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/idl_type.py
@@ -498,20 +498,18 @@ """ def __init__(self, - user_def_type, + user_defined_type, code_generator_info=None, debug_info=None, pass_key=None): - assert isinstance(user_def_type, UserDefinedType) + assert isinstance(user_defined_type, UserDefinedType) IdlType.__init__( self, code_generator_info=code_generator_info, debug_info=debug_info, pass_key=pass_key) - WithIdentifier.__init__(self, user_def_type.identifier) - self._definition = user_def_type - - # TODO(peria): Consider exposing access of |_definition| + WithIdentifier.__init__(self, user_defined_type.identifier) + self._definition = user_defined_type # IdlType overrides @property
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/interface.py b/third_party/blink/renderer/bindings/scripts/web_idl/interface.py index 45a71d4..df58e6b 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/interface.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/interface.py
@@ -40,12 +40,13 @@ constants=None, operations=None, iterable=None, - setlike=None, maplike=None, + setlike=None, extended_attributes=None, exposures=None, code_generator_info=None, component=None, + components=None, debug_info=None): assert isinstance(is_partial, bool) assert isinstance(is_mixin, bool) @@ -54,8 +55,8 @@ assert constants is None or isinstance(constants, (list, tuple)) assert operations is None or isinstance(operations, (list, tuple)) assert iterable is None or isinstance(iterable, Iterable) - assert setlike is None or isinstance(setlike, Setlike) assert maplike is None or isinstance(maplike, Maplike) + assert setlike is None or isinstance(setlike, Setlike) attributes = attributes or [] constants = constants or [] @@ -84,19 +85,38 @@ WithExtendedAttributes.__init__(self, extended_attributes) WithExposure.__init__(self, exposures) WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__(self, component) + WithComponent.__init__( + self, component=component, components=components) WithDebugInfo.__init__(self, debug_info) self.is_partial = is_partial self.is_mixin = is_mixin self.inherited = inherited - self.attrbiutes = list(attributes) + self.attributes = list(attributes) self.constants = list(constants) self.operations = list(operations) self.iterable = iterable self.maplike = maplike self.setlike = setlike + def make_copy(self): + return Interface.IR( + identifier=self.identifier, + is_partial=self.is_partial, + is_mixin=self.is_mixin, + inherited=self.inherited, + attributes=map(Attribute.IR.make_copy, self.attributes), + constants=map(Constant.IR.make_copy, self.constants), + operations=map(Operation.IR.make_copy, self.operations), + iterable=self.iterable, + maplike=self.maplike, + setlike=self.setlike, + extended_attributes=self.extended_attributes.make_copy(), + code_generator_info=self.code_generator_info.make_copy(), + components=self.components, + debug_info=self.debug_info.make_copy()) + + @property def inherited_interface(self): """
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py b/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py index b619dd32..ca9b094 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/ir_builder.py
@@ -27,9 +27,9 @@ from .values import DefaultValue -def load_and_register_idl_definitions(filepaths, register_ir, - create_ref_to_idl_type, - create_ref_to_idl_def, idl_type_factory): +def load_and_register_idl_definitions( + filepaths, register_ir, create_ref_to_idl_def, create_ref_to_idl_type, + idl_type_factory): """ Reads ASTs from |filepaths| and builds IRs from ASTs. @@ -37,10 +37,10 @@ filepaths: Paths to pickle files that store AST nodes. register_ir: A callback function that registers the argument as an IR. - create_ref_to_idl_type: A callback function that creates a reference - to an IdlType from the given identifier. create_ref_to_idl_def: A callback function that creates a reference to an IDL definition from the given identifier. + create_ref_to_idl_type: A callback function that creates a reference + to an IdlType from the given identifier. idl_type_factory: All IdlType instances will be created through this factory. """ @@ -49,8 +49,11 @@ for filepath in filepaths: asts_per_component = AstGroup.read_from_file(filepath) component = asts_per_component.component - builder = _IRBuilder(component, create_ref_to_idl_type, - create_ref_to_idl_def, idl_type_factory) + builder = _IRBuilder( + component=component, + create_ref_to_idl_def=create_ref_to_idl_def, + create_ref_to_idl_type=create_ref_to_idl_type, + idl_type_factory=idl_type_factory) for file_node in asts_per_component: assert file_node.GetClass() == 'File' @@ -59,25 +62,25 @@ class _IRBuilder(object): - def __init__(self, component, create_ref_to_idl_type, - create_ref_to_idl_def, idl_type_factory): + def __init__(self, component, create_ref_to_idl_def, + create_ref_to_idl_type, idl_type_factory): """ Args: component: A Component to which the built IRs are associated. - create_ref_to_idl_type: A callback function that creates a reference - to an IdlType from the given identifier. create_ref_to_idl_def: A callback function that creates a reference to an IDL definition from the given identifier. + create_ref_to_idl_type: A callback function that creates a reference + to an IdlType from the given identifier. idl_type_factory: All IdlType instances will be created through this factory. """ - assert callable(create_ref_to_idl_type) assert callable(create_ref_to_idl_def) + assert callable(create_ref_to_idl_type) assert isinstance(idl_type_factory, IdlTypeFactory) self._component = component - self._create_ref_to_idl_type = create_ref_to_idl_type self._create_ref_to_idl_def = create_ref_to_idl_def + self._create_ref_to_idl_type = create_ref_to_idl_type self._idl_type_factory = idl_type_factory def build_top_level_def(self, node): @@ -111,16 +114,12 @@ attributes = [] constants = [] operations = [] - property_handlers = [] for member in members: if isinstance(member, Attribute.IR): attributes.append(member) elif isinstance(member, Operation.IR): - assert member.identifier or member.is_property_handler if member.identifier: operations.append(member) - if member.is_property_handler: - property_handlers.append(member) elif isinstance(member, Constant.IR): constants.append(member) else: @@ -195,9 +194,6 @@ arguments=arguments, return_type=return_type, is_static=bool(node.GetProperty('STATIC')), - is_getter=bool(node.GetProperty('GETTER')), - is_setter=bool(node.GetProperty('SETTER')), - is_deleter=bool(node.GetProperty('DELETER')), extended_attributes=extended_attributes, component=self._component, debug_info=self._build_debug_info(node)) @@ -321,7 +317,7 @@ location=Location( filepath=node.GetProperty('FILENAME'), line_number=node.GetProperty('LINENO'), - column_number=node.GetProperty('POSITION'))) + position=node.GetProperty('POSITION'))) def _build_default_value(self, node): assert node.GetClass() == 'Default' @@ -333,7 +329,8 @@ def _build_inheritance(self, node): assert node.GetClass() == 'Inherit' - return self._create_ref_to_idl_def(node.GetName()) + return self._create_ref_to_idl_def(node.GetName(), + self._build_debug_info(node)) def _build_is_variadic_argument(self, node): # idl_parser produces the following tree to indicate an argument is @@ -439,7 +436,8 @@ def build_reference_type(node, extended_attributes): identifier = node.GetName() return self._idl_type_factory.reference_type( - ref_to_idl_type=self._create_ref_to_idl_type(identifier), + ref_to_idl_type=self._create_ref_to_idl_type( + identifier, self._build_debug_info(node)), is_optional=is_optional, extended_attributes=extended_attributes, debug_info=self._build_debug_info(node))
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/operation.py b/third_party/blink/renderer/bindings/scripts/web_idl/operation.py index 5916139..45d84a4 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/operation.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/operation.py
@@ -26,37 +26,39 @@ arguments, return_type, is_static=False, - is_getter=False, - is_setter=False, - is_deleter=False, extended_attributes=None, exposures=None, code_generator_info=None, component=None, + components=None, debug_info=None): assert isinstance(arguments, (list, tuple)) and all( isinstance(arg, Argument.IR) for arg in arguments) assert isinstance(return_type, IdlType) assert isinstance(is_static, bool) - assert isinstance(is_getter, bool) - assert isinstance(is_setter, bool) - assert isinstance(is_deleter, bool) - assert int(is_getter) + int(is_setter) + int(is_deleter) <= 1 WithIdentifier.__init__(self, identifier) WithExtendedAttributes.__init__(self, extended_attributes) WithExposure.__init__(self, exposures) WithCodeGeneratorInfo.__init__(self, code_generator_info) - WithComponent.__init__(self, component) + WithComponent.__init__( + self, component=component, components=components) WithDebugInfo.__init__(self, debug_info) self.arguments = list(arguments) self.return_type = return_type self.is_static = is_static - self.is_getter = is_getter - self.is_setter = is_setter - self.is_deleter = is_deleter - self.is_property_handler = is_getter or is_setter or is_deleter + + def make_copy(self): + return Operation.IR( + identifier=self.identifier, + arguments=map(Argument.IR.make_copy, self.arguments), + return_type=self.return_type, + is_static=self.is_static, + extended_attributes=self.extended_attributes.make_copy(), + code_generator_info=self.code_generator_info.make_copy(), + components=self.components, + debug_info=self.debug_info.make_copy()) @property def is_static(self):
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/reference.py b/third_party/blink/renderer/bindings/scripts/web_idl/reference.py index 4f54e08e..e86bf5d 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/reference.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/reference.py
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from .common import DebugInfo from .common import WithIdentifier @@ -98,9 +99,11 @@ def __init__(self, identifier, + debug_info=None, target_attrs=None, target_attrs_with_priority=None, pass_key=None): + assert debug_info is None or isinstance(debug_info, DebugInfo) assert pass_key is _REF_BY_ID_PASS_KEY Proxy.__init__( @@ -108,6 +111,12 @@ target_attrs=target_attrs, target_attrs_with_priority=target_attrs_with_priority) WithIdentifier.__init__(self, identifier) + self._ref_own_debug_info = debug_info + + @property + def ref_own_debug_info(self): + """This reference's own DebugInfo.""" + return self._ref_own_debug_info class RefByIdFactory(object): @@ -128,10 +137,17 @@ self._target_attrs = target_attrs self._target_attrs_with_priority = target_attrs_with_priority - def create(self, identifier): + def create(self, identifier, debug_info=None): + """ + Args: + identifier: An identifier to be resolved later. + debug_info: Where the reference is created, which is useful + especially when the reference is unresolvable. + """ assert not self._is_frozen ref = RefById( identifier, + debug_info=debug_info, target_attrs=self._target_attrs, target_attrs_with_priority=self._target_attrs_with_priority, pass_key=_REF_BY_ID_PASS_KEY)
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.cc b/third_party/blink/renderer/core/animation/compositor_animations.cc index ad9f756c..be4f5e1 100644 --- a/third_party/blink/renderer/core/animation/compositor_animations.cc +++ b/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -229,7 +229,7 @@ } const PropertySpecificKeyframeVector& keyframes = - keyframe_effect.GetPropertySpecificKeyframes(property); + *keyframe_effect.GetPropertySpecificKeyframes(property); DCHECK_GE(keyframes.size(), 2U); for (const auto& keyframe : keyframes) { if (keyframe->Composite() != EffectModel::kCompositeReplace && @@ -666,7 +666,7 @@ if (!std::isfinite(scale)) scale = 1.0; const PropertySpecificKeyframeVector& values = - effect.GetPropertySpecificKeyframes(property); + *effect.GetPropertySpecificKeyframes(property); compositor_target_property::Type target_property; std::unique_ptr<CompositorAnimationCurve> curve;
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc index 65cd329..358dfd0 100644 --- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc +++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -873,10 +873,10 @@ effect1->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style, nullptr); - EXPECT_EQ(2u, - effect1->GetPropertySpecificKeyframes(target_property1h).size()); - EXPECT_FALSE(effect1->GetPropertySpecificKeyframes(target_property1h)[0] - ->GetCompositorKeyframeValue()); + const auto& keyframes1 = + *effect1->GetPropertySpecificKeyframes(target_property1h); + EXPECT_EQ(2u, keyframes1.size()); + EXPECT_FALSE(keyframes1[0]->GetCompositorKeyframeValue()); EXPECT_EQ(1u, effect1->Properties().size()); EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *element_.Get(), animation1, *effect1) & @@ -896,10 +896,10 @@ effect2->SnapshotAllCompositorKeyframesIfNecessary(*inline_.Get(), *style, nullptr); - EXPECT_EQ(2u, - effect2->GetPropertySpecificKeyframes(target_property2h).size()); - EXPECT_TRUE(effect2->GetPropertySpecificKeyframes(target_property2h)[0] - ->GetCompositorKeyframeValue()); + const auto& keyframes2 = + *effect2->GetPropertySpecificKeyframes(target_property2h); + EXPECT_EQ(2u, keyframes2.size()); + EXPECT_TRUE(keyframes2[0]->GetCompositorKeyframeValue()); EXPECT_EQ(1u, effect2->Properties().size()); EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *inline_.Get(), animation2, *effect2) & @@ -922,10 +922,10 @@ effect3->SnapshotAllCompositorKeyframesIfNecessary(*element_.Get(), *style, nullptr); - EXPECT_EQ(2u, - effect3->GetPropertySpecificKeyframes(target_property3h).size()); - EXPECT_TRUE(effect3->GetPropertySpecificKeyframes(target_property3h)[0] - ->GetCompositorKeyframeValue()); + const auto& keyframes3 = + *effect3->GetPropertySpecificKeyframes(target_property3h); + EXPECT_EQ(2u, keyframes3.size()); + EXPECT_TRUE(keyframes3[0]->GetCompositorKeyframeValue()); EXPECT_EQ(1u, effect3->Properties().size()); EXPECT_TRUE(CheckCanStartEffectOnCompositor(timing_, *element_.Get(), animation3, *effect3) &
diff --git a/third_party/blink/renderer/core/animation/element_animations.cc b/third_party/blink/renderer/core/animation/element_animations.cc index 91375f7..375a6d8 100644 --- a/third_party/blink/renderer/core/animation/element_animations.cc +++ b/third_party/blink/renderer/core/animation/element_animations.cc
@@ -173,4 +173,16 @@ base_computed_style_ = nullptr; } +bool ElementAnimations::AnimationsPreserveAxisAlignment() const { + for (const auto& entry : animations_) { + const Animation& animation = *entry.key; + DCHECK(animation.effect()); + DCHECK(animation.effect()->IsKeyframeEffect()); + const KeyframeEffect& effect = *ToKeyframeEffect(animation.effect()); + if (!effect.AnimationsPreserveAxisAlignment()) + return false; + } + return true; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/animation/element_animations.h b/third_party/blink/renderer/core/animation/element_animations.h index 63743d1c..b1ed18d 100644 --- a/third_party/blink/renderer/core/animation/element_animations.h +++ b/third_party/blink/renderer/core/animation/element_animations.h
@@ -84,6 +84,8 @@ void UpdateBaseComputedStyle(const ComputedStyle*); void ClearBaseComputedStyle(); + bool AnimationsPreserveAxisAlignment() const; + void Trace(blink::Visitor*); private:
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect.cc b/third_party/blink/renderer/core/animation/keyframe_effect.cc index 4a39dd0e..3fb57f27 100644 --- a/third_party/blink/renderer/core/animation/keyframe_effect.cc +++ b/third_party/blink/renderer/core/animation/keyframe_effect.cc
@@ -32,6 +32,7 @@ #include "third_party/blink/renderer/bindings/core/v8/unrestricted_double_or_keyframe_effect_options.h" #include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" +#include "third_party/blink/renderer/core/animation/css/compositor_keyframe_transform.h" #include "third_party/blink/renderer/core/animation/effect_input.h" #include "third_party/blink/renderer/core/animation/element_animations.h" #include "third_party/blink/renderer/core/animation/sampled_effect.h" @@ -328,6 +329,47 @@ AnimationEffect::Trace(visitor); } +bool KeyframeEffect::AnimationsPreserveAxisAlignment( + const PropertyHandle& property) const { + const auto* keyframes = Model()->GetPropertySpecificKeyframes(property); + if (!keyframes) + return true; + for (const auto& keyframe : *keyframes) { + const auto* value = keyframe->GetCompositorKeyframeValue(); + if (!value) + continue; + DCHECK(value->IsTransform()); + const auto& transform_operations = + ToCompositorKeyframeTransform(value)->GetTransformOperations(); + if (!transform_operations.PreservesAxisAlignment()) + return false; + } + return true; +} + +namespace { + +static const size_t num_transform_properties = 4; + +const CSSProperty** TransformProperties() { + static const CSSProperty* kTransformProperties[num_transform_properties] = { + &GetCSSPropertyTransform(), &GetCSSPropertyScale(), + &GetCSSPropertyRotate(), &GetCSSPropertyTranslate()}; + return kTransformProperties; +} + +} // namespace + +bool KeyframeEffect::AnimationsPreserveAxisAlignment() const { + static const auto** properties = TransformProperties(); + for (size_t i = 0; i < num_transform_properties; i++) { + if (!AnimationsPreserveAxisAlignment(PropertyHandle(*properties[i]))) + return false; + } + + return true; +} + EffectModel::CompositeOperation KeyframeEffect::CompositeInternal() const { return model_->Composite(); } @@ -477,14 +519,14 @@ if (!target_->GetComputedStyle()) return false; - bool affects_transform = Affects(PropertyHandle(GetCSSPropertyTransform())) || - Affects(PropertyHandle(GetCSSPropertyScale())) || - Affects(PropertyHandle(GetCSSPropertyRotate())) || - Affects(PropertyHandle(GetCSSPropertyTranslate())); - if (HasActiveAnimationsOnCompositor()) { - if (target_->GetComputedStyle()->HasOffset() && affects_transform) - return true; + if (target_->GetComputedStyle()->HasOffset()) { + static const auto** properties = TransformProperties(); + for (size_t i = 0; i < num_transform_properties; i++) { + if (Affects(PropertyHandle(*properties[i]))) + return true; + } + } return HasMultipleTransformProperties(); }
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect.h b/third_party/blink/renderer/core/animation/keyframe_effect.h index 5c5c7e6..5d43efc2 100644 --- a/third_party/blink/renderer/core/animation/keyframe_effect.h +++ b/third_party/blink/renderer/core/animation/keyframe_effect.h
@@ -123,6 +123,8 @@ void Trace(blink::Visitor*) override; + bool AnimationsPreserveAxisAlignment() const; + private: EffectModel::CompositeOperation CompositeInternal() const; @@ -140,6 +142,8 @@ bool HasIncompatibleStyle() const; bool HasMultipleTransformProperties() const; + bool AnimationsPreserveAxisAlignment(const PropertyHandle&) const; + Member<Element> target_; Member<KeyframeEffectModelBase> model_; Member<SampledEffect> sampled_effect_;
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_model.h b/third_party/blink/renderer/core/animation/keyframe_effect_model.h index 970d670..2d2a2e60 100644 --- a/third_party/blink/renderer/core/animation/keyframe_effect_model.h +++ b/third_party/blink/renderer/core/animation/keyframe_effect_model.h
@@ -93,10 +93,13 @@ CompositeOperation Composite() const { return composite_; } void SetComposite(CompositeOperation composite) { composite_ = composite; } - const PropertySpecificKeyframeVector& GetPropertySpecificKeyframes( + const PropertySpecificKeyframeVector* GetPropertySpecificKeyframes( const PropertyHandle& property) const { EnsureKeyframeGroups(); - return keyframe_groups_->at(property)->Keyframes(); + const auto keyframe_group_iter = keyframe_groups_->find(property); + if (keyframe_group_iter == keyframe_groups_->end()) + return nullptr; + return &keyframe_group_iter->value->Keyframes(); } using KeyframeGroupMap =
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc b/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc index 5c5e1b0..e7f8668b 100644 --- a/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc +++ b/third_party/blink/renderer/core/animation/keyframe_effect_model_test.cc
@@ -162,7 +162,7 @@ EXPECT_TRUE(effect->SnapshotAllCompositorKeyframesIfNecessary( *element, *style, nullptr)); - return effect->GetPropertySpecificKeyframes(PropertyHandle(property_name)); + return *effect->GetPropertySpecificKeyframes(PropertyHandle(property_name)); } void ExpectProperty(CSSPropertyID property, @@ -610,7 +610,7 @@ auto* effect = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes); const StringPropertySpecificKeyframeVector& property_specific_keyframes = - effect->GetPropertySpecificKeyframes( + *effect->GetPropertySpecificKeyframes( PropertyHandle(GetCSSPropertyLeft())); EXPECT_EQ(3U, property_specific_keyframes.size()); EXPECT_DOUBLE_EQ(0.0, property_specific_keyframes[0]->Offset()); @@ -636,10 +636,9 @@ const CompositorKeyframeValue* value; // Compositor keyframe value should be empty before snapshot - value = effect - ->GetPropertySpecificKeyframes( - PropertyHandle(GetCSSPropertyOpacity()))[0] - ->GetCompositorKeyframeValue(); + const auto& empty_keyframes = *effect->GetPropertySpecificKeyframes( + PropertyHandle(GetCSSPropertyOpacity())); + value = empty_keyframes[0]->GetCompositorKeyframeValue(); EXPECT_FALSE(value); // Snapshot should update first time after construction @@ -654,10 +653,9 @@ *element, *style, nullptr)); // Compositor keyframe value should be available after snapshot - value = effect - ->GetPropertySpecificKeyframes( - PropertyHandle(GetCSSPropertyOpacity()))[0] - ->GetCompositorKeyframeValue(); + const auto& available_keyframes = *effect->GetPropertySpecificKeyframes( + PropertyHandle(GetCSSPropertyOpacity())); + value = available_keyframes[0]->GetCompositorKeyframeValue(); EXPECT_TRUE(value); EXPECT_TRUE(value->IsDouble()); } @@ -675,10 +673,9 @@ *element, *style, nullptr)); const CompositorKeyframeValue* value; - value = effect - ->GetPropertySpecificKeyframes( - PropertyHandle(GetCSSPropertyOpacity()))[0] - ->GetCompositorKeyframeValue(); + const auto& keyframes = *effect->GetPropertySpecificKeyframes( + PropertyHandle(GetCSSPropertyOpacity())); + value = keyframes[0]->GetCompositorKeyframeValue(); EXPECT_TRUE(value); EXPECT_TRUE(value->IsDouble()); @@ -689,10 +686,9 @@ // Snapshot should update after changing keyframes EXPECT_TRUE(effect->SnapshotAllCompositorKeyframesIfNecessary( *element, *style, nullptr)); - value = effect - ->GetPropertySpecificKeyframes( - PropertyHandle(GetCSSPropertyFilter()))[0] - ->GetCompositorKeyframeValue(); + const auto& updated_keyframes = *effect->GetPropertySpecificKeyframes( + PropertyHandle(GetCSSPropertyFilter())); + value = updated_keyframes[0]->GetCompositorKeyframeValue(); EXPECT_TRUE(value); EXPECT_TRUE(value->IsFilterOperations()); }
diff --git a/third_party/blink/renderer/core/animation/keyframe_effect_test.cc b/third_party/blink/renderer/core/animation/keyframe_effect_test.cc index 5e805cb..7545f7e9 100644 --- a/third_party/blink/renderer/core/animation/keyframe_effect_test.cc +++ b/third_party/blink/renderer/core/animation/keyframe_effect_test.cc
@@ -42,6 +42,31 @@ StringKeyframeVector()); } + // Returns a two-frame effect updated styles. + KeyframeEffect* GetTwoFrameEffect(const CSSPropertyID& property, + const String& value_a, + const String& value_b) { + StringKeyframeVector keyframes(2); + keyframes[0] = MakeGarbageCollected<StringKeyframe>(); + keyframes[0]->SetOffset(0.0); + keyframes[0]->SetCSSPropertyValue( + property, value_a, SecureContextMode::kInsecureContext, nullptr); + keyframes[1] = MakeGarbageCollected<StringKeyframe>(); + keyframes[1]->SetOffset(1.0); + keyframes[1]->SetCSSPropertyValue( + property, value_b, SecureContextMode::kInsecureContext, nullptr); + auto* model = MakeGarbageCollected<StringKeyframeEffectModel>(keyframes); + Timing timing; + auto* effect = MakeGarbageCollected<KeyframeEffect>(element, model, timing); + // Ensure GetCompositorKeyframeValue is updated which would normally happen + // when applying the animation styles. + UpdateAllLifecyclePhasesForTest(); + model->SnapshotAllCompositorKeyframesIfNecessary( + *element, *element->GetComputedStyle(), nullptr); + + return effect; + } + Persistent<Element> element; }; @@ -188,7 +213,7 @@ PropertyHandle property(GetCSSPropertyWidth()); const PropertySpecificKeyframeVector& keyframes = - effect->Model()->GetPropertySpecificKeyframes(property); + *effect->Model()->GetPropertySpecificKeyframes(property); EXPECT_EQ(EffectModel::kCompositeReplace, keyframes[0]->Composite()); EXPECT_EQ(EffectModel::kCompositeAdd, keyframes[1]->Composite()); @@ -469,4 +494,29 @@ CompositorAnimations::kTargetHasMultipleTransformProperties); } +TEST_F(KeyframeEffectTest, TranslationTransformsPreserveAxisAlignment) { + auto* effect = + GetTwoFrameEffect(CSSPropertyID::kTransform, "translate(10px, 10px)", + "translate(20px, 20px)"); + EXPECT_TRUE(effect->AnimationsPreserveAxisAlignment()); +} + +TEST_F(KeyframeEffectTest, ScaleTransformsPreserveAxisAlignment) { + auto* effect = + GetTwoFrameEffect(CSSPropertyID::kTransform, "scale(2)", "scale(3)"); + EXPECT_TRUE(effect->AnimationsPreserveAxisAlignment()); +} + +TEST_F(KeyframeEffectTest, RotationTransformsDoNotPreserveAxisAlignment) { + auto* effect = GetTwoFrameEffect(CSSPropertyID::kTransform, "rotate(10deg)", + "rotate(20deg)"); + + EXPECT_FALSE(effect->AnimationsPreserveAxisAlignment()); +} + +TEST_F(KeyframeEffectTest, RotationsDoNotPreserveAxisAlignment) { + auto* effect = GetTwoFrameEffect(CSSPropertyID::kRotate, "10deg", "20deg"); + EXPECT_FALSE(effect->AnimationsPreserveAxisAlignment()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/clipboard/data_object_item.cc b/third_party/blink/renderer/core/clipboard/data_object_item.cc index ff792028..0b4a308 100644 --- a/third_party/blink/renderer/core/clipboard/data_object_item.cc +++ b/third_party/blink/renderer/core/clipboard/data_object_item.cc
@@ -144,7 +144,8 @@ data->AppendBytes(png_data.data(), png_data.size()); const uint64_t length = data->length(); auto blob = BlobDataHandle::Create(std::move(data), length); - return File::Create("image.png", CurrentTimeMS(), std::move(blob)); + return File::Create("image.png", base::Time::Now().ToDoubleT() * 1000.0, + std::move(blob)); } }
diff --git a/third_party/blink/renderer/core/css/css_unset_value.h b/third_party/blink/renderer/core/css/css_unset_value.h index 56ff720e..91f23e06 100644 --- a/third_party/blink/renderer/core/css/css_unset_value.h +++ b/third_party/blink/renderer/core/css/css_unset_value.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_UNSET_VALUE_H_ #include "base/memory/scoped_refptr.h" +#include "base/util/type_safety/pass_key.h" #include "third_party/blink/renderer/core/css/css_value.h" #include "third_party/blink/renderer/platform/wtf/casting.h" @@ -19,9 +20,7 @@ public: static CSSUnsetValue* Create(); - // Only construct through MakeGarbageCollected for the initial value. Use - // Create() to get the pooled value. - CSSUnsetValue() : CSSValue(kUnsetClass) {} + explicit CSSUnsetValue(util::PassKey<CSSValuePool>) : CSSValue(kUnsetClass) {} String CustomCSSText() const; @@ -30,9 +29,6 @@ void TraceAfterDispatch(blink::Visitor* visitor) { CSSValue::TraceAfterDispatch(visitor); } - - private: - friend class ::blink::CSSValuePool; }; } // namespace cssvalue
diff --git a/third_party/blink/renderer/core/css/css_value_pool.cc b/third_party/blink/renderer/core/css/css_value_pool.cc index e6b18c2..8cfa8f7 100644 --- a/third_party/blink/renderer/core/css/css_value_pool.cc +++ b/third_party/blink/renderer/core/css/css_value_pool.cc
@@ -46,7 +46,7 @@ CSSValuePool::CSSValuePool() : inherited_value_(MakeGarbageCollected<CSSInheritedValue>()), initial_value_(MakeGarbageCollected<CSSInitialValue>()), - unset_value_(MakeGarbageCollected<CSSUnsetValue>()), + unset_value_(MakeGarbageCollected<CSSUnsetValue>(PassKey())), invalid_variable_value_(MakeGarbageCollected<CSSInvalidVariableValue>()), color_transparent_( MakeGarbageCollected<CSSColorValue>(Color::kTransparent)),
diff --git a/third_party/blink/renderer/core/css/css_value_pool.h b/third_party/blink/renderer/core/css/css_value_pool.h index 7fe38566..ce42ae5e 100644 --- a/third_party/blink/renderer/core/css/css_value_pool.h +++ b/third_party/blink/renderer/core/css/css_value_pool.h
@@ -28,6 +28,7 @@ #include "base/macros.h" #include "base/memory/scoped_refptr.h" +#include "base/util/type_safety/pass_key.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/css/css_color_value.h" #include "third_party/blink/renderer/core/css/css_custom_ident_value.h" @@ -51,6 +52,8 @@ : public GarbageCollectedFinalized<CSSValuePool> { public: + using PassKey = util::PassKey<CSSValuePool>; + // TODO(sashab): Make all the value pools store const CSSValues. static const int kMaximumCacheableIntegerValue = 255; using CSSColorValue = cssvalue::CSSColorValue;
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context.cc b/third_party/blink/renderer/core/display_lock/display_lock_context.cc index 07c432f4..3b3435a 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context.cc
@@ -145,6 +145,11 @@ ScriptPromise DisplayLockContext::acquire(ScriptState* script_state, DisplayLockOptions* options) { TRACE_EVENT0("blink", "DisplayLockContext::acquire()"); + if (!GetExecutionContext()) { + return GetRejectedPromise(script_state, + rejection_names::kExecutionContextDestroyed); + } + double timeout_ms = (options && options->hasTimeout()) ? options->timeout() : kDefaultLockTimeoutMs; @@ -264,10 +269,9 @@ } bool DisplayLockContext::CleanupAndRejectCommitIfNotConnected() { - // If we don't have an element or we're not connected, then the process of - // committing is the same as just unlocking the element. Early out if - // those conditions *don't* hold. - if (element_ && ConnectedToView()) + // If we're not connected, then the process of committing is the same as just + // unlocking the element. Early out if this conditions *doesn't* hold. + if (ConnectedToView()) return false; state_ = kUnlocked; @@ -809,7 +813,7 @@ // If we became disconnected for any reason, then we should reject the // update promise and go back to the locked state. - if (!element_ || !ConnectedToView()) { + if (!ConnectedToView()) { FinishUpdateResolver(kReject, rejection_names::kElementIsDisconnected); update_budget_.reset(); @@ -870,8 +874,10 @@ // can skip scheduling animation. If we do need to finalize update (ie reset // update_budget_), then we should still schedule an animation just in case // one was not scheduled. - if ((!ConnectedToView() && !update_budget_) || !document_->GetPage()) + if ((!ConnectedToView() && !update_budget_) || !document_ || + !document_->GetPage()) { return; + } // Schedule an animation to perform the lifecycle phases. document_->GetPage()->Animator().ScheduleVisualUpdate(document_->GetFrame()); @@ -899,7 +905,7 @@ void DisplayLockContext::TriggerTimeout() { // We might have started destroyed the element or started to shut down while // we're triggering a timeout. In that case, do nothing. - if (!element_ || !document_->Lifecycle().IsActive()) + if (!element_ || !document_ || !document_->Lifecycle().IsActive()) return; StartCommit(); } @@ -978,8 +984,7 @@ } bool DisplayLockContext::ConnectedToView() const { - DCHECK(element_); - return element_->isConnected() && document_->View(); + return element_ && document_ && element_->isConnected() && document_->View(); } // Scoped objects implementation
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc index 31d52cb..7c054b10 100644 --- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc +++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -1617,4 +1617,35 @@ // gracefully exit (and not crash). test::RunPendingTasks(); } + +class DisplayLockContextRenderingTest : public RenderingTest, + private ScopedDisplayLockingForTest { + public: + DisplayLockContextRenderingTest() + : RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()), + ScopedDisplayLockingForTest(true) {} +}; + +TEST_F(DisplayLockContextRenderingTest, FrameDocumentRemovedWhileAcquire) { + SetHtmlInnerHTML(R"HTML( + <iframe id="frame"></iframe> + )HTML"); + SetChildFrameHTML(R"HTML( + <style> + div { + contain: style layout; + } + </style> + <div id="target"></target> + )HTML"); + + auto* target = ChildDocument().getElementById("target"); + GetDocument().getElementById("frame")->remove(); + + auto* script_state = ToScriptStateForMainWorld(GetDocument().GetFrame()); + ScriptState::Scope scope(script_state); + DisplayLockOptions options; + target->getDisplayLockForBindings()->acquire(script_state, &options); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index 154a9dd..ac89475 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2339,23 +2339,23 @@ void Document::PropagateStyleToViewport() { DCHECK(InStyleRecalc()); - if (!documentElement()) - return; - HTMLElement* body = this->body(); + Element* document_element = this->documentElement(); + const ComputedStyle* document_element_style = + document_element && documentElement()->GetLayoutObject() + ? documentElement()->GetComputedStyle() + : nullptr; const ComputedStyle* body_style = - body ? body->EnsureComputedStyle() : nullptr; - const ComputedStyle* document_style = - documentElement()->EnsureComputedStyle(); + body && body->GetLayoutObject() ? body->GetComputedStyle() : nullptr; const ComputedStyle& viewport_style = GetLayoutView()->StyleRef(); scoped_refptr<ComputedStyle> new_viewport_style = ComputedStyle::Clone(viewport_style); bool changed = false; -#define PROPAGATE_FROM(source, getter, setter) \ - PROPAGATE_VALUE(source->getter(), getter, setter); +#define PROPAGATE_FROM(source, getter, setter, initial) \ + PROPAGATE_VALUE(source ? source->getter() : initial, getter, setter); #define PROPAGATE_VALUE(value, getter, setter) \ if ((new_viewport_style->getter()) != (value)) { \ @@ -2365,22 +2365,22 @@ // Writing mode and direction { - const ComputedStyle* direction_style = document_style; - if (body_style) - direction_style = body_style; - PROPAGATE_FROM(direction_style, GetWritingMode, SetWritingMode); - PROPAGATE_FROM(direction_style, Direction, SetDirection); + const ComputedStyle* direction_style = + body_style ? body_style : document_element_style; + PROPAGATE_FROM(direction_style, GetWritingMode, SetWritingMode, + WritingMode::kHorizontalTb); + PROPAGATE_FROM(direction_style, Direction, SetDirection, + TextDirection::kLtr); } // Background { - const ComputedStyle* background_style = document_style; + const ComputedStyle* background_style = document_element_style; // http://www.w3.org/TR/css3-background/#body-background // <html> root element with no background steals background from its first // <body> child. // Also see LayoutBoxModelObject::BackgroundTransfersToView() - if (IsHTMLHtmlElement(documentElement()) && - document_style->Display() != EDisplay::kNone && + if (body_style && IsHTMLHtmlElement(documentElement()) && IsHTMLBodyElement(body) && !background_style->HasBackground()) { background_style = body_style; } @@ -2389,7 +2389,7 @@ FillLayer background_layers(EFillLayerType::kBackground, true); EImageRendering image_rendering = EImageRendering::kAuto; - if (background_style->Display() != EDisplay::kNone) { + if (background_style) { background_color = background_style->VisitedDependentColor( GetCSSPropertyBackgroundColor()); background_layers = background_style->BackgroundLayers(); @@ -2424,98 +2424,115 @@ // Overflow { const ComputedStyle* overflow_style = nullptr; - Element* viewport_element = ViewportDefiningElement(); - DCHECK(viewport_element); - if (viewport_element == body) { - overflow_style = body_style; - } else { - DCHECK_EQ(viewport_element, documentElement()); - overflow_style = document_style; + if (Element* viewport_element = ViewportDefiningElement()) { + if (viewport_element == body) { + overflow_style = body_style; + } else { + DCHECK_EQ(viewport_element, documentElement()); + overflow_style = document_element_style; - // The body element has its own scrolling box, independent from the - // viewport. This is a bit of a weird edge case in the CSS spec that we - // might want to try to eliminate some day (eg. for ScrollTopLeftInterop - - // see http://crbug.com/157855). - if (body_style && !body_style->IsOverflowVisible()) - UseCounter::Count(*this, WebFeature::kBodyScrollsInAdditionToViewport); + // The body element has its own scrolling box, independent from the + // viewport. This is a bit of a weird edge case in the CSS spec that we + // might want to try to eliminate some day (eg. for ScrollTopLeftInterop + // - see http://crbug.com/157855). + if (body_style && !body_style->IsOverflowVisible()) { + UseCounter::Count(*this, + WebFeature::kBodyScrollsInAdditionToViewport); + } + } } - DCHECK(overflow_style); // TODO(954423, 952711): scroll-snap-* and overscroll-behavior (and most - // likely overflow-anchor) should be propagated from documet element and not - // the viewport defining element. + // likely overflow-anchor) should be propagated from the document element + // and not the viewport defining element. // We only propagate the properties related to snap container since viewport // defining element cannot be a snap area. - PROPAGATE_FROM(overflow_style, GetScrollSnapType, SetScrollSnapType); - PROPAGATE_FROM(overflow_style, ScrollPaddingTop, SetScrollPaddingTop); - PROPAGATE_FROM(overflow_style, ScrollPaddingRight, SetScrollPaddingRight); - PROPAGATE_FROM(overflow_style, ScrollPaddingBottom, SetScrollPaddingBottom); - PROPAGATE_FROM(overflow_style, ScrollPaddingLeft, SetScrollPaddingLeft); + PROPAGATE_FROM(overflow_style, GetScrollSnapType, SetScrollSnapType, + cc::ScrollSnapType()); + PROPAGATE_FROM(overflow_style, ScrollPaddingTop, SetScrollPaddingTop, + Length()); + PROPAGATE_FROM(overflow_style, ScrollPaddingRight, SetScrollPaddingRight, + Length()); + PROPAGATE_FROM(overflow_style, ScrollPaddingBottom, SetScrollPaddingBottom, + Length()); + PROPAGATE_FROM(overflow_style, ScrollPaddingLeft, SetScrollPaddingLeft, + Length()); + + PROPAGATE_FROM(overflow_style, OverscrollBehaviorX, SetOverscrollBehaviorX, + EOverscrollBehavior::kAuto); + PROPAGATE_FROM(overflow_style, OverscrollBehaviorY, SetOverscrollBehaviorY, + EOverscrollBehavior::kAuto); // Counts any time scroll snapping and scroll padding break if we change its // viewport propagation logic. Scroll snapping only breaks if body has // non-none snap type that is different from the document one. // TODO(952711): Remove once propagation logic change is complete. - bool snap_type_is_different = - !overflow_style->GetScrollSnapType().is_none && - (overflow_style->GetScrollSnapType() != - document_style->GetScrollSnapType()); - bool scroll_padding_is_different = - overflow_style->ScrollPaddingTop() != - document_style->ScrollPaddingTop() || - overflow_style->ScrollPaddingBottom() != - document_style->ScrollPaddingBottom() || - overflow_style->ScrollPaddingLeft() != - document_style->ScrollPaddingLeft() || - overflow_style->ScrollPaddingRight() != - document_style->ScrollPaddingRight(); + if (document_element_style && body_style) { + bool snap_type_is_different = + !body_style->GetScrollSnapType().is_none && + (body_style->GetScrollSnapType() != + document_element_style->GetScrollSnapType()); + bool scroll_padding_is_different = + body_style->ScrollPaddingTop() != + document_element_style->ScrollPaddingTop() || + body_style->ScrollPaddingBottom() != + document_element_style->ScrollPaddingBottom() || + body_style->ScrollPaddingLeft() != + document_element_style->ScrollPaddingLeft() || + body_style->ScrollPaddingRight() != + document_element_style->ScrollPaddingRight(); - if (snap_type_is_different) { - UseCounter::Count(*this, WebFeature::kScrollSnapOnViewportBreaks); - } - if (scroll_padding_is_different) { - UseCounter::Count(*this, WebFeature::kScrollPaddingOnViewportBreaks); + if (snap_type_is_different) { + UseCounter::Count(*this, WebFeature::kScrollSnapOnViewportBreaks); + } + if (scroll_padding_is_different) { + UseCounter::Count(*this, WebFeature::kScrollPaddingOnViewportBreaks); + } } - PROPAGATE_FROM(overflow_style, OverscrollBehaviorX, SetOverscrollBehaviorX); - PROPAGATE_FROM(overflow_style, OverscrollBehaviorY, SetOverscrollBehaviorY); + EOverflow overflow_x = EOverflow::kAuto; + EOverflow overflow_y = EOverflow::kAuto; + EOverflowAnchor overflow_anchor = EOverflowAnchor::kAuto; - EOverflow overflow_x = overflow_style->OverflowX(); - EOverflow overflow_y = overflow_style->OverflowY(); - EOverflowAnchor overflow_anchor = overflow_style->OverflowAnchor(); + if (overflow_style) { + overflow_x = overflow_style->OverflowX(); + overflow_y = overflow_style->OverflowY(); + overflow_anchor = overflow_style->OverflowAnchor(); + // Visible overflow on the viewport is meaningless, and the spec says to + // treat it as 'auto': + if (overflow_x == EOverflow::kVisible) + overflow_x = EOverflow::kAuto; + if (overflow_y == EOverflow::kVisible) + overflow_y = EOverflow::kAuto; + if (overflow_anchor == EOverflowAnchor::kVisible) + overflow_anchor = EOverflowAnchor::kAuto; - // Visible overflow on the viewport is meaningless, and the spec says to - // treat it as 'auto': - if (overflow_x == EOverflow::kVisible) - overflow_x = EOverflow::kAuto; - if (overflow_y == EOverflow::kVisible) - overflow_y = EOverflow::kAuto; - if (overflow_anchor == EOverflowAnchor::kVisible) - overflow_anchor = EOverflowAnchor::kAuto; + if (IsInMainFrame()) { + using OverscrollBehaviorType = + cc::OverscrollBehavior::OverscrollBehaviorType; + GetPage()->GetChromeClient().SetOverscrollBehavior( + *GetFrame(), + cc::OverscrollBehavior(static_cast<OverscrollBehaviorType>( + overflow_style->OverscrollBehaviorX()), + static_cast<OverscrollBehaviorType>( + overflow_style->OverscrollBehaviorY()))); + } + } PROPAGATE_VALUE(overflow_x, OverflowX, SetOverflowX) PROPAGATE_VALUE(overflow_y, OverflowY, SetOverflowY) PROPAGATE_VALUE(overflow_anchor, OverflowAnchor, SetOverflowAnchor); - - if (IsInMainFrame()) { - using OverscrollBehaviorType = - cc::OverscrollBehavior::OverscrollBehaviorType; - GetPage()->GetChromeClient().SetOverscrollBehavior( - *GetFrame(), - cc::OverscrollBehavior(static_cast<OverscrollBehaviorType>( - overflow_style->OverscrollBehaviorX()), - static_cast<OverscrollBehaviorType>( - overflow_style->OverscrollBehaviorY()))); - } } // Misc { - PROPAGATE_FROM(document_style, GetEffectiveTouchAction, - SetEffectiveTouchAction); - PROPAGATE_FROM(document_style, GetScrollBehavior, SetScrollBehavior); - PROPAGATE_FROM(document_style, DarkColorScheme, SetDarkColorScheme); + PROPAGATE_FROM(document_element_style, GetEffectiveTouchAction, + SetEffectiveTouchAction, TouchAction::kTouchActionAuto); + PROPAGATE_FROM(document_element_style, GetScrollBehavior, SetScrollBehavior, + kScrollBehaviorAuto); + PROPAGATE_FROM(document_element_style, DarkColorScheme, SetDarkColorScheme, + false); } if (changed) { @@ -3742,7 +3759,7 @@ if (!root_element) return nullptr; const ComputedStyle* root_style = root_element->GetComputedStyle(); - if (!root_style) + if (!root_style || root_style->IsEnsuredInDisplayNone()) return nullptr; if (body_element && root_style->IsOverflowVisible() && IsHTMLHtmlElement(*root_element)) @@ -5686,10 +5703,6 @@ CountUse(WebFeature::kCookieGet); - // FIXME: The HTML5 DOM spec states that this attribute can raise an - // InvalidStateError exception on getting if the Document has no - // browsing context. - if (!GetSecurityOrigin()->CanAccessCookies()) { if (IsSandboxed(WebSandboxFlags::kOrigin)) exception_state.ThrowSecurityError( @@ -5716,10 +5729,6 @@ UseCounter::Count(*this, WebFeature::kCookieSet); - // FIXME: The HTML5 DOM spec states that this attribute can raise an - // InvalidStateError exception on setting if the Document has no - // browsing context. - if (!GetSecurityOrigin()->CanAccessCookies()) { if (IsSandboxed(WebSandboxFlags::kOrigin)) exception_state.ThrowSecurityError( @@ -5859,9 +5868,10 @@ // FIXME: If this document came from the file system, the HTML5 // specificiation tells us to read the last modification date from the file // system. - if (!found_date) + if (!found_date) { date.SetMillisecondsSinceEpochForDateTime( - ConvertToLocalTime(CurrentTimeMS())); + ConvertToLocalTime(base::Time::Now().ToDoubleT() * 1000.0)); + } return String::Format("%02d/%02d/%04d %02d:%02d:%02d", date.Month() + 1, date.MonthDay(), date.FullYear(), date.Hour(), date.Minute(), date.Second());
diff --git a/third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h b/third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h index a2b872f5..a4a00d4 100644 --- a/third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h +++ b/third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h
@@ -5,7 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_DOM_HIGH_RES_TIME_STAMP_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_DOM_HIGH_RES_TIME_STAMP_H_ -#include "third_party/blink/renderer/platform/wtf/time.h" +#include "base/time/time.h" namespace blink {
diff --git a/third_party/blink/renderer/core/dom/element.idl b/third_party/blink/renderer/core/dom/element.idl index 84a5afb..a6ea0464 100644 --- a/third_party/blink/renderer/core/dom/element.idl +++ b/third_party/blink/renderer/core/dom/element.idl
@@ -144,6 +144,9 @@ // Display locking. Returns a display lock context. [RuntimeEnabled=DisplayLocking, ImplementedAs=getDisplayLockForBindings] readonly attribute DisplayLockContext displayLock; + + // Element Timing + [RuntimeEnabled=ElementTiming, Affects=Nothing, CEReactions, Reflect=elementtiming] attribute DOMString elementTiming; }; Element includes ParentNode;
diff --git a/third_party/blink/renderer/core/events/message_event.cc b/third_party/blink/renderer/core/events/message_event.cc index bf2ce4c..f941210 100644 --- a/third_party/blink/renderer/core/events/message_event.cc +++ b/third_party/blink/renderer/core/events/message_event.cc
@@ -126,7 +126,8 @@ EventTarget* source, Vector<MessagePortChannel> channels, UserActivation* user_activation, - bool transfer_user_activation) + bool transfer_user_activation, + bool allow_autoplay) : Event(event_type_names::kMessage, Bubbles::kNo, Cancelable::kNo), data_type_(kDataTypeSerializedScriptValue), data_as_serialized_script_value_( @@ -136,7 +137,8 @@ source_(source), channels_(std::move(channels)), user_activation_(user_activation), - transfer_user_activation_(transfer_user_activation) { + transfer_user_activation_(transfer_user_activation), + allow_autoplay_(allow_autoplay) { DCHECK(IsValidSource(source_.Get())); } @@ -216,7 +218,8 @@ EventTarget* source, MessagePortArray* ports, UserActivation* user_activation, - bool transfer_user_activation) { + bool transfer_user_activation, + bool allow_autoplay) { if (IsBeingDispatched()) return; @@ -233,6 +236,7 @@ is_ports_dirty_ = true; user_activation_ = user_activation; transfer_user_activation_ = transfer_user_activation; + allow_autoplay_ = allow_autoplay; } void MessageEvent::initMessageEvent(const AtomicString& type,
diff --git a/third_party/blink/renderer/core/events/message_event.h b/third_party/blink/renderer/core/events/message_event.h index 9a8b01f..13462d96 100644 --- a/third_party/blink/renderer/core/events/message_event.h +++ b/third_party/blink/renderer/core/events/message_event.h
@@ -79,10 +79,11 @@ const String& last_event_id = String(), EventTarget* source = nullptr, UserActivation* user_activation = nullptr, - bool transfer_user_activation = false) { + bool transfer_user_activation = false, + bool allow_autoplay = false) { return MakeGarbageCollected<MessageEvent>( std::move(data), origin, last_event_id, source, std::move(channels), - user_activation, transfer_user_activation); + user_activation, transfer_user_activation, allow_autoplay); } static MessageEvent* CreateError(const String& origin = String(), EventTarget* source = nullptr) { @@ -121,7 +122,8 @@ EventTarget* source, Vector<MessagePortChannel>, UserActivation* user_activation, - bool transfer_user_activation); + bool transfer_user_activation, + bool allow_autoplay); // Creates a "messageerror" event. MessageEvent(const String& origin, EventTarget* source); MessageEvent(const String& data, const String& origin); @@ -146,7 +148,8 @@ EventTarget* source, MessagePortArray*, UserActivation* user_activation, - bool transfer_user_activation = false); + bool transfer_user_activation = false, + bool allow_autoplay = false); void initMessageEvent(const AtomicString& type, bool bubbles, bool cancelable, @@ -165,6 +168,7 @@ bool isPortsDirty() const { return is_ports_dirty_; } UserActivation* userActivation() const { return user_activation_; } bool transferUserActivation() const { return transfer_user_activation_; } + bool allowAutoplay() const { return allow_autoplay_; } Vector<MessagePortChannel> ReleaseChannels() { return std::move(channels_); } @@ -231,6 +235,7 @@ Vector<MessagePortChannel> channels_; Member<UserActivation> user_activation_; bool transfer_user_activation_ = false; + bool allow_autoplay_ = false; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_dom_message_event.cc b/third_party/blink/renderer/core/exported/web_dom_message_event.cc index 3b15ac8..63d0f3ef 100644 --- a/third_party/blink/renderer/core/exported/web_dom_message_event.cc +++ b/third_party/blink/renderer/core/exported/web_dom_message_event.cc
@@ -92,7 +92,7 @@ Unwrap<MessageEvent>()->initMessageEvent( "message", false, false, std::move(msg.message), origin, "" /*lastEventId*/, window, ports, user_activation, - msg.transfer_user_activation); + msg.transfer_user_activation, msg.allow_autoplay); } WebString WebDOMMessageEvent::Origin() const { @@ -105,6 +105,7 @@ msg.ports = Unwrap<MessageEvent>()->ReleaseChannels(); msg.transfer_user_activation = Unwrap<MessageEvent>()->transferUserActivation(); + msg.allow_autoplay = Unwrap<MessageEvent>()->allowAutoplay(); UserActivation* user_activation = Unwrap<MessageEvent>()->userActivation(); TransferableMessage transferable_msg = ToTransferableMessage(std::move(msg)); if (user_activation) {
diff --git a/third_party/blink/renderer/core/exported/web_frame_serializer.cc b/third_party/blink/renderer/core/exported/web_frame_serializer.cc index 84e4e65..ded2118 100644 --- a/third_party/blink/renderer/core/exported/web_frame_serializer.cc +++ b/third_party/blink/renderer/core/exported/web_frame_serializer.cc
@@ -228,7 +228,8 @@ // srcset prevents the problem. Long term we should make sure to MHTML plays // nicely with srcset. if (IsHTMLImageElement(element) && - attribute.LocalName() == html_names::kSrcsetAttr) { + (attribute.LocalName() == html_names::kSrcsetAttr || + attribute.LocalName() == html_names::kSizesAttr)) { return true; }
diff --git a/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc b/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc index 82bbb45..7dba928 100644 --- a/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc +++ b/third_party/blink/renderer/core/exported/web_frame_serializer_sanitization_test.cc
@@ -227,8 +227,17 @@ String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "img_srcset.html"); - // srcset attribute should be skipped. + // srcset and sizes attributes should be skipped. EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcset=")); + EXPECT_EQ(WTF::kNotFound, mhtml.Find("sizes=")); + + // src attribute with original URL should be preserved. + EXPECT_EQ(2, + MatchSubstring(mhtml, "src=3D\"http://www.test.com/1x.png\"", 34)); + + // The image resource for original URL should be attached. + EXPECT_NE(WTF::kNotFound, + mhtml.Find("Content-Location: http://www.test.com/1x.png")); // Width and height attributes should be set when none is present in <img>. EXPECT_NE(WTF::kNotFound, @@ -248,8 +257,17 @@ String mhtml = GenerateMHTMLFromHtml("http://www.test.com", "img_srcset.html"); - // srcset attribute should be skipped. + // srcset and sizes attributes should be skipped. EXPECT_EQ(WTF::kNotFound, mhtml.Find("srcset=")); + EXPECT_EQ(WTF::kNotFound, mhtml.Find("sizes=")); + + // src attribute with original URL should be preserved. + EXPECT_EQ(2, + MatchSubstring(mhtml, "src=3D\"http://www.test.com/1x.png\"", 34)); + + // The image resource for original URL should be attached. + EXPECT_NE(WTF::kNotFound, + mhtml.Find("Content-Location: http://www.test.com/1x.png")); // New width and height attributes should not be set. EXPECT_NE(WTF::kNotFound, mhtml.Find("id=3D\"i1\">"));
diff --git a/third_party/blink/renderer/core/exported/web_layer_test.cc b/third_party/blink/renderer/core/exported/web_layer_test.cc index a165021a..915e9891 100644 --- a/third_party/blink/renderer/core/exported/web_layer_test.cc +++ b/third_party/blink/renderer/core/exported/web_layer_test.cc
@@ -1044,4 +1044,37 @@ EXPECT_FALSE(effect_node->HasRenderSurface()); } +TEST_P(WebLayerListSimTest, NoRenderSurfaceWithAxisAlignedTransformAnimation) { + InitializeWithHTML(R"HTML( + <!DOCTYPE html> + <style> + @keyframes translation { + 0% { transform: translate(10px, 11px); } + 100% { transform: translate(20px, 21px); } + } + .animate { + animation-name: translation; + animation-duration: 1s; + width: 100px; + height: 100px; + overflow: hidden; + } + .compchild { + height: 200px; + width: 10px; + background: lightblue; + will-change: transform; + } + </style> + <div class="animate"><div class="compchild"></div></div> + )HTML"); + Compositor().BeginFrame(); + // No effect node with kClipAxisAlignment should be created because the + // animation is axis-aligned. + for (const auto& effect_node : GetPropertyTrees()->effect_tree.nodes()) { + EXPECT_NE(cc::RenderSurfaceReason::kClipAxisAlignment, + effect_node.render_surface_reason); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index 6a75713..414e7de2 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3286,13 +3286,17 @@ root_graphics_layer_ = nullptr; visual_viewport_container_layer_ = nullptr; root_layer_ = nullptr; - - // This path is called when the local main frame is being detached, which - // will destroy the WebWidgetClient in the future, but does not right now. - // TODO(crbug.com/419087): There should be no need to clean up the - // WebWidgetClient once the RenderWidget is destroyed with the main frame. AsWidget().client->SetRootLayer(nullptr); AsWidget().client->RegisterViewportLayers(cc::ViewportLayers()); + + // When the document in an already-attached main frame is being replaced by + // a navigation then SetRootGraphicsLayer(nullptr) will be called. Since we + // are navigating, defer BeginMainFrames until the new document is ready for + // them. + // + // TODO(crbug.com/936696): This should not be needed once we always swap + // frames when swapping documents. + scoped_defer_main_frame_update_ = AsWidget().client->DeferMainFrameUpdate(); } }
diff --git a/third_party/blink/renderer/core/fileapi/file.cc b/third_party/blink/renderer/core/fileapi/file.cc index c53c0e3..28bd8a4c 100644 --- a/third_party/blink/renderer/core/fileapi/file.cc +++ b/third_party/blink/renderer/core/fileapi/file.cc
@@ -134,7 +134,7 @@ if (options->hasLastModified()) last_modified = static_cast<double>(options->lastModified()); else - last_modified = CurrentTimeMS(); + last_modified = base::Time::Now().ToDoubleT() * 1000.0; DCHECK(options->hasEndings()); bool normalize_line_endings_to_native = options->endings() == "native"; if (normalize_line_endings_to_native) @@ -301,7 +301,7 @@ IsValidFileTime(modification_time_ms)) return modification_time_ms; - return CurrentTimeMS(); + return base::Time::Now().ToDoubleT() * 1000.0; } int64_t File::lastModified() const { @@ -310,7 +310,7 @@ // The getter should return the current time when the last modification time // isn't known. if (!IsValidFileTime(modified_date)) - modified_date = CurrentTimeMS(); + modified_date = base::Time::Now().ToDoubleT() * 1000.0; // lastModified returns a number, not a Date instance, // http://dev.w3.org/2006/webapi/FileAPI/#file-attrs @@ -323,7 +323,7 @@ // The getter should return the current time when the last modification time // isn't known. if (!IsValidFileTime(modified_date)) - modified_date = CurrentTimeMS(); + modified_date = base::Time::Now().ToDoubleT() * 1000.0; // lastModifiedDate returns a Date instance, // http://www.w3.org/TR/FileAPI/#dfn-lastModifiedDate
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc index c7f11d4..ba49eb0 100644 --- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc +++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -843,10 +843,11 @@ } bool ContentSecurityPolicy::AllowTrustedTypeAssignmentFailure( - const String& message) const { + const String& message, + const String& sample) const { bool allow = true; for (const auto& policy : policies_) { - allow &= policy->AllowTrustedTypeAssignmentFailure(message); + allow &= policy->AllowTrustedTypeAssignmentFailure(message, sample); } return allow; }
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h index 75f8137..cb2b5a4 100644 --- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h +++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -340,7 +340,8 @@ // Determine whether to enforce the assignment failure. Also handle reporting. // Returns whether enforcing Trusted Types CSP directives are present. - bool AllowTrustedTypeAssignmentFailure(const String& message) const; + bool AllowTrustedTypeAssignmentFailure(const String& message, + const String& sample = String()) const; void UsesScriptHashAlgorithms(uint8_t content_security_policy_hash_algorithm); void UsesStyleHashAlgorithms(uint8_t content_security_policy_hash_algorithm);
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc index 8fb0a2e..ff18a796 100644 --- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc +++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -183,7 +183,8 @@ const String& console_message, const KURL& blocked_url, ResourceRequest::RedirectStatus redirect_status, - ContentSecurityPolicy::ViolationType violation_type) const { + ContentSecurityPolicy::ViolationType violation_type, + const String& sample) const { String message = IsReportOnly() ? "[Report Only] " + console_message : console_message; policy_->LogToConsole( @@ -194,7 +195,9 @@ header_type_, violation_type, std::unique_ptr<SourceLocation>(), nullptr, // localFrame - redirect_status); + redirect_status, + nullptr, // Element* + sample); } void CSPDirectiveList::ReportViolationWithFrame( @@ -327,7 +330,8 @@ } bool CSPDirectiveList::AllowTrustedTypeAssignmentFailure( - const String& message) const { + const String& message, + const String& sample) const { if (!trusted_types_) return true; @@ -335,7 +339,7 @@ ContentSecurityPolicy::DirectiveType::kTrustedTypes), ContentSecurityPolicy::DirectiveType::kTrustedTypes, message, KURL(), RedirectStatus::kFollowedRedirect, - ContentSecurityPolicy::kTrustedTypesViolation); + ContentSecurityPolicy::kTrustedTypesViolation, sample); return IsReportOnly(); }
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.h b/third_party/blink/renderer/core/frame/csp/csp_directive_list.h index fc9f93e2b..264b22da 100644 --- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.h +++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
@@ -100,7 +100,8 @@ ResourceRequest::RedirectStatus, SecurityViolationReportingPolicy) const; - bool AllowTrustedTypeAssignmentFailure(const String& message) const; + bool AllowTrustedTypeAssignmentFailure(const String& message, + const String& sample) const; bool StrictMixedContentChecking() const { return strict_mixed_content_checking_enforced_; @@ -200,7 +201,8 @@ const KURL& blocked_url, ResourceRequest::RedirectStatus, ContentSecurityPolicy::ViolationType violation_type = - ContentSecurityPolicy::kURLViolation) const; + ContentSecurityPolicy::kURLViolation, + const String& sample = String()) const; void ReportViolationWithFrame(const String& directive_text, const ContentSecurityPolicy::DirectiveType, const String& console_message,
diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc index 9fbcf595..8cf2031 100644 --- a/third_party/blink/renderer/core/frame/dom_window.cc +++ b/third_party/blink/renderer/core/frame/dom_window.cc
@@ -465,15 +465,26 @@ if (options->includeUserActivation()) user_activation = UserActivation::CreateSnapshot(source); + LocalFrame* source_frame = source->GetFrame(); + + bool allow_autoplay = false; + if (RuntimeEnabledFeatures::ExperimentalAutoplayDynamicDelegationEnabled( + GetExecutionContext()) && + LocalFrame::HasTransientUserActivation(source_frame) && + options->hasAllow()) { + Vector<String> policy_entry_list; + options->allow().Split(' ', policy_entry_list); + allow_autoplay = policy_entry_list.Contains("autoplay"); + } + MessageEvent* event = MessageEvent::Create( std::move(channels), std::move(message), source_origin, String(), source, - user_activation, options->transferUserActivation()); + user_activation, options->transferUserActivation(), allow_autoplay); // Transfer user activation state in the source's renderer when // |transferUserActivation| is true. // TODO(lanwei): we should execute the below code after the post task fires // (for both local and remote posting messages). - LocalFrame* source_frame = source->GetFrame(); if (RuntimeEnabledFeatures::UserActivationPostMessageTransferEnabled() && options->transferUserActivation() && LocalFrame::HasTransientUserActivation(source_frame)) {
diff --git a/third_party/blink/renderer/core/frame/frame_serializer.cc b/third_party/blink/renderer/core/frame/frame_serializer.cc index 8bea126..69df9b1 100644 --- a/third_party/blink/renderer/core/frame/frame_serializer.cc +++ b/third_party/blink/renderer/core/frame/frame_serializer.cc
@@ -382,13 +382,20 @@ } if (const auto* image = ToHTMLImageElementOrNull(element)) { - // ImageSourceURL() works for both scenarios: - // * parent element is <picture>: best fit image URL from sibling source - // element - // * single <img> element: image url contained in href attribute - KURL image_url = document.CompleteURL(image->ImageSourceURL()); + AtomicString image_url_value; + const Element* parent = element.parentElement(); + if (parent && IsHTMLPictureElement(parent)) { + // If parent element is <picture>, use ImageSourceURL() to get best fit + // image URL from sibling source. + image_url_value = image->ImageSourceURL(); + } else { + // Otherwise, it is single <img> element. We should get image url + // contained in href attribute. ImageSourceURL() may return a different + // URL from srcset attribute. + image_url_value = image->getAttribute(html_names::kSrcAttr); + } ImageResourceContent* cached_image = image->CachedImage(); - AddImageToResources(cached_image, image_url); + AddImageToResources(cached_image, document.CompleteURL(image_url_value)); } else if (const auto* input = ToHTMLInputElementOrNull(element)) { if (input->type() == input_type_names::kImage && input->ImageLoader()) { KURL image_url = input->Src();
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index a0e9ad3..3215cba 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -114,7 +114,7 @@ #include "third_party/blink/public/web/web_console_message.h" #include "third_party/blink/public/web/web_content_capture_client.h" #include "third_party/blink/public/web/web_document.h" -#include "third_party/blink/public/web/web_dom_event.h" +#include "third_party/blink/public/web/web_dom_message_event.h" #include "third_party/blink/public/web/web_form_element.h" #include "third_party/blink/public/web/web_frame_owner_properties.h" #include "third_party/blink/public/web/web_history_item.h" @@ -2244,7 +2244,7 @@ void WebLocalFrameImpl::DispatchMessageEventWithOriginCheck( const WebSecurityOrigin& intended_target_origin, - const WebDOMEvent& event, + const WebDOMMessageEvent& event, bool has_user_gesture) { DCHECK(!event.IsNull()); @@ -2258,15 +2258,27 @@ UserGestureIndicator::SetWasForwardedCrossProcess(); } - // Transfer user activation state in the target's renderer when - // |transferUserActivation| is true. MessageEvent* msg_event = static_cast<MessageEvent*>((Event*)event); Frame* source_frame = nullptr; if (msg_event->source() && msg_event->source()->ToDOMWindow()) source_frame = msg_event->source()->ToDOMWindow()->GetFrame(); - if (RuntimeEnabledFeatures::UserActivationPostMessageTransferEnabled() && - msg_event->transferUserActivation()) { + + // Transfer user activation state in the target's renderer when + // |transferUserActivation| is true. + // + // Also do the same as an ad-hoc solution to allow the origin trial of dynamic + // delegation of autoplay capability through postMessages. Note that we + // skipped updating the user activation states in all other copies of the + // frame tree in this case because this is a temporary hack. + // + // TODO(mustaq): Remove the ad-hoc solution when the API shape is + // ready. crbug.com/985914 + if ((RuntimeEnabledFeatures::UserActivationPostMessageTransferEnabled() && + msg_event->transferUserActivation()) || + msg_event->allowAutoplay()) { GetFrame()->TransferUserActivationFrom(source_frame); + if (msg_event->allowAutoplay()) + UseCounter::Count(GetDocument(), WebFeature::kAutoplayDynamicDelegation); } GetFrame()->DomWindow()->DispatchMessageEventWithOriginCheck(
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h index 744a3f1..c9a5d1d 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -237,7 +237,7 @@ void DispatchMessageEventWithOriginCheck( const WebSecurityOrigin& intended_target_origin, - const WebDOMEvent&, + const WebDOMMessageEvent&, bool has_user_gesture) override; WebRect GetSelectionBoundsRectForTesting() const override;
diff --git a/third_party/blink/renderer/core/frame/window_post_message_options.idl b/third_party/blink/renderer/core/frame/window_post_message_options.idl index e078ea3..b82c6f7b 100644 --- a/third_party/blink/renderer/core/frame/window_post_message_options.idl +++ b/third_party/blink/renderer/core/frame/window_post_message_options.idl
@@ -9,4 +9,6 @@ [RuntimeEnabled = UserActivationPostMessageTransfer] boolean transferUserActivation = false; + [OriginTrialEnabled = + ExperimentalAutoplayDynamicDelegation] DOMString allow = ""; };
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc index d6ec4af..0c2745c 100644 --- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc +++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -129,6 +129,15 @@ } } +SkColorType GetColorTypeForConversion(SkColorType color_type) { + if (color_type == kRGBA_8888_SkColorType || + color_type == kBGRA_8888_SkColorType) { + return color_type; + } + + return kN32_SkColorType; +} + } // anonymous namespace CanvasAsyncBlobCreator::CanvasAsyncBlobCreator( @@ -191,7 +200,9 @@ // covnert to the requested color space and pixel format. if (function_type_ != kHTMLCanvasConvertToBlobPromise) { if (skia_image->colorSpace()) { - image_ = image_->ConvertToColorSpace(SkColorSpace::MakeSRGB()); + image_ = image_->ConvertToColorSpace( + SkColorSpace::MakeSRGB(), + GetColorTypeForConversion(skia_image->colorType())); skia_image = image_->PaintImageForCurrentFrame().GetSkImage(); } @@ -212,7 +223,8 @@ DCHECK(skia_image->colorSpace()); } - SkColorType target_color_type = kN32_SkColorType; + SkColorType target_color_type = + GetColorTypeForConversion(skia_image->colorType()); if (encode_options_->pixelFormat() == kRGBA16ImagePixelFormatName) target_color_type = kRGBA_F16_SkColorType; // We can do color space and color type conversion together.
diff --git a/third_party/blink/renderer/core/html/forms/base_temporal_input_type.cc b/third_party/blink/renderer/core/html/forms/base_temporal_input_type.cc index 8d4cdb42..54f77cc 100644 --- a/third_party/blink/renderer/core/html/forms/base_temporal_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/base_temporal_input_type.cc
@@ -109,7 +109,8 @@ } Decimal BaseTemporalInputType::DefaultValueForStepUp() const { - return Decimal::FromDouble(ConvertToLocalTime(CurrentTimeMS())); + return Decimal::FromDouble( + ConvertToLocalTime(base::Time::Now().ToDoubleT() * 1000.0)); } bool BaseTemporalInputType::IsSteppable() const {
diff --git a/third_party/blink/renderer/core/html/forms/date_time_field_elements.cc b/third_party/blink/renderer/core/html/forms/date_time_field_elements.cc index 35de0956..1c0b62e 100644 --- a/third_party/blink/renderer/core/html/forms/date_time_field_elements.cc +++ b/third_party/blink/renderer/core/html/forms/date_time_field_elements.cc
@@ -664,7 +664,8 @@ static int CurrentFullYear() { DateComponents date; - date.SetMillisecondsSinceEpochForMonth(ConvertToLocalTime(CurrentTimeMS())); + date.SetMillisecondsSinceEpochForMonth( + ConvertToLocalTime(base::Time::Now().ToDoubleT() * 1000.0)); return date.FullYear(); }
diff --git a/third_party/blink/renderer/core/html/forms/form_data.cc b/third_party/blink/renderer/core/html/forms/form_data.cc index f550517e..bd44cb04 100644 --- a/third_party/blink/renderer/core/html/forms/form_data.cc +++ b/third_party/blink/renderer/core/html/forms/form_data.cc
@@ -359,7 +359,7 @@ String filename = filename_; if (filename.IsNull()) filename = "blob"; - return File::Create(filename, CurrentTimeMS(), + return File::Create(filename, base::Time::Now().ToDoubleT() * 1000.0, GetBlob()->GetBlobDataHandle()); }
diff --git a/third_party/blink/renderer/core/html/forms/month_input_type.cc b/third_party/blink/renderer/core/html/forms/month_input_type.cc index 00fc06f..50c9fc6 100644 --- a/third_party/blink/renderer/core/html/forms/month_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/month_input_type.cc
@@ -76,7 +76,8 @@ Decimal MonthInputType::DefaultValueForStepUp() const { DateComponents date; - date.SetMillisecondsSinceEpochForMonth(ConvertToLocalTime(CurrentTimeMS())); + date.SetMillisecondsSinceEpochForMonth( + ConvertToLocalTime(base::Time::Now().ToDoubleT() * 1000.0)); double months = date.MonthsSinceEpoch(); DCHECK(std::isfinite(months)); return Decimal::FromDouble(months);
diff --git a/third_party/blink/renderer/core/html/forms/time_input_type.cc b/third_party/blink/renderer/core/html/forms/time_input_type.cc index 9d8170a..5f75f6f3 100644 --- a/third_party/blink/renderer/core/html/forms/time_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/time_input_type.cc
@@ -65,7 +65,8 @@ Decimal TimeInputType::DefaultValueForStepUp() const { DateComponents date; - date.SetMillisecondsSinceMidnight(ConvertToLocalTime(CurrentTimeMS())); + date.SetMillisecondsSinceMidnight( + ConvertToLocalTime(base::Time::Now().ToDoubleT() * 1000.0)); double milliseconds = date.MillisecondsSinceEpoch(); DCHECK(std::isfinite(milliseconds)); return Decimal::FromDouble(milliseconds);
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc index b1020a9..04a0e8e3 100644 --- a/third_party/blink/renderer/core/html/html_anchor_element.cc +++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -57,6 +57,47 @@ namespace blink { +namespace { + +// Note: Here it covers download originated from clicking on <a download> link +// that results in direct download. Features in this method can also be logged +// from browser for download due to navigations to non-web-renderable content. +bool ShouldInterveneDownloadByFramePolicy(LocalFrame* frame) { + bool should_intervene_download = false; + Document& document = *(frame->GetDocument()); + UseCounter::Count(document, WebFeature::kDownloadPrePolicyCheck); + bool has_gesture = LocalFrame::HasTransientUserActivation(frame); + if (!has_gesture) { + UseCounter::Count(document, WebFeature::kDownloadWithoutUserGesture); + } + if (frame->IsAdSubframe()) { + UseCounter::Count(document, WebFeature::kDownloadInAdFrame); + if (!has_gesture) { + UseCounter::Count(document, + WebFeature::kDownloadInAdFrameWithoutUserGesture); + if (base::FeatureList::IsEnabled( + blink::features:: + kBlockingDownloadsInAdFrameWithoutUserActivation)) + should_intervene_download = true; + } + } + if (document.IsSandboxed(WebSandboxFlags::kDownloads)) { + UseCounter::Count(document, WebFeature::kDownloadInSandbox); + if (!has_gesture) { + UseCounter::Count(document, + WebFeature::kDownloadInSandboxWithoutUserGesture); + if (RuntimeEnabledFeatures:: + BlockingDownloadsInSandboxWithoutUserActivationEnabled()) + should_intervene_download = true; + } + } + if (!should_intervene_download) + UseCounter::Count(document, WebFeature::kDownloadPostPolicyCheck); + return should_intervene_download; +} + +} // namespace + using namespace html_names; HTMLAnchorElement::HTMLAnchorElement(Document& document) @@ -390,33 +431,8 @@ if (hasAttribute(kDownloadAttr) && NavigationPolicyFromEvent(&event) != kNavigationPolicyDownload && GetDocument().GetSecurityOrigin()->CanReadContent(completed_url)) { - UseCounter::Count(GetDocument(), WebFeature::kDownloadPrePolicyCheck); - bool has_gesture = LocalFrame::HasTransientUserActivation(frame); - if (frame->IsAdSubframe()) { - // Note: Here it covers download originated from clicking on <a download> - // link that results in direct download. These two features can also be - // logged from browser for download due to navigations to - // non-web-renderable content. - UseCounter::Count(GetDocument(), - has_gesture - ? WebFeature::kDownloadInAdFrameWithUserGesture - : WebFeature::kDownloadInAdFrameWithoutUserGesture); - if (!has_gesture && - base::FeatureList::IsEnabled( - blink::features:: - kBlockingDownloadsInAdFrameWithoutUserActivation)) - return; - } - if (GetDocument().IsSandboxed(WebSandboxFlags::kDownloads)) { - if (!has_gesture) { - UseCounter::Count(GetDocument(), - WebFeature::kDownloadInSandboxWithoutUserGesture); - if (RuntimeEnabledFeatures:: - BlockingDownloadsInSandboxWithoutUserActivationEnabled()) - return; - } - } - UseCounter::Count(GetDocument(), WebFeature::kDownloadPostPolicyCheck); + if (ShouldInterveneDownloadByFramePolicy(frame)) + return; request.SetSuggestedFilename( static_cast<String>(FastGetAttribute(kDownloadAttr))); request.SetRequestContext(mojom::RequestContextType::DOWNLOAD);
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.cc b/third_party/blink/renderer/core/input/mouse_event_manager.cc index 20109961..71baf09 100644 --- a/third_party/blink/renderer/core/input/mouse_event_manager.cc +++ b/third_party/blink/renderer/core/input/mouse_event_manager.cc
@@ -435,6 +435,7 @@ } void MouseEventManager::MarkHoverStateDirty() { + LOG(ERROR) << "MouseEventManager::MarkHoverStateDirty "; DCHECK(RuntimeEnabledFeatures::UpdateHoverAtBeginFrameEnabled()); DCHECK(frame_->IsLocalRoot()); hover_state_dirty_ = true;
diff --git a/third_party/blink/renderer/core/inspector/console_message.cc b/third_party/blink/renderer/core/inspector/console_message.cc index 029a7d1..19d5f8ba 100644 --- a/third_party/blink/renderer/core/inspector/console_message.cc +++ b/third_party/blink/renderer/core/inspector/console_message.cc
@@ -93,7 +93,7 @@ level_(level), message_(message), location_(std::move(location)), - timestamp_(WTF::CurrentTimeMS()), + timestamp_(base::Time::Now().ToDoubleT() * 1000.0), frame_(nullptr) {} ConsoleMessage::~ConsoleMessage() = default;
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc index 57521c2..728866b 100644 --- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc +++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -804,8 +804,8 @@ maybe_frame_id = frame_id; GetFrontend()->requestWillBeSent( request_id, loader_id, documentURL, std::move(request_info), - base::TimeTicks::Now().since_origin().InSecondsF(), CurrentTime(), - std::move(initiator_object), + base::TimeTicks::Now().since_origin().InSecondsF(), + base::Time::Now().ToDoubleT(), std::move(initiator_object), BuildObjectForResourceResponse(redirect_response), resource_type, std::move(maybe_frame_id), request.HasUserGesture()); if (is_handling_sync_xhr_) @@ -1245,8 +1245,8 @@ .build(); GetFrontend()->webSocketWillSendHandshakeRequest( IdentifiersFactory::SubresourceRequestId(identifier), - base::TimeTicks::Now().since_origin().InSecondsF(), CurrentTime(), - std::move(request_object)); + base::TimeTicks::Now().since_origin().InSecondsF(), + base::Time::Now().ToDoubleT(), std::move(request_object)); } void InspectorNetworkAgent::DidReceiveWebSocketHandshakeResponse( @@ -1362,6 +1362,8 @@ Response InspectorNetworkAgent::disable() { DCHECK(!pending_request_type_); + if (IsMainThread()) + GetNetworkStateNotifier().ClearOverride(); instrumenting_agents_->RemoveInspectorNetworkAgent(this); agent_state_.ClearAllFields(); resources_data_->Clear();
diff --git a/third_party/blink/renderer/core/inspector/thread_debugger.cc b/third_party/blink/renderer/core/inspector/thread_debugger.cc index 675108b..de227eb 100644 --- a/third_party/blink/renderer/core/inspector/thread_debugger.cc +++ b/third_party/blink/renderer/core/inspector/thread_debugger.cc
@@ -190,7 +190,7 @@ } double ThreadDebugger::currentTimeMS() { - return WTF::CurrentTimeMS(); + return base::Time::Now().ToDoubleT() * 1000.0; } bool ThreadDebugger::isInspectableHeapObject(v8::Local<v8::Object> object) {
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc index c5dbaf3e..402133b 100644 --- a/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc +++ b/third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc
@@ -276,7 +276,8 @@ return does_intersect; if (local_ancestor->HasOverflowClip()) { intersection_rect.Move( - -PhysicalOffset(local_ancestor->ScrolledContentOffset())); + -PhysicalOffset(LayoutPoint(local_ancestor->ScrollOrigin()) + + local_ancestor->ScrolledContentOffset())); } LayoutRect root_clip_rect = root_rect.ToLayoutRect(); // TODO(szager): This flipping seems incorrect because root_rect is already
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index 77d00ef..a6b1d43 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -2269,6 +2269,9 @@ if (!g_positioned_descendants_map) return; + if (LayoutBlockedByDisplayLock(DisplayLockContext::kChildren)) + return; + if (TrackedLayoutBoxListHashSet* positioned_descendant_set = PositionedObjects()) { TrackedLayoutBoxListHashSet::const_iterator end = @@ -2277,7 +2280,10 @@ positioned_descendant_set->begin(); it != end; ++it) { LayoutBox* curr_box = *it; - DCHECK(!curr_box->NeedsLayout()); + DCHECK(!curr_box->SelfNeedsLayout()); + DCHECK( + curr_box->LayoutBlockedByDisplayLock(DisplayLockContext::kChildren) || + !curr_box->NeedsLayout()); } } }
diff --git a/third_party/blink/renderer/core/layout/layout_view_test.cc b/third_party/blink/renderer/core/layout/layout_view_test.cc index 44988926..e42db57 100644 --- a/third_party/blink/renderer/core/layout/layout_view_test.cc +++ b/third_party/blink/renderer/core/layout/layout_view_test.cc
@@ -56,16 +56,13 @@ LayoutObject* view = frame_doc->GetLayoutView(); ASSERT_TRUE(view); EXPECT_FALSE(view->CanHaveChildren()); + EXPECT_FALSE(frame_doc->documentElement()->GetComputedStyle()); frame_doc->body()->SetInnerHTMLFromString(R"HTML( <div id="div"></div> )HTML"); - frame_doc->Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc); - frame_doc->GetStyleEngine().RecalcStyle({}); - - Element* div = frame_doc->getElementById("div"); - EXPECT_FALSE(div->GetComputedStyle()); + EXPECT_FALSE(frame_doc->NeedsLayoutTreeUpdate()); } struct HitTestConfig {
diff --git a/third_party/blink/renderer/core/loader/document_load_timing_test.cc b/third_party/blink/renderer/core/loader/document_load_timing_test.cc index f837f61..bf97e47 100644 --- a/third_party/blink/renderer/core/loader/document_load_timing_test.cc +++ b/third_party/blink/renderer/core/loader/document_load_timing_test.cc
@@ -23,7 +23,7 @@ timing.SetNavigationStart(base::TimeTicks() + base::TimeDelta::FromSecondsD( embedder_navigation_start)); - double real_wall_time = CurrentTime(); + double real_wall_time = base::Time::Now().ToDoubleT(); base::TimeDelta adjusted_wall_time = timing.MonotonicTimeToPseudoWallTime(timing.NavigationStart()); @@ -46,7 +46,7 @@ // Super quick load! Expect the wall time reported by this event to be // dominated by the navigationStartDelta, but similar to currentTime(). timing.MarkLoadEventEnd(); - double real_wall_load_event_end = CurrentTime(); + double real_wall_load_event_end = base::Time::Now().ToDoubleT(); base::TimeDelta adjusted_load_event_end = timing.MonotonicTimeToPseudoWallTime(timing.LoadEventEnd());
diff --git a/third_party/blink/renderer/core/loader/form_submission.cc b/third_party/blink/renderer/core/loader/form_submission.cc index 2c2baa3113..e489d40a 100644 --- a/third_party/blink/renderer/core/loader/form_submission.cc +++ b/third_party/blink/renderer/core/loader/form_submission.cc
@@ -58,7 +58,7 @@ // Initialize to the current time to reduce the likelihood of generating // identifiers that overlap with those from past/future browser sessions. static int64_t next_identifier = - static_cast<int64_t>(CurrentTime() * 1000000.0); + static_cast<int64_t>(base::Time::Now().ToDoubleT() * 1000000.0); return ++next_identifier; }
diff --git a/third_party/blink/renderer/core/loader/history_item.cc b/third_party/blink/renderer/core/loader/history_item.cc index 2c77a07c..b96d132 100644 --- a/third_party/blink/renderer/core/loader/history_item.cc +++ b/third_party/blink/renderer/core/loader/history_item.cc
@@ -41,7 +41,8 @@ static int64_t GenerateSequenceNumber() { // Initialize to the current time to reduce the likelihood of generating // identifiers that overlap with those from past/future browser sessions. - static int64_t next = static_cast<int64_t>(CurrentTime() * 1000000.0); + static int64_t next = + static_cast<int64_t>(base::Time::Now().ToDoubleT() * 1000000.0); return ++next; }
diff --git a/third_party/blink/renderer/core/loader/progress_tracker.cc b/third_party/blink/renderer/core/loader/progress_tracker.cc index 3a0ae51..8b458a21 100644 --- a/third_party/blink/renderer/core/loader/progress_tracker.cc +++ b/third_party/blink/renderer/core/loader/progress_tracker.cc
@@ -217,7 +217,7 @@ if (progress_value_ < last_notified_progress_value_) return; - double now = CurrentTime(); + double now = base::Time::Now().ToDoubleT(); double notified_progress_time_delta = now - last_notified_progress_time_; double notification_progress_delta =
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message.cc b/third_party/blink/renderer/core/messaging/blink_transferable_message.cc index 52a247ff..4d0e8b74 100644 --- a/third_party/blink/renderer/core/messaging/blink_transferable_message.cc +++ b/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
@@ -82,6 +82,7 @@ message.user_activation->was_active); } result.transfer_user_activation = message.transfer_user_activation; + result.allow_autoplay = message.allow_autoplay; if (!message.array_buffer_contents_array.empty()) { SerializedScriptValue::ArrayBufferContentsArray array_buffer_contents_array; @@ -150,6 +151,7 @@ message.user_activation->was_active); } result.transfer_user_activation = message.transfer_user_activation; + result.allow_autoplay = message.allow_autoplay; auto& array_buffer_contents_array = message.message->GetArrayBufferContentsArray();
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message.h b/third_party/blink/renderer/core/messaging/blink_transferable_message.h index d00868a..ccf6185 100644 --- a/third_party/blink/renderer/core/messaging/blink_transferable_message.h +++ b/third_party/blink/renderer/core/messaging/blink_transferable_message.h
@@ -34,6 +34,7 @@ mojom::blink::UserActivationSnapshotPtr user_activation; bool transfer_user_activation = false; + bool allow_autoplay = false; private: DISALLOW_COPY_AND_ASSIGN(BlinkTransferableMessage);
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc index 180fe59..343c797 100644 --- a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc +++ b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc
@@ -52,6 +52,7 @@ std::make_move_iterator(stream_channels.end())); out->has_user_gesture = data.has_user_gesture(); out->transfer_user_activation = data.transfer_user_activation(); + out->allow_autoplay = data.allow_autoplay(); out->message->SetArrayBufferContentsArray( std::move(array_buffer_contents_array));
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.h b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.h index 53ee100b..9dcf78fa 100644 --- a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.h +++ b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.h
@@ -66,6 +66,10 @@ return input.transfer_user_activation; } + static bool allow_autoplay(const blink::BlinkTransferableMessage& input) { + return input.allow_autoplay; + } + static bool Read(blink::mojom::blink::TransferableMessage::DataView, blink::BlinkTransferableMessage* out); };
diff --git a/third_party/blink/renderer/core/offscreencanvas/OWNERS b/third_party/blink/renderer/core/offscreencanvas/OWNERS index ffa62011..5ef87b1aa 100644 --- a/third_party/blink/renderer/core/offscreencanvas/OWNERS +++ b/third_party/blink/renderer/core/offscreencanvas/OWNERS
@@ -1,5 +1,4 @@ fserb@chromium.org -xidachen@chromium.org # TEAM: paint-dev@chromium.org # COMPONENT: Blink>Canvas
diff --git a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc index 2c238008..d73535f 100644 --- a/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc +++ b/third_party/blink/renderer/core/page/scrolling/fragment_anchor.cc
@@ -15,14 +15,22 @@ LocalFrame& frame, bool same_document_navigation) { FragmentAnchor* anchor = nullptr; + const bool text_fragment_identifiers_enabled = + RuntimeEnabledFeatures::TextFragmentIdentifiersEnabled( + frame.GetDocument()); - anchor = ElementFragmentAnchor::TryCreate(url, frame); + if (text_fragment_identifiers_enabled) { + anchor = TextFragmentAnchor::TryCreateFragmentDirective( + url, frame, same_document_navigation); + } + if (!anchor) { - if (RuntimeEnabledFeatures::TextFragmentIdentifiersEnabled( - frame.GetDocument())) { - anchor = - TextFragmentAnchor::TryCreate(url, frame, same_document_navigation); - } + anchor = ElementFragmentAnchor::TryCreate(url, frame); + } + + if (!anchor && text_fragment_identifiers_enabled) { + anchor = + TextFragmentAnchor::TryCreate(url, frame, same_document_navigation); } return anchor;
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc index b8a3dc3e..671cc77 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.cc
@@ -23,9 +23,14 @@ namespace { +constexpr char kFragmentDirectivePrefix[] = "##"; constexpr char kTextFragmentIdentifierPrefix[] = "targetText="; -constexpr size_t kTextFragmentIdentifierPrefixArrayLength = - base::size(kTextFragmentIdentifierPrefix); + +// Subtract 1 because base::size includes the \0 string terminator. +constexpr size_t kFragmentDirectivePrefixStringLength = + base::size(kFragmentDirectivePrefix) - 1; +constexpr size_t kTextFragmentIdentifierPrefixStringLength = + base::size(kTextFragmentIdentifierPrefix) - 1; bool ParseTargetTextIdentifier(const String& fragment, Vector<TextFragmentSelector>* out_selectors) { @@ -37,8 +42,7 @@ if (fragment.Find(kTextFragmentIdentifierPrefix, start_pos) != start_pos) return false; - // The prefix array length includes the \0 string terminator. - start_pos += kTextFragmentIdentifierPrefixArrayLength - 1; + start_pos += kTextFragmentIdentifierPrefixStringLength; end_pos = fragment.find('&', start_pos); String target_text; @@ -54,26 +58,46 @@ return true; } +// For fragment directive style text fragment anchors, we strip the directive +// from the fragment string to avoid breaking pages that rely on the fragment. +// E.g. "#id##targetText=a" --> "#id" +String StripFragmentDirective(const String& fragment) { + size_t start_pos = fragment.Find(kFragmentDirectivePrefix); + if (start_pos == kNotFound) + return fragment; + + return fragment.Substring(0, start_pos); +} + +bool CheckSecurityRestrictions(LocalFrame& frame, + bool same_document_navigation) { + // For security reasons, we only allow text fragments on the main frame of a + // main window. So no iframes, no window.open. Also only on a full + // navigation. + if (frame.Tree().Parent() || frame.DomWindow()->opener() || + same_document_navigation) { + return false; + } + + // For security reasons, we only allow text fragment anchors for user or + // browser initiated navigations, i.e. no script navigations. + if (!(frame.Loader().GetDocumentLoader()->HadTransientActivation() || + frame.Loader().GetDocumentLoader()->IsBrowserInitiated())) { + return false; + } + + return true; +} + } // namespace TextFragmentAnchor* TextFragmentAnchor::TryCreate( const KURL& url, LocalFrame& frame, bool same_document_navigation) { - // For security reasons, we only allow text fragments on the main frame of a - // main window. So no iframes, no window.open. Also only on a full - // navigation. - if (frame.Tree().Parent() || frame.DomWindow()->opener() || - same_document_navigation) + if (!CheckSecurityRestrictions(frame, same_document_navigation)) return nullptr; - // For security reasons, we only allow text fragment anchors for user or - // browser initiated navigations, i.e. no script navigations. - if (!(frame.Loader().GetDocumentLoader()->HadTransientActivation() || - frame.Loader().GetDocumentLoader()->IsBrowserInitiated())) { - return nullptr; - } - Vector<TextFragmentSelector> selectors; if (!ParseTargetTextIdentifier(url.FragmentIdentifier(), &selectors)) @@ -82,6 +106,40 @@ return MakeGarbageCollected<TextFragmentAnchor>(selectors, frame); } +TextFragmentAnchor* TextFragmentAnchor::TryCreateFragmentDirective( + const KURL& url, + LocalFrame& frame, + bool same_document_navigation) { + DCHECK(RuntimeEnabledFeatures::TextFragmentIdentifiersEnabled( + frame.GetDocument())); + + if (!CheckSecurityRestrictions(frame, same_document_navigation)) + return nullptr; + + Vector<TextFragmentSelector> selectors; + + // Add the hash to the beginning of the fragment identifier as it is + // part of parsing the ##targetText= prefix but is not included by + // KURL::FragmentIdentifier(). + String fragment = "#" + url.FragmentIdentifier(); + size_t directive_pos = fragment.Find(kFragmentDirectivePrefix); + if (directive_pos == kNotFound) + return nullptr; + + size_t start_pos = directive_pos + kFragmentDirectivePrefixStringLength; + if (!ParseTargetTextIdentifier(fragment.Substring(start_pos), &selectors)) + return nullptr; + + // Strip the fragment directive from the document URL so that the page cannot + // see the directive, to avoid breaking pages that rely on the fragment. + String stripped_fragment = StripFragmentDirective(fragment).Substring(1); + KURL stripped_url(url); + stripped_url.SetFragmentIdentifier(stripped_fragment); + frame.GetDocument()->SetURL(std::move(stripped_url)); + + return MakeGarbageCollected<TextFragmentAnchor>(selectors, frame); +} + TextFragmentAnchor::TextFragmentAnchor( const Vector<TextFragmentSelector>& text_fragment_selectors, LocalFrame& frame)
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h index f787c6c..fa27ab0 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h
@@ -26,6 +26,11 @@ LocalFrame& frame, bool same_document_navigation); + static TextFragmentAnchor* TryCreateFragmentDirective( + const KURL& url, + LocalFrame& frame, + bool same_document_navigation); + TextFragmentAnchor( const Vector<TextFragmentSelector>& text_fragment_selectors, LocalFrame& frame);
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc index 1d57026..b97dbb07 100644 --- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
@@ -1113,6 +1113,105 @@ EXPECT_EQ(14u, markers.at(0)->EndOffset()); } +// Test that the ##targetText fragment syntax works properly and is stripped +// from the URL. +TEST_F(TextFragmentAnchorTest, DoubleHashSyntax) { + SimRequest request("https://example.com/test.html##targetText=test", + "text/html"); + LoadURL("https://example.com/test.html##targetText=test"); + request.Complete(R"HTML( + <!DOCTYPE html> + <style> + body { + height: 1200px; + } + p { + position: absolute; + top: 1000px; + } + </style> + <p id="text">This is a test page</p> + )HTML"); + Compositor().BeginFrame(); + + RunAsyncMatchingTasks(); + + EXPECT_EQ(1u, GetDocument().Markers().Markers().size()); + + EXPECT_EQ(GetDocument().Url(), "https://example.com/test.html#"); +} + +// Test that the ##targetText fragment directive is stripped from the URL when +// there's also non-directive fragment contents. +TEST_F(TextFragmentAnchorTest, DoubleHashStrippedWithRemainingFragment) { + SimRequest request("https://example.com/test.html#element##targetText=test", + "text/html"); + LoadURL("https://example.com/test.html#element##targetText=test"); + request.Complete(R"HTML( + <!DOCTYPE html> + <style> + body { + height: 1200px; + } + #text { + position: absolute; + top: 1000px; + } + #element { + position: absolute; + top: 2000px; + } + </style> + <p id="text">This is a test page</p> + <div id="element"></div> + )HTML"); + Compositor().BeginFrame(); + + RunAsyncMatchingTasks(); + + EXPECT_EQ(GetDocument().Url(), "https://example.com/test.html#element"); + + Element& p = *GetDocument().getElementById("text"); + + EXPECT_TRUE(ViewportRect().Contains(BoundingRectInFrame(p))) + << "<p> Element wasn't scrolled into view, viewport's scroll offset: " + << LayoutViewport()->GetScrollOffset().ToString(); +} + +// If the fragment has a double hash, but the double hash isn't followed by a +// valid targetText syntax, it should be interpreted as an element ID. +TEST_F(TextFragmentAnchorTest, IdFragmentWithDoubleHash) { + SimRequest request("https://example.com/test.html#element##id", "text/html"); + LoadURL("https://example.com/test.html#element##id"); + request.Complete(R"HTML( + <!DOCTYPE html> + <style> + body { + height: 2200px; + } + p { + position: absolute; + top: 1000px; + } + div { + position: absolute; + top: 2000px; + } + </style> + <p id="element">This is a test page</p> + <div id="element##id"></div> + )HTML"); + Compositor().BeginFrame(); + + RunAsyncMatchingTasks(); + + Element& div = *GetDocument().getElementById("element##id"); + + EXPECT_TRUE(ViewportRect().Contains(BoundingRectInFrame(div))) + << "Should have scrolled <div> into view but didn't, scroll offset: " + << LayoutViewport()->GetScrollOffset().ToString(); +} + } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc index 54fd60c94..3607833 100644 --- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc +++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -3250,6 +3250,37 @@ // cases, fall back to painting the first kPixelDistanceToRecord pixels in // each direction. + // Note that since the interest rect mapping above can produce extremely + // large numbers in cases of perspective, try our best to "normalize" the + // result by ensuring that none of the rect dimensions exceed some large, + // but reasonable, limit. + const float reasonable_pixel_limit = std::numeric_limits<int>::max() / 2.f; + auto unpadded_intersection = local_interest_rect; + + // Note that by clamping X and Y, we are effectively moving the rect right / + // down. However, this will at most make us paint more content, which is + // better than erroneously deciding that the rect produced here is far + // offscreen. + if (unpadded_intersection.X() < -reasonable_pixel_limit) + unpadded_intersection.SetX(-reasonable_pixel_limit); + if (unpadded_intersection.Y() < -reasonable_pixel_limit) + unpadded_intersection.SetY(-reasonable_pixel_limit); + if (unpadded_intersection.MaxX() > reasonable_pixel_limit) { + unpadded_intersection.SetWidth(reasonable_pixel_limit - + unpadded_intersection.X()); + } + if (unpadded_intersection.MaxY() > reasonable_pixel_limit) { + unpadded_intersection.SetHeight(reasonable_pixel_limit - + unpadded_intersection.Y()); + } + + unpadded_intersection.Intersect(FloatRect(graphics_layer_bounds)); + // If our unpadded intersection is not empty, then use that before padding, + // since it can produce more stable results, and it would not produce any + // smaller area than if we used the original local interest rect. + if (!unpadded_intersection.IsEmpty()) + local_interest_rect = unpadded_intersection; + // Expand by interest rect padding amount, scaled by the approximate scale // of the GraphicsLayer relative to screen pixels. If width or height // are zero or nearly zero, fall back to kPixelDistanceToRecord. @@ -3264,7 +3295,10 @@ : 1.0f; // Take the max, to account for situations like rotation transforms, which // swap x and y. - float scale = max(x_scale, y_scale); + // Since at this point we can also have an extremely large scale due to + // perspective (see the comments above), cap it to something reasonable. + float scale = std::min(std::max(x_scale, y_scale), + reasonable_pixel_limit / kPixelDistanceToRecord); local_interest_rect.Inflate(kPixelDistanceToRecord * scale); } else { // Expand by interest rect padding amount.
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc index 2e34c930..64509cd 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -1229,6 +1229,7 @@ void PaintLayerScrollableArea::UpdateAfterOverflowRecalc() { UpdateScrollDimensions(); UpdateScrollbarProportions(); + UpdateScrollbarEnabledState(); bool needs_horizontal_scrollbar; bool needs_vertical_scrollbar; @@ -1249,6 +1250,7 @@ } ClampScrollOffsetAfterOverflowChange(); + UpdateScrollableAreaSet(); } IntRect PaintLayerScrollableArea::RectForHorizontalScrollbar(
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc index 9472f47f..aeae43ac 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -8,6 +8,7 @@ #include "cc/input/main_thread_scrolling_reason.h" #include "cc/input/overscroll_behavior.h" +#include "third_party/blink/renderer/core/animation/element_animations.h" #include "third_party/blink/renderer/core/dom/dom_node_ids.h" #include "third_party/blink/renderer/core/frame/link_highlights.h" #include "third_party/blink/renderer/core/frame/local_frame.h" @@ -676,6 +677,20 @@ return false; } +static bool ActiveTransformAnimationIsAxisAligned( + const LayoutObject& object, + CompositingReasons compositing_reasons) { + if (!(compositing_reasons & CompositingReason::kActiveTransformAnimation)) + return false; + + if (!object.GetNode() || !object.GetNode()->IsElementNode()) + return false; + const Element* element = To<Element>(object.GetNode()); + const auto* animations = element->GetElementAnimations(); + DCHECK(animations); + return animations->AnimationsPreserveAxisAlignment(); +} + void FragmentPaintPropertyTreeBuilder::UpdateTransform() { if (object_.IsSVGChild()) { UpdateTransformForNonRootSVG(); @@ -728,6 +743,13 @@ state.direct_compositing_reasons = full_context_.direct_compositing_reasons & CompositingReasonsForTransformProperty(); + // TODO(flackr): This only needs to consider composited transform + // animations. This is currently a cyclic dependency but we could + // calculate most of the compositable animation reasons up front to + // only consider animations which are candidates for compositing. + state.animation_is_axis_aligned = + ActiveTransformAnimationIsAxisAligned( + object_, full_context_.direct_compositing_reasons); } }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc index 114d527c..524cf4e 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -6875,4 +6875,49 @@ false); } +TEST_P(PaintPropertyTreeBuilderTest, TransformAnimationAxisAlignment) { + if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) + return; + SetBodyInnerHTML(R"HTML( + <!DOCTYPE html> + <style> + @keyframes transform_translation { + 0% { transform: translate(10px, 11px); } + 100% { transform: translate(20px, 21px); } + } + #translation_animation { + animation-name: transform_translation; + animation-duration: 1s; + width: 100px; + height: 100px; + will-change: transform; + } + @keyframes transform_rotation { + 0% { transform: rotateZ(10deg); } + 100% { transform: rotateZ(20deg); } + } + #rotation_animation { + animation-name: transform_rotation; + animation-duration: 1s; + width: 100px; + height: 100px; + will-change: transform; + } + </style> + <div id="translation_animation"></div> + <div id="rotation_animation"></div> + )HTML"); + UpdateAllLifecyclePhasesForTest(); + + const auto* translation = + PaintPropertiesForElement("translation_animation")->Transform(); + EXPECT_TRUE(translation->HasActiveTransformAnimation()); + EXPECT_TRUE(translation->TransformAnimationIsAxisAligned()); + + const auto* rotation = + PaintPropertiesForElement("rotation_animation")->Transform(); + EXPECT_TRUE(rotation->HasActiveTransformAnimation()); + EXPECT_FALSE(rotation->TransformAnimationIsAxisAligned()); +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc index 1c4e75e1..f43af5e 100644 --- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc +++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -1622,7 +1622,23 @@ !RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) return; - SetBodyInnerHTML("<div id='target' style='width: 100px; height: 100px'>"); + SetBodyInnerHTML(R"HTML( + <!DOCTYPE html> + <style> + @keyframes animation { + 0% { opacity: 0.3; } + 100% { opacity: 0.4; } + } + #target { + animation-name: animation; + animation-duration: 1s; + width: 100px; + height: 100px; + } + </style> + <div id='target'></div> + )HTML"); + auto* target = GetLayoutObjectByElementId("target"); auto style = ComputedStyle::Clone(target->StyleRef()); GetDocument().Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
diff --git a/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm b/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm index 0d198d97..783dec8 100644 --- a/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm +++ b/third_party/blink/renderer/core/scroll/scroll_animator_mac.mm
@@ -312,7 +312,7 @@ ~BlinkScrollbarPartAnimationTimer() {} void Start() { - start_time_ = WTF::CurrentTime(); + start_time_ = base::Time::Now().ToDoubleT(); // Set the framerate of the animation. NSAnimation uses a default // framerate of 60 Hz, so use that here. timer_.StartRepeating(base::TimeDelta::FromSecondsD(1.0 / 60.0), FROM_HERE); @@ -324,7 +324,7 @@ private: void TimerFired(TimerBase*) { - double current_time = WTF::CurrentTime(); + double current_time = base::Time::Now().ToDoubleT(); double delta = current_time - start_time_; if (delta >= duration_)
diff --git a/third_party/blink/renderer/core/testing/data/frameserialization/img_srcset.html b/third_party/blink/renderer/core/testing/data/frameserialization/img_srcset.html index 0f3dbe6..cceee51 100644 --- a/third_party/blink/renderer/core/testing/data/frameserialization/img_srcset.html +++ b/third_party/blink/renderer/core/testing/data/frameserialization/img_srcset.html
@@ -4,7 +4,7 @@ <title>Test Image with srcset</title> </head> <body> -<img src="1x.png" id="i1" srcset="2x.png 2x"> +<img src="1x.png" id="i1" srcset="2x.png 2x" sizes="(max-width: 640px) 6px"> <img src="1x.png" id="i2" width="8" srcset="2x.png 2x"> </body> </html>
diff --git a/third_party/blink/renderer/core/timing/largest_contentful_paint.cc b/third_party/blink/renderer/core/timing/largest_contentful_paint.cc index 40d2483..2457079 100644 --- a/third_party/blink/renderer/core/timing/largest_contentful_paint.cc +++ b/third_party/blink/renderer/core/timing/largest_contentful_paint.cc
@@ -38,6 +38,11 @@ if (!element_ || !element_->isConnected() || element_->IsInShadowTree()) return nullptr; + // Do not expose |element_| when the document is not 'fully active'. + const Document& document = element_->GetDocument(); + if (!document.IsActive() || !document.GetFrame()) + return nullptr; + return element_; } @@ -48,7 +53,7 @@ builder.Add("loadTime", load_time_); builder.Add("id", id_); builder.Add("url", url_); - builder.Add("element", element_); + builder.Add("element", element()); } void LargestContentfulPaint::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/timing/performance_element_timing.cc b/third_party/blink/renderer/core/timing/performance_element_timing.cc index 1a03016..f0cab81 100644 --- a/third_party/blink/renderer/core/timing/performance_element_timing.cc +++ b/third_party/blink/renderer/core/timing/performance_element_timing.cc
@@ -26,13 +26,15 @@ DCHECK_GE(naturalWidth, 0); DCHECK_GE(naturalHeight, 0); DCHECK(element); + double start_time = render_time != 0.0 ? render_time : load_time; return MakeGarbageCollected<PerformanceElementTiming>( - name, url, intersection_rect, render_time, load_time, identifier, - naturalWidth, naturalHeight, id, element); + name, start_time, url, intersection_rect, render_time, load_time, + identifier, naturalWidth, naturalHeight, id, element); } PerformanceElementTiming::PerformanceElementTiming( const AtomicString& name, + DOMHighResTimeStamp start_time, const String& url, const FloatRect& intersection_rect, DOMHighResTimeStamp render_time, @@ -42,7 +44,7 @@ int naturalHeight, const AtomicString& id, Element* element) - : PerformanceEntry(name, 0, 0), + : PerformanceEntry(name, start_time, start_time), element_(element), intersection_rect_(DOMRectReadOnly::FromFloatRect(intersection_rect)), render_time_(render_time), @@ -67,6 +69,11 @@ if (!element_ || !element_->isConnected() || element_->IsInShadowTree()) return nullptr; + // Do not expose |element_| when the document is not 'fully active'. + const Document& document = element_->GetDocument(); + if (!document.IsActive() || !document.GetFrame()) + return nullptr; + return element_; }
diff --git a/third_party/blink/renderer/core/timing/performance_element_timing.h b/third_party/blink/renderer/core/timing/performance_element_timing.h index f60fc2e0..ad6a994 100644 --- a/third_party/blink/renderer/core/timing/performance_element_timing.h +++ b/third_party/blink/renderer/core/timing/performance_element_timing.h
@@ -32,6 +32,7 @@ const AtomicString& id, Element*); PerformanceElementTiming(const AtomicString& name, + DOMHighResTimeStamp start_time, const String& url, const FloatRect& intersection_rect, DOMHighResTimeStamp render_time,
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc index 89cace0..948ffbc 100644 --- a/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc +++ b/third_party/blink/renderer/core/trustedtypes/trusted_types_util.cc
@@ -24,11 +24,16 @@ #include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h" #include "third_party/blink/renderer/core/trustedtypes/trusted_url.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" namespace blink { namespace { +// This value is derived from the Trusted Types spec (draft), and determines the +// maximum length of the sample value in the violation reports. +const unsigned kReportedValueMaximumLength = 40; + enum TrustedTypeViolationKind { kAnyTrustedTypeAssignment, kTrustedHTMLAssignment, @@ -81,6 +86,31 @@ return ""; } +std::pair<String, String> GetMessageAndSample( + TrustedTypeViolationKind kind, + const ExceptionState& exception_state, + const String& value) { + const char* interface_name = exception_state.InterfaceName(); + const char* property_name = exception_state.PropertyName(); + + // We have two sample formats, one for eval and one for assignment. + // If we don't have the required values being passed in, just leave the + // sample empty. + StringBuilder sample; + if (interface_name && strcmp("eval", interface_name) == 0) { + sample.Append("eval"); + } else if (interface_name && property_name) { + sample.Append(interface_name); + sample.Append("."); + sample.Append(property_name); + } + if (!sample.IsEmpty()) { + sample.Append(" "); + sample.Append(value.Left(kReportedValueMaximumLength)); + } + return std::make_pair<String, String>(GetMessage(kind), sample.ToString()); +} + // Handle failure of a Trusted Type assignment. // // If trusted type assignment fails, we need to @@ -91,7 +121,8 @@ // Returns whether the failure should be enforced. bool TrustedTypeFail(TrustedTypeViolationKind kind, const ExecutionContext* execution_context, - ExceptionState& exception_state) { + ExceptionState& exception_state, + const String& value) { if (!execution_context) return true; @@ -100,10 +131,12 @@ if (execution_context->GetTrustedTypes()) execution_context->GetTrustedTypes()->CountTrustedTypeAssignmentError(); - const char* message = GetMessage(kind); + String message; + String sample; + std::tie(message, sample) = GetMessageAndSample(kind, exception_state, value); bool allow = execution_context->GetSecurityContext() .GetContentSecurityPolicy() - ->AllowTrustedTypeAssignmentFailure(message); + ->AllowTrustedTypeAssignmentFailure(message, sample); if (!allow) { exception_state.ThrowTypeError(message); } @@ -129,8 +162,9 @@ if (string_or_trusted_type.IsString() && RequireTrustedTypesCheck(execution_context)) { - TrustedTypeFail(kAnyTrustedTypeAssignment, execution_context, - exception_state); + TrustedTypeFail( + kAnyTrustedTypeAssignment, execution_context, exception_state, + GetStringFromTrustedTypeWithoutCheck(string_or_trusted_type)); return g_empty_string; } @@ -243,7 +277,7 @@ TrustedTypePolicy* default_policy = GetDefaultPolicy(execution_context); if (!default_policy) { if (TrustedTypeFail(kTrustedHTMLAssignment, execution_context, - exception_state)) { + exception_state, string)) { return g_empty_string; } return string; @@ -254,7 +288,7 @@ if (exception_state.HadException()) { exception_state.ClearException(); TrustedTypeFail(kTrustedHTMLAssignmentAndDefaultPolicyFailed, - execution_context, exception_state); + execution_context, exception_state, string); return g_empty_string; } @@ -295,7 +329,7 @@ TrustedTypePolicy* default_policy = GetDefaultPolicy(execution_context); if (!default_policy) { if (TrustedTypeFail(kTrustedScriptAssignment, execution_context, - exception_state)) { + exception_state, potential_script)) { return g_empty_string; } return potential_script; @@ -307,7 +341,7 @@ if (exception_state.HadException()) { exception_state.ClearException(); TrustedTypeFail(kTrustedScriptAssignmentAndDefaultPolicyFailed, - execution_context, exception_state); + execution_context, exception_state, potential_script); return g_empty_string; } @@ -319,35 +353,36 @@ const ExecutionContext* execution_context, ExceptionState& exception_state) { DCHECK(!string_or_trusted_script_url.IsNull()); + if (string_or_trusted_script_url.IsTrustedScriptURL()) { + return string_or_trusted_script_url.GetAsTrustedScriptURL()->toString(); + } + + DCHECK(string_or_trusted_script_url.IsString()); + String string = string_or_trusted_script_url.GetAsString(); bool require_trusted_type = RequireTrustedTypesCheck(execution_context) && RuntimeEnabledFeatures::TrustedDOMTypesEnabled(execution_context); - if (!require_trusted_type && string_or_trusted_script_url.IsString()) { - return string_or_trusted_script_url.GetAsString(); - } - - if (string_or_trusted_script_url.IsTrustedScriptURL()) { - return string_or_trusted_script_url.GetAsTrustedScriptURL()->toString(); + if (!require_trusted_type) { + return string; } TrustedTypePolicy* default_policy = GetDefaultPolicy(execution_context); if (!default_policy) { if (TrustedTypeFail(kTrustedScriptURLAssignment, execution_context, - exception_state)) { + exception_state, string)) { return g_empty_string; } - return string_or_trusted_script_url.GetAsString(); + return string; } TrustedScriptURL* result = default_policy->CreateScriptURL( - execution_context->GetIsolate(), - string_or_trusted_script_url.GetAsString(), exception_state); + execution_context->GetIsolate(), string, exception_state); if (exception_state.HadException()) { exception_state.ClearException(); TrustedTypeFail(kTrustedScriptURLAssignmentAndDefaultPolicyFailed, - execution_context, exception_state); + execution_context, exception_state, string); return g_empty_string; } @@ -358,32 +393,33 @@ const ExecutionContext* execution_context, ExceptionState& exception_state) { DCHECK(!string_or_trusted_url.IsNull()); - - bool require_trusted_type = RequireTrustedTypesCheck(execution_context); - if (!require_trusted_type && string_or_trusted_url.IsUSVString()) { - return string_or_trusted_url.GetAsUSVString(); - } - if (string_or_trusted_url.IsTrustedURL()) { return string_or_trusted_url.GetAsTrustedURL()->toString(); } + DCHECK(string_or_trusted_url.IsUSVString()); + String string = string_or_trusted_url.GetAsUSVString(); + + bool require_trusted_type = RequireTrustedTypesCheck(execution_context); + if (!require_trusted_type) { + return string; + } + TrustedTypePolicy* default_policy = GetDefaultPolicy(execution_context); if (!default_policy) { if (TrustedTypeFail(kTrustedURLAssignment, execution_context, - exception_state)) { + exception_state, string)) { return g_empty_string; } - return string_or_trusted_url.GetAsUSVString(); + return string; } TrustedURL* result = default_policy->CreateURL( - execution_context->GetIsolate(), string_or_trusted_url.GetAsUSVString(), - exception_state); + execution_context->GetIsolate(), string, exception_state); if (exception_state.HadException()) { exception_state.ClearException(); TrustedTypeFail(kTrustedURLAssignmentAndDefaultPolicyFailed, - execution_context, exception_state); + execution_context, exception_state, string); return g_empty_string; } @@ -399,7 +435,8 @@ TrustedTypePolicy* default_policy = GetDefaultPolicy(doc); if (!default_policy) { - return TrustedTypeFail(kTextNodeScriptAssignment, doc, exception_state) + return TrustedTypeFail(kTextNodeScriptAssignment, doc, exception_state, + child->textContent()) ? nullptr : child; } @@ -409,7 +446,7 @@ if (exception_state.HadException()) { exception_state.ClearException(); return TrustedTypeFail(kTextNodeScriptAssignmentAndDefaultPolicyFailed, doc, - exception_state) + exception_state, child->textContent()) ? nullptr : child; }
diff --git a/third_party/blink/renderer/devtools/BUILD.gn b/third_party/blink/renderer/devtools/BUILD.gn index 7d01a82..537f373c 100644 --- a/third_party/blink/renderer/devtools/BUILD.gn +++ b/third_party/blink/renderer/devtools/BUILD.gn
@@ -101,7 +101,7 @@ "front_end/changes/changesSidebar.css", "front_end/changes/ChangesSidebar.js", "front_end/changes/module.json", - "front_end/cm/activeline.js", + "front_end/cm/active-line.js", "front_end/cm/brace-fold.js", "front_end/cm/closebrackets.js", "front_end/cm/codemirror.css", @@ -109,7 +109,7 @@ "front_end/cm/comment.js", "front_end/cm/foldcode.js", "front_end/cm/foldgutter.js", - "front_end/cm/markselection.js", + "front_end/cm/mark-selection.js", "front_end/cm/matchbrackets.js", "front_end/cm/module.json", "front_end/cm/multiplex.js",
diff --git a/third_party/blink/renderer/devtools/front_end/cm/README.md b/third_party/blink/renderer/devtools/front_end/cm/README.md index 6a8ff1a..ab9ca0a 100644 --- a/third_party/blink/renderer/devtools/front_end/cm/README.md +++ b/third_party/blink/renderer/devtools/front_end/cm/README.md
@@ -5,13 +5,16 @@ Every once in a while, the CodeMirror dependency (which is located in Source/devtools/front_end/cm/ folder) should be updated to a newer version. ## Updating CodeMirror + +Run `python devtools/scripts/roll_codemirror.js <codemirror_dir> <devtools_dir>` + +## Manual steps This requires the following steps to be done: 1. File `headlesscodemirror.js` is a `runmode-standalone.js` file from CodeMirror distribution, but wrapped in `(function(window) { ... }(this))` construction. This is needed to support in web workers. -2. File `markselection.js` is a `mark-selection.js` from CodeMirror distribution. The "dash" is removed due to the restriction on the chromium grd generator. -3. File codemirror.css contains both the default theme of CodeMirror and structural css required for it to work. Discard everything in the file up to the word `/* STOP */`. -4. All other files in front_end/cm/ folder should be substituted with their newer versions from the upstream. Note that some need to be renamed to remove `-` from the file name. -5. All files in front_end/cm_web_modes/ and front_end/cm_modes/ should be updated with newer versions from upstream. +2. File `codemirror.css` contains both the default theme of CodeMirror and structural css required for it to work. Discard everything in the file up to the word `/* STOP */`. +3. All other files in `front_end/cm/` folder should be substituted with their newer versions from the upstream. +4. All files in `front_end/cm_web_modes/` and `front_end/cm_modes/` should be updated with newer versions from upstream. ## Testing DevTools wrap CodeMirror via `CodeMirrorTextEditor.js` and `cmdevtools.css` files. @@ -30,7 +33,7 @@ 3. Go to the Elements panel, select a node and verify the "Edit it as HTML" command works. ## Committing -The only changes allowed to front_end/cm/ folder are CodeMirror rolls. There's a presubmit check that enforces this, so make sure you include the phrase "roll CodeMirror" into +The only changes allowed to `front_end/cm/` folder are CodeMirror rolls. There's a presubmit check that enforces this, so make sure you include the phrase "roll CodeMirror" into your patch description. ## Example
diff --git a/third_party/blink/renderer/devtools/front_end/cm/activeline.js b/third_party/blink/renderer/devtools/front_end/cm/active-line.js similarity index 100% rename from third_party/blink/renderer/devtools/front_end/cm/activeline.js rename to third_party/blink/renderer/devtools/front_end/cm/active-line.js
diff --git a/third_party/blink/renderer/devtools/front_end/cm/codemirror.css b/third_party/blink/renderer/devtools/front_end/cm/codemirror.css index 66567f0..6cdbd9b 100644 --- a/third_party/blink/renderer/devtools/front_end/cm/codemirror.css +++ b/third_party/blink/renderer/devtools/front_end/cm/codemirror.css
@@ -1,4 +1,3 @@ -/* STOP */ /* The rest of this file contains styles related to the mechanics of the editor. You probably shouldn't touch them. */
diff --git a/third_party/blink/renderer/devtools/front_end/cm/codemirror.js b/third_party/blink/renderer/devtools/front_end/cm/codemirror.js index 9f9704e..c6beeda4 100644 --- a/third_party/blink/renderer/devtools/front_end/cm/codemirror.js +++ b/third_party/blink/renderer/devtools/front_end/cm/codemirror.js
@@ -9689,7 +9689,7 @@ addLegacyProps(CodeMirror); - CodeMirror.version = "5.48.1"; + CodeMirror.version = "5.48.3"; return CodeMirror;
diff --git a/third_party/blink/renderer/devtools/front_end/cm/markselection.js b/third_party/blink/renderer/devtools/front_end/cm/mark-selection.js similarity index 100% rename from third_party/blink/renderer/devtools/front_end/cm/markselection.js rename to third_party/blink/renderer/devtools/front_end/cm/mark-selection.js
diff --git a/third_party/blink/renderer/devtools/front_end/cm/module.json b/third_party/blink/renderer/devtools/front_end/cm/module.json index ecabb5f..efe284e 100644 --- a/third_party/blink/renderer/devtools/front_end/cm/module.json +++ b/third_party/blink/renderer/devtools/front_end/cm/module.json
@@ -4,10 +4,10 @@ "multiplex.js", "matchbrackets.js", "closebrackets.js", - "markselection.js", + "mark-selection.js", "comment.js", "overlay.js", - "activeline.js", + "active-line.js", "foldcode.js", "foldgutter.js", "brace-fold.js" @@ -17,10 +17,10 @@ "multiplex.js", "matchbrackets.js", "closebrackets.js", - "markselection.js", + "mark-selection.js", "comment.js", "overlay.js", - "activeline.js", + "active-line.js", "foldcode.js", "foldgutter.js", "brace-fold.js"
diff --git a/third_party/blink/renderer/devtools/front_end/cm_web_modes/javascript.js b/third_party/blink/renderer/devtools/front_end/cm_web_modes/javascript.js index 85cb666..8055f1ba 100644 --- a/third_party/blink/renderer/devtools/front_end/cm_web_modes/javascript.js +++ b/third_party/blink/renderer/devtools/front_end/cm_web_modes/javascript.js
@@ -67,7 +67,7 @@ if (ch == '"' || ch == "'") { state.tokenize = tokenString(ch); return state.tokenize(stream, state); - } else if (ch == "." && stream.match(/^[\d_]+(?:[eE][+\-]?[\d_]+)?/)) { + } else if (ch == "." && stream.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/)) { return ret("number", "number"); } else if (ch == "." && stream.match("..")) { return ret("spread", "meta"); @@ -195,8 +195,12 @@ ++depth; } else if (wordRE.test(ch)) { sawSomething = true; - } else if (/["'\/]/.test(ch)) { - return; + } else if (/["'\/`]/.test(ch)) { + for (;; --pos) { + if (pos == 0) return + var next = stream.string.charAt(pos - 1) + if (next == ch && stream.string.charAt(pos - 2) != "\\") { pos--; break } + } } else if (sawSomething && !depth) { ++pos; break;
diff --git a/third_party/blink/renderer/devtools/scripts/roll_codemirror.py b/third_party/blink/renderer/devtools/scripts/roll_codemirror.py new file mode 100644 index 0000000..1019259 --- /dev/null +++ b/third_party/blink/renderer/devtools/scripts/roll_codemirror.py
@@ -0,0 +1,120 @@ +# 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. + +import argparse +import glob +import os +import shutil +import subprocess +import sys + + +def parse_options(cli_args): + parser = argparse.ArgumentParser(description='Roll CodeMirror') + parser.add_argument('cm_dir', help='CodeMirror directory') + parser.add_argument('devtools_dir', help='DevTools directory') + return parser.parse_args(cli_args) + + +def run_npm(options): + print 'Building CodeMirror in %s' % os.path.abspath(options.cm_dir) + subprocess.check_output(['npm', 'install'], cwd=options.cm_dir, stderr=subprocess.PIPE) + subprocess.check_output(['npm', 'run', 'build'], cwd=options.cm_dir, stderr=subprocess.PIPE) + + +def copy_lib_files(options): + print 'Copying codemirror.js and codemirror.css' + result = '' + target_dir = os.path.join(options.devtools_dir, 'front_end', 'cm') + + with open(os.path.join(options.cm_dir, 'lib', 'codemirror.js'), 'r') as read: + lines = read.readlines() + with open(os.path.join(target_dir, 'codemirror.js'), 'w') as write: + for line in lines: + if 'CodeMirror.version =' in line: + result = line.strip() + write.write(line) + + with open(os.path.join(options.cm_dir, 'lib', 'codemirror.css'), 'r') as read: + lines = read.readlines() + found_stop = False + with open(os.path.join(target_dir, 'codemirror.css'), 'w') as write: + for line in lines: + if found_stop: + write.write(line) + elif '/* STOP */' in line: + found_stop = True + assert found_stop + return result + + +def copy_headless_file(options): + print 'Copying runmode-standalone.js into headlesscodemirror.js' + source_file = os.path.join(options.cm_dir, 'addon', 'runmode', 'runmode-standalone.js') + target_file = os.path.join(options.devtools_dir, 'front_end', 'cm_headless', 'headlesscodemirror.js') + + with open(source_file, 'r') as read: + lines = read.readlines() + with open(target_file, 'w') as write: + write.write('// Content of the function is equal to runmode-standalone.js file\n') + write.write('// from CodeMirror distribution\n') + write.write('(function(window) {\n') + for line in lines: + write.write(line) + write.write('}(this))\n') + + +def find_and_copy_js_files(source_dir, target_dir, filter_fn): + for f in os.listdir(target_dir): + if not filter_fn(f): + continue + target_file = os.path.join(target_dir, f) + if not os.path.isfile(os.path.join(target_dir, f)): + continue + source = glob.glob(os.path.join(source_dir, '*', f)) + assert len(source) == 1 + source_file = source[0] + print 'Copying %s from %s' % (target_file, source_file) + shutil.copyfile(source_file, target_file) + + +def copy_cm_files(options): + source_dir = os.path.join(options.cm_dir, 'addon') + target_dir = os.path.join(options.devtools_dir, 'front_end', 'cm') + + def cm_filter(f): + return f.endswith('.js') and f != 'codemirror.js' + + find_and_copy_js_files(source_dir, target_dir, cm_filter) + + +def copy_cm_modes_files(options): + source_dir = os.path.join(options.cm_dir, 'mode') + target_dir = os.path.join(options.devtools_dir, 'front_end', 'cm_modes') + + def cm_modes_filter(f): + return f.endswith('.js') and f != 'DefaultCodeMirrorMimeMode.js' + + find_and_copy_js_files(source_dir, target_dir, cm_modes_filter) + + +def copy_cm_web_modes_files(options): + source_dir = os.path.join(options.cm_dir, 'mode') + target_dir = os.path.join(options.devtools_dir, 'front_end', 'cm_web_modes') + + def cm_web_modes_filter(f): + return f.endswith('.js') + + find_and_copy_js_files(source_dir, target_dir, cm_web_modes_filter) + + +if __name__ == '__main__': + OPTIONS = parse_options(sys.argv[1:]) + run_npm(OPTIONS) + copy_cm_files(OPTIONS) + copy_cm_modes_files(OPTIONS) + copy_cm_web_modes_files(OPTIONS) + copy_headless_file(OPTIONS) + VERSION = copy_lib_files(OPTIONS) + print VERSION
diff --git a/third_party/blink/renderer/modules/accessibility/ax_position.cc b/third_party/blink/renderer/modules/accessibility/ax_position.cc index ca52113..be6ef77 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_position.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_position.cc
@@ -444,7 +444,13 @@ // after the last character. const AXObject* child = ChildAfterTreePosition(); if (!child) { - const AXObject* next_in_order = container_object_->NextInTreeObject(); + // If this is a static text object, we should not descend into its inline + // text boxes when present, because we'll just be creating a text position + // in the same piece of text. + const AXObject* next_in_order = + container_object_->ChildCount() + ? container_object_->DeepestLastChild()->NextInTreeObject() + : container_object_->NextInTreeObject(); if (!next_in_order || !next_in_order->ParentObjectIncludedInTree()) return {}; @@ -474,7 +480,10 @@ // Handles both an "after children" position, or a text position that is // before the first character. if (!child) { - if (container_object_->ChildCount()) { + // If this is a static text object, we should not descend into its inline + // text boxes when present, because we'll just be creating a text position + // in the same piece of text. + if (!container_object_->IsTextObject() && container_object_->ChildCount()) { const AXObject* last_child = container_object_->LastChild(); // Dont skip over any intervening text. if (last_child->IsTextObject() || last_child->IsNativeTextControl()) { @@ -531,7 +540,7 @@ // 5. We arbitrarily decided to ignore positions that are anchored to before a // text object. We move such positions to before the first character of the // text object. This is in an effort to ensure that two positions, one a - // "before object" position anchored to before a text object, and one a "text + // "before object" position anchored to a text object, and one a "text // position" anchored to before the first character of the same text object, // compare as equivalent.
diff --git a/third_party/blink/renderer/modules/accessibility/ax_position_test.cc b/third_party/blink/renderer/modules/accessibility/ax_position_test.cc index 41c0d31..c28df08 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_position_test.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_position_test.cc
@@ -1236,6 +1236,135 @@ EXPECT_EQ(12, position_after.GetPosition().OffsetInContainerNode()); } +TEST_F(AccessibilityTest, PositionInTableWithCSSContent) { + SetBodyInnerHTML(kHTMLTable); + + // Add some CSS content, i.e. a plus symbol before and a colon after each + // table header cell. + Element* const style_element = + GetDocument().CreateRawElement(html_names::kStyleTag); + ASSERT_NE(nullptr, style_element); + style_element->setTextContent(R"STYLE( + th::before { + content: "+"; + } + th::after { + content: ":"; + } + )STYLE"); + GetDocument().body()->insertBefore(style_element, + GetDocument().body()->firstChild()); + UpdateAllLifecyclePhasesForTest(); + + const Node* first_header_cell = GetElementById("firstHeaderCell"); + ASSERT_NE(nullptr, first_header_cell); + const Node* last_header_cell = GetElementById("lastHeaderCell"); + ASSERT_NE(nullptr, last_header_cell); + + // CSS text nodes are not in the DOM tree. + const Node* first_header_cell_text = first_header_cell->firstChild(); + ASSERT_NE(nullptr, first_header_cell_text); + ASSERT_FALSE(first_header_cell_text->IsPseudoElement()); + ASSERT_TRUE(first_header_cell_text->IsTextNode()); + const Node* last_header_cell_text = last_header_cell->firstChild(); + ASSERT_NE(nullptr, last_header_cell_text); + ASSERT_FALSE(last_header_cell_text->IsPseudoElement()); + ASSERT_TRUE(last_header_cell_text->IsTextNode()); + + const AXObject* ax_first_header_cell = + GetAXObjectByElementId("firstHeaderCell"); + ASSERT_NE(nullptr, ax_first_header_cell); + ASSERT_EQ(ax::mojom::Role::kColumnHeader, ax_first_header_cell->RoleValue()); + const AXObject* ax_last_header_cell = + GetAXObjectByElementId("lastHeaderCell"); + ASSERT_NE(nullptr, ax_last_header_cell); + ASSERT_EQ(ax::mojom::Role::kColumnHeader, ax_last_header_cell->RoleValue()); + + ASSERT_EQ(3, ax_first_header_cell->ChildCount()); + AXObject* const ax_first_cell_css_before = ax_first_header_cell->FirstChild(); + ASSERT_NE(nullptr, ax_first_cell_css_before); + ASSERT_EQ(ax::mojom::Role::kStaticText, + ax_first_cell_css_before->RoleValue()); + + ASSERT_EQ(3, ax_last_header_cell->ChildCount()); + AXObject* const ax_last_cell_css_after = ax_last_header_cell->LastChild(); + ASSERT_NE(nullptr, ax_last_cell_css_after); + ASSERT_EQ(ax::mojom::Role::kStaticText, ax_last_cell_css_after->RoleValue()); + + // The first position inside the first header cell should be before the plus + // symbol inside the CSS content. It should be valid in the accessibility tree + // but not valid in the DOM tree. + auto ax_position_before = + AXPosition::CreateFirstPositionInObject(*ax_first_header_cell); + EXPECT_TRUE(ax_position_before.IsTextPosition()); + EXPECT_EQ(0, ax_position_before.TextOffset()); + auto position_before = ax_position_before.ToPositionWithAffinity( + AXPositionAdjustmentBehavior::kMoveRight); + EXPECT_EQ(first_header_cell_text, position_before.AnchorNode()); + EXPECT_EQ(0, position_before.GetPosition().OffsetInContainerNode()); + + // Same situation as above, but explicitly create a text position inside the + // CSS content, instead of having it implicitly created by + // CreateFirstPositionInObject. + ax_position_before = + AXPosition::CreateFirstPositionInObject(*ax_first_cell_css_before); + EXPECT_TRUE(ax_position_before.IsTextPosition()); + EXPECT_EQ(0, ax_position_before.TextOffset()); + position_before = ax_position_before.ToPositionWithAffinity( + AXPositionAdjustmentBehavior::kMoveRight); + EXPECT_EQ(first_header_cell_text, position_before.AnchorNode()); + EXPECT_EQ(0, position_before.GetPosition().OffsetInContainerNode()); + + // Same situation as above, but now create a text position inside the inline + // text box representing the CSS content after the last header cell. + ax_first_cell_css_before->LoadInlineTextBoxes(); + ASSERT_NE(nullptr, ax_first_cell_css_before->FirstChild()); + ax_position_before = AXPosition::CreateFirstPositionInObject( + *ax_first_cell_css_before->FirstChild()); + EXPECT_TRUE(ax_position_before.IsTextPosition()); + EXPECT_EQ(0, ax_position_before.TextOffset()); + position_before = ax_position_before.ToPositionWithAffinity( + AXPositionAdjustmentBehavior::kMoveRight); + EXPECT_EQ(first_header_cell_text, position_before.AnchorNode()); + EXPECT_EQ(0, position_before.GetPosition().OffsetInContainerNode()); + + // An "after children" position inside the last header cell should be after + // the CSS content that displays a colon. It should be valid in the + // accessibility tree but not valid in the DOM tree. + auto ax_position_after = + AXPosition::CreateLastPositionInObject(*ax_last_header_cell); + EXPECT_FALSE(ax_position_after.IsTextPosition()); + EXPECT_EQ(3, ax_position_after.ChildIndex()); + auto position_after = ax_position_after.ToPositionWithAffinity( + AXPositionAdjustmentBehavior::kMoveLeft); + EXPECT_EQ(last_header_cell_text, position_after.AnchorNode()); + EXPECT_EQ(8, position_after.GetPosition().OffsetInContainerNode()); + + // Similar to the last case, but explicitly create a text position inside the + // CSS content after the last header cell. + ax_position_after = + AXPosition::CreateLastPositionInObject(*ax_last_cell_css_after); + EXPECT_TRUE(ax_position_after.IsTextPosition()); + EXPECT_EQ(1, ax_position_after.TextOffset()); + position_after = ax_position_after.ToPositionWithAffinity( + AXPositionAdjustmentBehavior::kMoveLeft); + EXPECT_EQ(last_header_cell_text, position_after.AnchorNode()); + EXPECT_EQ(8, position_after.GetPosition().OffsetInContainerNode()); + + // Same situation as above, but now create a text position inside the inline + // text box representing the CSS content after the last header cell. + ax_last_cell_css_after->LoadInlineTextBoxes(); + ASSERT_NE(nullptr, ax_last_cell_css_after->FirstChild()); + ax_position_after = AXPosition::CreateLastPositionInObject( + *ax_last_cell_css_after->FirstChild()); + EXPECT_TRUE(ax_position_after.IsTextPosition()); + EXPECT_EQ(1, ax_position_after.TextOffset()); + position_after = ax_position_after.ToPositionWithAffinity( + AXPositionAdjustmentBehavior::kMoveLeft); + EXPECT_EQ(last_header_cell_text, position_after.AnchorNode()); + EXPECT_EQ(8, position_after.GetPosition().OffsetInContainerNode()); +} + // // Objects deriving from |AXMockObject|, e.g. table columns, are in the // accessibility tree but are neither in the DOM or layout trees.
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc index 7a7e7bb..a3a5963b 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
@@ -105,15 +105,28 @@ domain = cookie_url_host; } - // The cookie store API is only exposed on secure origins. If this changes: - // 1) The secure option must default to false for insecure origins. - // 2) Only secure origins can set the "secure" option to true. - DCHECK(SecurityOrigin::IsSecure(cookie_url)); - - const bool secure = options->secure(); + // Although the Cookie Store API spec always defaults the "secure" cookie + // attribute to true, we only default to true on cryptographically secure + // origins, where only secure cookies may be written, and to false otherwise, + // where only insecure cookies may be written. As a result, + // cookieStore.set("name", "value") sets a cookie and + // cookieStore.delete("name") deletes a cookie on both http://localhost and + // secure origins, without having to specify "secure: false" on + // http://localhost. + const bool secure = options->hasSecure() + ? options->secure() + : SecurityOrigin::IsSecure(cookie_url); + // If attempting to set/delete a secure cookie on an insecure origin, throw an + // exception, rather than failing silently as document.cookie does. + if (secure && !SecurityOrigin::IsSecure(cookie_url)) { + exception_state.ThrowTypeError( + "Cannot modify a secure cookie on insecure origin"); + return base::nullopt; + } if (!secure && (name.StartsWith("__Secure-") || name.StartsWith("__Host-"))) { exception_state.ThrowTypeError( "__Secure- and __Host- cookies must be secure"); + return base::nullopt; } network::mojom::CookieSameSite same_site; @@ -268,7 +281,8 @@ set_options->setExpires(options->expires()); set_options->setDomain(options->domain()); set_options->setPath(options->path()); - set_options->setSecure(options->secure()); + if (options->hasSecure()) + set_options->setSecure(options->secure()); set_options->setSameSite(options->sameSite()); return set(script_state, set_options, exception_state); } @@ -306,7 +320,6 @@ set_options->setExpires(0); set_options->setDomain(options->domain()); set_options->setPath(options->path()); - set_options->setSecure(true); set_options->setSameSite("strict"); return DoWrite(script_state, set_options, exception_state); }
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store_set_options.idl b/third_party/blink/renderer/modules/cookie_store/cookie_store_set_options.idl index 4a01a9fa..c9d2cafc 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store_set_options.idl +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store_set_options.idl
@@ -14,6 +14,6 @@ DOMTimeStamp? expires = null; USVString? domain = null; USVString path = "/"; - boolean secure = true; + boolean secure; CookieSameSite sameSite = "strict"; };
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc index 4b5b647..54e1827 100644 --- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc +++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -405,14 +405,6 @@ if (credential->echo_hmac_create_secret) { extension_outputs->setHmacCreateSecret(credential->hmac_create_secret); } -#if defined(OS_ANDROID) - if (credential->echo_user_verification_methods) { - extension_outputs->setUvm( - UvmEntryToArray(std::move(*credential->user_verification_methods))); - UseCounter::Count(resolver->GetExecutionContext(), - WebFeature::kCredentialManagerCreateSuccessWithUVM); - } -#endif resolver->Resolve(MakeGarbageCollected<PublicKeyCredential>( credential->info->id, raw_id, authenticator_response, extension_outputs)); @@ -708,13 +700,6 @@ resolver->GetExecutionContext(), WebFeature::kCredentialManagerCreatePublicKeyCredential); } -#if defined(OS_ANDROID) - if (options->publicKey()->hasExtensions() && - options->publicKey()->extensions()->hasUvm()) { - UseCounter::Count(resolver->GetExecutionContext(), - WebFeature::kCredentialManagerCreateWithUVM); - } -#endif const String& relying_party_id = options->publicKey()->rp()->id(); if (!CheckPublicKeySecurityRequirements(resolver, relying_party_id))
diff --git a/third_party/blink/renderer/modules/exported/web_ax_object.cc b/third_party/blink/renderer/modules/exported/web_ax_object.cc index 98362e5d..3ebfbd5 100644 --- a/third_party/blink/renderer/modules/exported/web_ax_object.cc +++ b/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -154,14 +154,7 @@ return false; if (document->View()->NeedsLayout()) return false; - DocumentLifecycle::LifecycleState state = document->Lifecycle().GetState(); - if (state >= DocumentLifecycle::kLayoutClean || - state == DocumentLifecycle::kStyleClean || - state == DocumentLifecycle::kLayoutSubtreeChangeClean) { - return true; - } - - return false; + return document->Lifecycle().GetState() >= DocumentLifecycle::kLayoutClean; } void WebAXObject::Reset() {
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation.cc b/third_party/blink/renderer/modules/geolocation/geolocation.cc index 3fb54af..ff11b93f 100644 --- a/third_party/blink/renderer/modules/geolocation/geolocation.cc +++ b/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -297,7 +297,7 @@ if (!options->maximumAge()) return false; DOMTimeStamp current_time_millis = - ConvertSecondsToDOMTimeStamp(CurrentTime()); + ConvertSecondsToDOMTimeStamp(base::Time::Now().ToDoubleT()); return last_position_->timestamp() > current_time_millis - options->maximumAge(); }
diff --git a/third_party/blink/renderer/modules/image_downloader/BUILD.gn b/third_party/blink/renderer/modules/image_downloader/BUILD.gn index 88388e7..125f62e 100644 --- a/third_party/blink/renderer/modules/image_downloader/BUILD.gn +++ b/third_party/blink/renderer/modules/image_downloader/BUILD.gn
@@ -10,8 +10,6 @@ "fetcher/associated_resource_fetcher.h", "fetcher/multi_resolution_image_resource_fetcher.cc", "fetcher/multi_resolution_image_resource_fetcher.h", - "image_downloader_base.cc", - "image_downloader_base.h", "image_downloader_impl.cc", "image_downloader_impl.h", ]
diff --git a/third_party/blink/renderer/modules/image_downloader/image_downloader_base.cc b/third_party/blink/renderer/modules/image_downloader/image_downloader_base.cc deleted file mode 100644 index 8958861..0000000 --- a/third_party/blink/renderer/modules/image_downloader/image_downloader_base.cc +++ /dev/null
@@ -1,117 +0,0 @@ -// 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. - -#include "third_party/blink/renderer/modules/image_downloader/image_downloader_base.h" - -#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" -#include "third_party/blink/public/platform/web_data.h" -#include "third_party/blink/public/platform/web_image.h" -#include "third_party/blink/public/platform/web_size.h" -#include "third_party/blink/renderer/core/frame/local_frame.h" -#include "third_party/blink/renderer/modules/image_downloader/fetcher/multi_resolution_image_resource_fetcher.h" -#include "third_party/blink/renderer/platform/heap/persistent.h" -#include "third_party/blink/renderer/platform/network/network_utils.h" -#include "third_party/blink/renderer/platform/weborigin/kurl.h" -#include "third_party/blink/renderer/platform/wtf/functional.h" -#include "ui/gfx/favicon_size.h" - -namespace { - -// Decodes a data: URL image or returns an empty image in case of failure. -SkBitmap ImageFromDataUrl(const blink::KURL& url) { - std::string data; - if (blink::network_utils::IsDataURLMimeTypeSupported(url, &data) && - !data.empty()) { - gfx::Size desired_icon_size = - gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize); - const unsigned char* src_data = - reinterpret_cast<const unsigned char*>(data.data()); - return blink::WebImage::FromData( - blink::WebData(reinterpret_cast<const char*>(src_data), data.size()), - blink::WebSize(desired_icon_size)); - } - return SkBitmap(); -} - -} // namespace - -namespace blink { - -ImageDownloaderBase::ImageDownloaderBase(ExecutionContext* context, - LocalFrame& frame) - : ContextLifecycleObserver(context), frame_(frame) {} - -ImageDownloaderBase::~ImageDownloaderBase() {} - -void ImageDownloaderBase::DownloadImage(const KURL& image_url, - bool is_favicon, - bool bypass_cache, - DownloadCallback callback) { - if (!image_url.ProtocolIsData()) { - FetchImage(image_url, is_favicon, bypass_cache, std::move(callback)); - // Will complete asynchronously via ImageDownloaderBase::DidFetchImage. - return; - } - - WTF::Vector<SkBitmap> result_images; - SkBitmap data_image = ImageFromDataUrl(image_url); - - // Drop null or empty SkBitmap. - if (!data_image.drawsNothing()) - result_images.push_back(data_image); - - std::move(callback).Run(0, result_images); -} - -void ImageDownloaderBase::FetchImage(const KURL& image_url, - bool is_favicon, - bool bypass_cache, - DownloadCallback callback) { - // Create an image resource fetcher and assign it with a call back object. - image_fetchers_.push_back( - std::make_unique<MultiResolutionImageResourceFetcher>( - image_url, frame_, 0, - is_favicon ? blink::mojom::RequestContextType::FAVICON - : blink::mojom::RequestContextType::IMAGE, - bypass_cache ? blink::mojom::FetchCacheMode::kBypassCache - : blink::mojom::FetchCacheMode::kDefault, - WTF::Bind(&ImageDownloaderBase::DidFetchImage, WrapPersistent(this), - std::move(callback)))); -} - -void ImageDownloaderBase::DidFetchImage( - DownloadCallback callback, - MultiResolutionImageResourceFetcher* fetcher, - const WTF::Vector<SkBitmap>& images) { - int32_t http_status_code = fetcher->http_status_code(); - - // Remove the image fetcher from our pending list. We're in the callback from - // MultiResolutionImageResourceFetcher, best to delay deletion. - for (auto* it = image_fetchers_.begin(); it != image_fetchers_.end(); ++it) { - MultiResolutionImageResourceFetcher* image_fetcher = it->get(); - DCHECK(image_fetcher); - if (image_fetcher == fetcher) { - it = image_fetchers_.erase(it); - break; - } - } - - // |this| may be destructed after callback is run. - std::move(callback).Run(http_status_code, images); -} - -void ImageDownloaderBase::Trace(blink::Visitor* visitor) { - visitor->Trace(frame_); - ContextLifecycleObserver::Trace(visitor); -} - -void ImageDownloaderBase::ContextDestroyed(ExecutionContext*) { - for (const auto& fetchers : image_fetchers_) { - // Will run callbacks with an empty image vector. - fetchers->OnRenderFrameDestruct(); - } - image_fetchers_.clear(); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/image_downloader/image_downloader_base.h b/third_party/blink/renderer/modules/image_downloader/image_downloader_base.h deleted file mode 100644 index 755ff801..0000000 --- a/third_party/blink/renderer/modules/image_downloader/image_downloader_base.h +++ /dev/null
@@ -1,72 +0,0 @@ -// 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. - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_IMAGE_DOWNLOADER_IMAGE_DOWNLOADER_BASE_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_IMAGE_DOWNLOADER_IMAGE_DOWNLOADER_BASE_H_ - -#include <stdint.h> - -#include "base/callback.h" -#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" -#include "third_party/blink/renderer/platform/heap/visitor.h" -#include "third_party/skia/include/core/SkBitmap.h" - -namespace blink { - -class KURL; -class MultiResolutionImageResourceFetcher; -class LocalFrame; - -class ImageDownloaderBase : public ContextLifecycleObserver { - public: - ImageDownloaderBase(ExecutionContext*, LocalFrame&); - ~ImageDownloaderBase(); - - using DownloadCallback = - base::OnceCallback<void(int32_t, const WTF::Vector<SkBitmap>&)>; - - // Request to asynchronously download an image. When done, |callback| will be - // called. - void DownloadImage(const KURL& url, - bool is_favicon, - bool bypass_cache, - DownloadCallback callback); - - void Trace(blink::Visitor*) override; - - protected: - // ContextLifecycleObserver: - void ContextDestroyed(ExecutionContext*) override; - - private: - // Requests to fetch an image. When done, the image downloader is notified by - // way of DidFetchImage. If the image is a favicon, cookies will not be sent - // nor accepted during download. If the image has multiple frames, all frames - // are returned. - void FetchImage(const KURL& image_url, - bool is_favicon, - bool bypass_cache, - DownloadCallback callback); - - // This callback is triggered when FetchImage completes, either - // successfully or with a failure. See FetchImage for more - // details. - void DidFetchImage(DownloadCallback callback, - MultiResolutionImageResourceFetcher* fetcher, - const WTF::Vector<SkBitmap>& images); - - typedef WTF::Vector<std::unique_ptr<MultiResolutionImageResourceFetcher>> - ImageResourceFetcherList; - - // ImageResourceFetchers schedule via FetchImage. - ImageResourceFetcherList image_fetchers_; - - Member<LocalFrame> frame_; - - DISALLOW_COPY_AND_ASSIGN(ImageDownloaderBase); -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_IMAGE_DOWNLOADER_IMAGE_DOWNLOADER_BASE_H_
diff --git a/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc b/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc index fa940a7e..ce3e32ab 100644 --- a/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc +++ b/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
@@ -9,18 +9,40 @@ #include "base/bind.h" #include "base/logging.h" #include "skia/ext/image_operations.h" +#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/platform/interface_registry.h" +#include "third_party/blink/public/platform/web_data.h" +#include "third_party/blink/public/platform/web_image.h" #include "third_party/blink/public/platform/web_size.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" +#include "third_party/blink/renderer/modules/image_downloader/fetcher/multi_resolution_image_resource_fetcher.h" #include "third_party/blink/renderer/platform/heap/visitor.h" +#include "third_party/blink/renderer/platform/network/network_utils.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "ui/gfx/favicon_size.h" #include "ui/gfx/geometry/size.h" namespace { +// Decodes a data: URL image or returns an empty image in case of failure. +SkBitmap ImageFromDataUrl(const blink::KURL& url) { + std::string data; + if (blink::network_utils::IsDataURLMimeTypeSupported(url, &data) && + !data.empty()) { + gfx::Size desired_icon_size = + gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize); + const unsigned char* src_data = + reinterpret_cast<const unsigned char*>(data.data()); + return blink::WebImage::FromData( + blink::WebData(reinterpret_cast<const char*>(src_data), data.size()), + blink::WebSize(desired_icon_size)); + } + return SkBitmap(); +} + // Proportionally resizes the |image| to fit in a box of size // |max_image_size|. SkBitmap ResizeImage(const SkBitmap& image, uint32_t max_image_size) { @@ -109,7 +131,7 @@ ImageDownloaderImpl::ImageDownloaderImpl(LocalFrame& frame) : Supplement<LocalFrame>(frame), - ImageDownloaderBase(frame.GetDocument()->GetExecutionContext(), frame) { + ContextLifecycleObserver(frame.GetDocument()->GetExecutionContext()) { frame.GetInterfaceRegistry()->AddInterface(WTF::BindRepeating( &ImageDownloaderImpl::CreateMojoService, WrapWeakPersistent(this))); } @@ -129,13 +151,25 @@ uint32_t max_bitmap_size, bool bypass_cache, DownloadImageCallback callback) { - WTF::Vector<SkBitmap> result_images; - WTF::Vector<gfx::Size> result_original_image_sizes; - - ImageDownloaderBase::DownloadImage( - image_url, is_favicon, bypass_cache, + auto download_callback = WTF::Bind(&ImageDownloaderImpl::DidDownloadImage, WrapPersistent(this), - max_bitmap_size, std::move(callback))); + max_bitmap_size, std::move(callback)); + + if (!image_url.ProtocolIsData()) { + FetchImage(image_url, is_favicon, bypass_cache, + std::move(download_callback)); + // Will complete asynchronously via ImageDownloaderImpl::DidFetchImage. + return; + } + + WTF::Vector<SkBitmap> result_images; + SkBitmap data_image = ImageFromDataUrl(image_url); + + // Drop null or empty SkBitmap. + if (!data_image.drawsNothing()) + result_images.push_back(data_image); + + std::move(download_callback).Run(0, result_images); } void ImageDownloaderImpl::DidDownloadImage( @@ -152,18 +186,58 @@ result_original_image_sizes); } -void ImageDownloaderImpl::ContextDestroyed(ExecutionContext* context) { - ImageDownloaderBase::ContextDestroyed(context); - Dispose(); -} - void ImageDownloaderImpl::Dispose() { binding_.Close(); } +void ImageDownloaderImpl::FetchImage(const KURL& image_url, + bool is_favicon, + bool bypass_cache, + DownloadCallback callback) { + // Create an image resource fetcher and assign it with a call back object. + image_fetchers_.push_back( + std::make_unique<MultiResolutionImageResourceFetcher>( + image_url, GetSupplementable(), 0, + is_favicon ? blink::mojom::RequestContextType::FAVICON + : blink::mojom::RequestContextType::IMAGE, + bypass_cache ? blink::mojom::FetchCacheMode::kBypassCache + : blink::mojom::FetchCacheMode::kDefault, + WTF::Bind(&ImageDownloaderImpl::DidFetchImage, WrapPersistent(this), + std::move(callback)))); +} + +void ImageDownloaderImpl::DidFetchImage( + DownloadCallback callback, + MultiResolutionImageResourceFetcher* fetcher, + const WTF::Vector<SkBitmap>& images) { + int32_t http_status_code = fetcher->http_status_code(); + + // Remove the image fetcher from our pending list. We're in the callback from + // MultiResolutionImageResourceFetcher, best to delay deletion. + for (auto* it = image_fetchers_.begin(); it != image_fetchers_.end(); ++it) { + MultiResolutionImageResourceFetcher* image_fetcher = it->get(); + DCHECK(image_fetcher); + if (image_fetcher == fetcher) { + it = image_fetchers_.erase(it); + break; + } + } + + // |this| may be destructed after callback is run. + std::move(callback).Run(http_status_code, images); +} + void ImageDownloaderImpl::Trace(Visitor* visitor) { Supplement<LocalFrame>::Trace(visitor); - ImageDownloaderBase::Trace(visitor); + ContextLifecycleObserver::Trace(visitor); +} + +void ImageDownloaderImpl::ContextDestroyed(ExecutionContext*) { + for (const auto& fetchers : image_fetchers_) { + // Will run callbacks with an empty image vector. + fetchers->OnRenderFrameDestruct(); + } + image_fetchers_.clear(); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.h b/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.h index a51c6f38f..9d768d57 100644 --- a/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.h +++ b/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.h
@@ -7,18 +7,19 @@ #include "mojo/public/cpp/bindings/binding.h" #include "third_party/blink/public/mojom/image_downloader/image_downloader.mojom-blink.h" -#include "third_party/blink/renderer/modules/image_downloader/image_downloader_base.h" +#include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h" #include "third_party/blink/renderer/platform/supplementable.h" namespace blink { class KURL; class LocalFrame; +class MultiResolutionImageResourceFetcher; class ImageDownloaderImpl final : public GarbageCollectedFinalized<ImageDownloaderImpl>, public Supplement<LocalFrame>, - public ImageDownloaderBase, + public ContextLifecycleObserver, public mojom::blink::ImageDownloader { USING_PRE_FINALIZER(ImageDownloaderImpl, Dispose); USING_GARBAGE_COLLECTED_MIXIN(ImageDownloaderImpl); @@ -29,17 +30,21 @@ explicit ImageDownloaderImpl(LocalFrame&); ~ImageDownloaderImpl() override; + using DownloadCallback = + base::OnceCallback<void(int32_t, const WTF::Vector<SkBitmap>&)>; + static ImageDownloaderImpl* From(LocalFrame&); static void ProvideTo(LocalFrame&); void Trace(Visitor*) override; - private: - // Override ImageDownloaderBase::ContextDestroyed(). + // OverContextLifecycleObserver overrides. void ContextDestroyed(ExecutionContext*) override; - // ImageDownloader implementation. + private: + // ImageDownloader implementation. Request to asynchronously download an + // image. When done, |callback| will be called. void DownloadImage(const KURL& url, bool is_favicon, uint32_t max_bitmap_size, @@ -62,6 +67,28 @@ // Called before the object gets garbage collected. void Dispose(); + // Requests to fetch an image. When done, the image downloader is notified by + // way of DidFetchImage. If the image is a favicon, cookies will not be sent + // nor accepted during download. If the image has multiple frames, all frames + // are returned. + void FetchImage(const KURL& image_url, + bool is_favicon, + bool bypass_cache, + DownloadCallback callback); + + // This callback is triggered when FetchImage completes, either + // successfully or with a failure. See FetchImage for more + // details. + void DidFetchImage(DownloadCallback callback, + MultiResolutionImageResourceFetcher* fetcher, + const WTF::Vector<SkBitmap>& images); + + typedef WTF::Vector<std::unique_ptr<MultiResolutionImageResourceFetcher>> + ImageResourceFetcherList; + + // ImageResourceFetchers schedule via FetchImage. + ImageResourceFetcherList image_fetchers_; + mojo::Binding<mojom::blink::ImageDownloader> binding_{this}; DISALLOW_COPY_AND_ASSIGN(ImageDownloaderImpl);
diff --git a/third_party/blink/renderer/modules/manifest/manifest_change_notifier.h b/third_party/blink/renderer/modules/manifest/manifest_change_notifier.h index 759b4f0d..b49e7f8b 100644 --- a/third_party/blink/renderer/modules/manifest/manifest_change_notifier.h +++ b/third_party/blink/renderer/modules/manifest/manifest_change_notifier.h
@@ -6,6 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_MANIFEST_MANIFEST_CHANGE_NOTIFIER_H_ #include "base/macros.h" +#include "mojo/public/cpp/bindings/associated_remote.h" #include "third_party/blink/public/mojom/manifest/manifest_observer.mojom-blink.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/heap/handle.h" @@ -30,7 +31,7 @@ void EnsureManifestChangeObserver(); Member<LocalFrame> frame_; - mojom::blink::ManifestUrlChangeObserverAssociatedPtr + mojo::AssociatedRemote<mojom::blink::ManifestUrlChangeObserver> manifest_change_observer_; bool report_task_scheduled_ = false;
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc index 7903f2e..8040fed 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
@@ -6,8 +6,9 @@ #include <memory> -#include "mojo/public/cpp/bindings/associated_binding.h" -#include "mojo/public/cpp/bindings/associated_interface_ptr.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "mojo/public/cpp/bindings/associated_remote.h" +#include "mojo/public/cpp/bindings/pending_associated_receiver.h" #include "services/device/public/mojom/screen_orientation.mojom-blink.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -63,7 +64,7 @@ class MockScreenOrientation final : public device::mojom::blink::ScreenOrientation { public: - MockScreenOrientation() : binding_(this) {} + MockScreenOrientation() = default; // device::mojom::blink::ScreenOrientation overrides: void LockOrientation(WebScreenOrientationLockType type, @@ -73,19 +74,21 @@ LockOrientation(type); } - void BindRequest( - device::mojom::blink::ScreenOrientationAssociatedRequest request) { - binding_.Bind(std::move(request)); + void BindPendingReceiver( + mojo::PendingAssociatedReceiver<device::mojom::blink::ScreenOrientation> + pending_receiver) { + receiver_.Bind(std::move(pending_receiver)); } - void Close() { binding_.Close(); } + void Close() { receiver_.reset(); } MOCK_METHOD0(UnlockOrientation, void()); MOCK_METHOD1(LockOrientation, void(WebScreenOrientationLockType)); private: - mojo::AssociatedBinding<device::mojom::blink::ScreenOrientation> binding_; + mojo::AssociatedReceiver<device::mojom::blink::ScreenOrientation> receiver_{ + this}; }; void DidEnterFullscreen(Document* document) { @@ -107,11 +110,12 @@ void InstallSupplements(LocalFrame& frame) override { EmptyChromeClient::InstallSupplements(frame); ScreenOrientationControllerImpl::ProvideTo(frame); - device::mojom::blink::ScreenOrientationAssociatedPtr screen_orientation; - ScreenOrientationClient().BindRequest( - mojo::MakeRequestAssociatedWithDedicatedPipe(&screen_orientation)); + mojo::AssociatedRemote<device::mojom::blink::ScreenOrientation> + screen_orientation; + ScreenOrientationClient().BindPendingReceiver( + screen_orientation.BindNewEndpointAndPassDedicatedReceiverForTesting()); ScreenOrientationControllerImpl::From(frame) - ->SetScreenOrientationAssociatedPtrForTests( + ->SetScreenOrientationAssociatedRemoteForTests( std::move(screen_orientation)); } // The real ChromeClient::EnterFullscreen/ExitFullscreen implementation is
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc index 0b438f9..af6efa41 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
@@ -4,7 +4,7 @@ #include "third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.h" -#include "mojo/public/cpp/bindings/associated_interface_ptr.h" +#include "mojo/public/cpp/bindings/associated_remote.h" #include "services/device/public/mojom/screen_orientation.mojom-blink.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -57,10 +57,12 @@ void InstallSupplements(LocalFrame& frame) override { EmptyChromeClient::InstallSupplements(frame); ScreenOrientationControllerImpl::ProvideTo(frame); - device::mojom::blink::ScreenOrientationAssociatedPtr screen_orientation; - mojo::MakeRequestAssociatedWithDedicatedPipe(&screen_orientation); + mojo::AssociatedRemote<device::mojom::blink::ScreenOrientation> + screen_orientation; + ignore_result( + screen_orientation.BindNewEndpointAndPassDedicatedReceiverForTesting()); ScreenOrientationControllerImpl::From(frame) - ->SetScreenOrientationAssociatedPtrForTests( + ->SetScreenOrientationAssociatedRemoteForTests( std::move(screen_orientation)); } void EnterFullscreen(LocalFrame& frame, const FullscreenOptions*) override {
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc index 2f6e044..c8fb6674 100644 --- a/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc +++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder.cc
@@ -319,7 +319,7 @@ return; } WriteData(nullptr /* data */, 0 /* length */, true /* lastInSlice */, - WTF::CurrentTimeMS()); + base::Time::Now().ToDoubleT() * 1000.0); } bool MediaRecorder::isTypeSupported(ExecutionContext* context, @@ -352,7 +352,7 @@ return; WriteData(nullptr /* data */, 0 /* length */, true /* lastInSlice */, - WTF::CurrentTimeMS()); + base::Time::Now().ToDoubleT() * 1000.0); stopped_ = true; stream_.Clear(); @@ -404,7 +404,7 @@ recorder_handler_->Stop(); WriteData(nullptr /* data */, 0 /* length */, true /* lastInSlice */, - WTF::CurrentTimeMS()); + base::Time::Now().ToDoubleT() * 1000.0); ScheduleDispatchEvent(Event::Create(event_type_names::kStop)); }
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc index 10fd72f..c6bea870 100644 --- a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc +++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.cc
@@ -119,7 +119,8 @@ audio_codec_id_(AudioTrackRecorder::CodecId::LAST), recording_(false), recorder_(nullptr), - task_runner_(std::move(task_runner)) {} + task_runner_(std::move(task_runner)), + weak_factory_(this) {} MediaRecorderHandler::~MediaRecorderHandler() = default; @@ -253,7 +254,7 @@ CodecIdToMediaAudioCodec(audio_codec_id_), use_video_tracks, use_audio_tracks, WTF::BindRepeating(&MediaRecorderHandler::WriteData, - WrapWeakPersistent(this)))); + weak_factory_.GetWeakPtr()))); if (use_video_tracks) { // TODO(mcasas): The muxer API supports only one video track. Extend it to @@ -266,7 +267,7 @@ const VideoTrackRecorder::OnEncodedVideoCB on_encoded_video_cb = media::BindToCurrentLoop(WTF::BindRepeating( - &MediaRecorderHandler::OnEncodedVideo, WrapWeakPersistent(this))); + &MediaRecorderHandler::OnEncodedVideo, weak_factory_.GetWeakPtr())); video_recorders_.emplace_back(MakeGarbageCollected<VideoTrackRecorder>( video_codec_id_, video_tracks_[0], on_encoded_video_cb, @@ -284,7 +285,7 @@ const AudioTrackRecorder::OnEncodedAudioCB on_encoded_audio_cb = media::BindToCurrentLoop(base::Bind( - &MediaRecorderHandler::OnEncodedAudio, WrapWeakPersistent(this))); + &MediaRecorderHandler::OnEncodedAudio, weak_factory_.GetWeakPtr())); audio_recorders_.emplace_back(MakeGarbageCollected<AudioTrackRecorder>( audio_codec_id_, audio_tracks_[0], std::move(on_encoded_audio_cb), @@ -299,6 +300,7 @@ DCHECK(IsMainThread()); // Don't check |recording_| since we can go directly from pause() to stop(). + weak_factory_.InvalidateWeakPtrs(); recording_ = false; timeslice_ = base::TimeDelta::FromMilliseconds(0); video_recorders_.clear(); @@ -458,9 +460,6 @@ bool is_key_frame) { DCHECK(IsMainThread()); - if (video_recorders_.IsEmpty()) - return; - if (UpdateTracksAndCheckIfChanged()) { recorder_->OnError("Amount of tracks in MediaStream has changed."); return; @@ -480,9 +479,6 @@ base::TimeTicks timestamp) { DCHECK(IsMainThread()); - if (audio_recorders_.IsEmpty()) - return; - if (UpdateTracksAndCheckIfChanged()) { recorder_->OnError("Amount of tracks in MediaStream has changed."); return;
diff --git a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h index 7c3da873..f979b4ba 100644 --- a/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h +++ b/third_party/blink/renderer/modules/mediarecorder/media_recorder_handler.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_piece.h" #include "base/threading/thread_checker.h" @@ -139,6 +140,8 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + base::WeakPtrFactory<MediaRecorderHandler> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(MediaRecorderHandler); };
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index 0298705..cf616ab 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -219,7 +219,6 @@ "mediastream/media_stream_track_event.idl", "mediastream/overconstrained_error.idl", "native_file_system/native_file_system_directory_iterator.idl", - "native_file_system/native_file_system_writable_file_stream.idl", "native_file_system/file_system_directory_handle.idl", "native_file_system/file_system_file_handle.idl", "native_file_system/file_system_handle.idl",
diff --git a/third_party/blink/renderer/modules/native_file_system/BUILD.gn b/third_party/blink/renderer/modules/native_file_system/BUILD.gn index 3470b58e..3fa676a9 100644 --- a/third_party/blink/renderer/modules/native_file_system/BUILD.gn +++ b/third_party/blink/renderer/modules/native_file_system/BUILD.gn
@@ -14,8 +14,6 @@ "native_file_system_file_handle.h", "native_file_system_handle.cc", "native_file_system_handle.h", - "native_file_system_writable_file_stream.cc", - "native_file_system_writable_file_stream.h", "native_file_system_writer.cc", "native_file_system_writer.h", "window_native_file_system.cc",
diff --git a/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl b/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl index 2dc91c5c..1b9f6375 100644 --- a/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl +++ b/third_party/blink/renderer/modules/native_file_system/file_system_file_handle.idl
@@ -10,6 +10,5 @@ ImplementedAs=NativeFileSystemFileHandle ] interface FileSystemFileHandle : FileSystemHandle { [CallWith=ScriptState] Promise<FileSystemWriter> createWriter(); - [CallWith=ScriptState] Promise<FileSystemWritableFileStream> createWritable(); [CallWith=ScriptState] Promise<File> getFile(); };
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc index aadd59b..b385ee5 100644 --- a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc +++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.cc
@@ -11,7 +11,6 @@ #include "third_party/blink/renderer/core/dom/dom_exception.h" #include "third_party/blink/renderer/core/fileapi/file.h" #include "third_party/blink/renderer/core/fileapi/file_error.h" -#include "third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h" #include "third_party/blink/renderer/modules/native_file_system/native_file_system_writer.h" #include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/wtf/functional.h" @@ -52,32 +51,6 @@ return result; } -ScriptPromise NativeFileSystemFileHandle::createWritable( - ScriptState* script_state) { - auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); - ScriptPromise result = resolver->Promise(); - - mojo_ptr_->CreateFileWriter(WTF::Bind( - [](ScriptPromiseResolver* resolver, - mojom::blink::NativeFileSystemErrorPtr result, - mojom::blink::NativeFileSystemFileWriterPtr writer) { - ExecutionContext* context = resolver->GetExecutionContext(); - if (!context) - return; - if (result->error_code == base::File::FILE_OK) { - resolver->Resolve(MakeGarbageCollected< - NativeFileSystemWritableFileStream>( - RevocableInterfacePtr<mojom::blink::NativeFileSystemFileWriter>( - writer.PassInterface(), context->GetInterfaceInvalidator(), - context->GetTaskRunner(TaskType::kMiscPlatformAPI)))); - } else { - resolver->Reject(file_error::CreateDOMException(result->error_code)); - } - }, - WrapPersistent(resolver))); - return result; -} - ScriptPromise NativeFileSystemFileHandle::getFile(ScriptState* script_state) { auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise result = resolver->Promise();
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h index 88586f5f..fe24da2 100644 --- a/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h +++ b/third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h
@@ -22,7 +22,6 @@ bool isFile() const override { return true; } ScriptPromise createWriter(ScriptState*); - ScriptPromise createWritable(ScriptState*); ScriptPromise getFile(ScriptState*); mojom::blink::NativeFileSystemTransferTokenPtr Transfer() override;
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.cc b/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.cc deleted file mode 100644 index 395abea1..0000000 --- a/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.cc +++ /dev/null
@@ -1,175 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h" - -#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h" -#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_blob.h" -#include "third_party/blink/renderer/core/dom/dom_exception.h" -#include "third_party/blink/renderer/core/fileapi/blob.h" -#include "third_party/blink/renderer/core/fileapi/file_error.h" -#include "third_party/blink/renderer/modules/native_file_system/native_file_system_file_handle.h" -#include "third_party/blink/renderer/platform/blob/blob_data.h" -#include "third_party/blink/renderer/platform/wtf/functional.h" - -namespace blink { - -NativeFileSystemWritableFileStream::NativeFileSystemWritableFileStream( - RevocableInterfacePtr<mojom::blink::NativeFileSystemFileWriter> mojo_ptr) - : mojo_ptr_(std::move(mojo_ptr)) { - DCHECK(mojo_ptr_); -} - -ScriptPromise NativeFileSystemWritableFileStream::write( - ScriptState* script_state, - uint64_t position, - const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data, - ExceptionState& exception_state) { - DCHECK(!data.IsNull()); - - auto blob_data = std::make_unique<BlobData>(); - Blob* blob = nullptr; - if (data.IsArrayBuffer()) { - DOMArrayBuffer* array_buffer = data.GetAsArrayBuffer(); - blob_data->AppendBytes(array_buffer->Data(), array_buffer->ByteLength()); - } else if (data.IsArrayBufferView()) { - DOMArrayBufferView* array_buffer_view = data.GetAsArrayBufferView().View(); - blob_data->AppendBytes(array_buffer_view->BaseAddress(), - array_buffer_view->byteLength()); - } else if (data.IsBlob()) { - blob = data.GetAsBlob(); - } else if (data.IsUSVString()) { - // Let the developer be explicit about line endings. - blob_data->AppendText(data.GetAsUSVString(), - /*normalize_line_endings_to_native=*/false); - } - - if (!blob) { - uint64_t size = blob_data->length(); - blob = Blob::Create(BlobDataHandle::Create(std::move(blob_data), size)); - } - - return WriteBlob(script_state, position, blob); -} - -ScriptPromise NativeFileSystemWritableFileStream::truncate( - ScriptState* script_state, - uint64_t size) { - if (!mojo_ptr_ || pending_operation_) { - return ScriptPromise::RejectWithDOMException( - script_state, MakeGarbageCollected<DOMException>( - DOMExceptionCode::kInvalidStateError)); - } - pending_operation_ = - MakeGarbageCollected<ScriptPromiseResolver>(script_state); - ScriptPromise result = pending_operation_->Promise(); - mojo_ptr_->Truncate( - size, WTF::Bind(&NativeFileSystemWritableFileStream::TruncateComplete, - WrapPersistent(this))); - return result; -} - -void NativeFileSystemWritableFileStream::WriteComplete( - mojom::blink::NativeFileSystemErrorPtr result, - uint64_t bytes_written) { - DCHECK(pending_operation_); - if (result->error_code == base::File::FILE_OK) { - pending_operation_->Resolve(); - } else { - pending_operation_->Reject( - file_error::CreateDOMException(result->error_code)); - } - pending_operation_ = nullptr; -} - -void NativeFileSystemWritableFileStream::TruncateComplete( - mojom::blink::NativeFileSystemErrorPtr result) { - DCHECK(pending_operation_); - if (result->error_code == base::File::FILE_OK) { - pending_operation_->Resolve(); - } else { - pending_operation_->Reject( - file_error::CreateDOMException(result->error_code)); - } - pending_operation_ = nullptr; -} - -ScriptPromise NativeFileSystemWritableFileStream::WriteBlob( - ScriptState* script_state, - uint64_t position, - Blob* blob) { - if (!mojo_ptr_ || pending_operation_) { - return ScriptPromise::RejectWithDOMException( - script_state, MakeGarbageCollected<DOMException>( - DOMExceptionCode::kInvalidStateError)); - } - pending_operation_ = - MakeGarbageCollected<ScriptPromiseResolver>(script_state); - ScriptPromise result = pending_operation_->Promise(); - mojo_ptr_->Write(position, blob->AsMojoBlob(), - WTF::Bind(&NativeFileSystemWritableFileStream::WriteComplete, - WrapPersistent(this))); - return result; -} - -ScriptPromise NativeFileSystemWritableFileStream::abort( - ScriptState* script_state, - ExceptionState& exception_state) { - return ScriptPromise::RejectWithDOMException( - script_state, - MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError)); -} - -ScriptPromise NativeFileSystemWritableFileStream::abort( - ScriptState* script_state, - ScriptValue reason, - ExceptionState& exception_state) { - return ScriptPromise::RejectWithDOMException( - script_state, - MakeGarbageCollected<DOMException>(DOMExceptionCode::kNotSupportedError)); -} - -ScriptValue NativeFileSystemWritableFileStream::getWriter( - ScriptState* script_state, - ExceptionState& exception_state) { - exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, - "Not Implemented"); - return ScriptValue(); -} - -bool NativeFileSystemWritableFileStream::locked( - ScriptState* script_state, - ExceptionState& exception_state) const { - auto result = IsLocked(script_state, exception_state); - - exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, - "Not Implemented"); - return !result || *result; -} - -base::Optional<bool> NativeFileSystemWritableFileStream::IsLocked( - ScriptState* script_state, - ExceptionState& exception_state) const { - exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, - "Not Implemented"); - return base::nullopt; -} - -void NativeFileSystemWritableFileStream::Serialize( - ScriptState* script_state, - MessagePort* port, - ExceptionState& exception_state) { - DCHECK(port); - DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled()); - exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError, - "Not Implemented"); -} - -void NativeFileSystemWritableFileStream::Trace(Visitor* visitor) { - ScriptWrappable::Trace(visitor); - visitor->Trace(pending_operation_); -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h b/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h deleted file mode 100644 index 2f17f7d..0000000 --- a/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.h +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_ - -#include "third_party/blink/public/mojom/native_file_system/native_file_system_error.mojom-blink.h" -#include "third_party/blink/public/mojom/native_file_system/native_file_system_file_writer.mojom-blink.h" -#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h" -#include "third_party/blink/renderer/core/streams/writable_stream.h" -#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" -#include "third_party/blink/renderer/platform/mojo/revocable_interface_ptr.h" - -namespace blink { - -class Blob; -class ExceptionState; -class ScriptPromise; -class ScriptPromiseResolver; -class ScriptState; - -class NativeFileSystemWritableFileStream final : public WritableStream { - DEFINE_WRAPPERTYPEINFO(); - - public: - explicit NativeFileSystemWritableFileStream( - RevocableInterfacePtr<mojom::blink::NativeFileSystemFileWriter>); - - void Trace(Visitor* visitor) override; - - // IDL defined functions for WritableStream. - bool locked(ScriptState*, ExceptionState&) const override; - ScriptPromise abort(ScriptState*, ExceptionState&) override; - ScriptPromise abort(ScriptState*, - ScriptValue reason, - ExceptionState&) override; - ScriptValue getWriter(ScriptState*, ExceptionState&) override; - void Serialize(ScriptState*, MessagePort* port, ExceptionState&) override; - base::Optional<bool> IsLocked(ScriptState*, ExceptionState&) const override; - - // IDL defined functions specific to NativeFileSystemWritableFileStream. - ScriptPromise write(ScriptState*, - uint64_t position, - const ArrayBufferOrArrayBufferViewOrBlobOrUSVString& data, - ExceptionState&); - ScriptPromise truncate(ScriptState*, uint64_t size); - - private: - ScriptPromise WriteBlob(ScriptState*, uint64_t position, Blob*); - - void WriteComplete(mojom::blink::NativeFileSystemErrorPtr result, - uint64_t bytes_written); - void TruncateComplete(mojom::blink::NativeFileSystemErrorPtr result); - - RevocableInterfacePtr<mojom::blink::NativeFileSystemFileWriter> mojo_ptr_; - - Member<ScriptPromiseResolver> pending_operation_; -}; -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_NATIVE_FILE_SYSTEM_NATIVE_FILE_SYSTEM_WRITABLE_FILE_STREAM_H_
diff --git a/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.idl b/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.idl deleted file mode 100644 index 81435e3a..0000000 --- a/third_party/blink/renderer/modules/native_file_system/native_file_system_writable_file_stream.idl +++ /dev/null
@@ -1,12 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// https://wicg.github.io/native-file-system/#filesystemwritablefilestream -[ - RuntimeEnabled=NativeFileSystem, - ImplementedAs=NativeFileSystemWritableFileStream - ] interface NativeFileSystemWritableFileStream : WritableStream { - [CallWith=ScriptState, RaisesException] Promise<void> write(unsigned long long position, (BufferSource or Blob or USVString) data); - [CallWith=ScriptState] Promise<void> truncate(unsigned long long size); - };
diff --git a/third_party/blink/renderer/modules/notifications/notification_data.cc b/third_party/blink/renderer/modules/notifications/notification_data.cc index cf54e46..efc43ca 100644 --- a/third_party/blink/renderer/modules/notifications/notification_data.cc +++ b/third_party/blink/renderer/modules/notifications/notification_data.cc
@@ -83,7 +83,7 @@ vibration_pattern.size()); notification_data->timestamp = options->hasTimestamp() ? static_cast<double>(options->timestamp()) - : WTF::CurrentTimeMS(); + : base::Time::Now().ToDoubleT() * 1000.0; notification_data->renotify = options->renotify(); notification_data->silent = options->silent(); notification_data->require_interaction = options->requireInteraction();
diff --git a/third_party/blink/renderer/modules/notifications/notification_data_test.cc b/third_party/blink/renderer/modules/notifications/notification_data_test.cc index 8aff9e7..1676bb0 100644 --- a/third_party/blink/renderer/modules/notifications/notification_data_test.cc +++ b/third_party/blink/renderer/modules/notifications/notification_data_test.cc
@@ -99,7 +99,7 @@ actions.push_back(action); } - DOMTimeStamp showTimestamp = WTF::CurrentTimeMS(); + DOMTimeStamp showTimestamp = base::Time::Now().ToDoubleT() * 1000.0; TimestampTrigger* showTrigger = TimestampTrigger::Create(showTimestamp); NotificationOptions* options = NotificationOptions::Create(); @@ -286,7 +286,8 @@ // The timestamp should be set to the current time since the epoch if it // wasn't supplied by the developer. "32" has no significance, but an equal // comparison of the value could lead to flaky failures. - EXPECT_NEAR(notification_data->timestamp, WTF::CurrentTimeMS(), 32); + EXPECT_NEAR(notification_data->timestamp, + base::Time::Now().ToDoubleT() * 1000.0, 32); } TEST_F(NotificationDataTest, DirectionValues) {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc index 14d33d68..f01a8c90 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -656,7 +656,8 @@ // Make sure no certificates have expired. if (!configuration.certificates.empty()) { - DOMTimeStamp now = ConvertSecondsToDOMTimeStamp(CurrentTime()); + DOMTimeStamp now = + ConvertSecondsToDOMTimeStamp(base::Time::Now().ToDoubleT()); for (const rtc::scoped_refptr<rtc::RTCCertificate>& certificate : configuration.certificates) { DOMTimeStamp expires = certificate->Expires(); @@ -1876,6 +1877,12 @@ return String(); } +void RTCPeerConnection::restartIce() { + if (closed_) + return; + peer_handler_->RestartIce(); +} + void RTCPeerConnection::addStream(ScriptState* script_state, MediaStream* stream, const Dictionary& media_constraints,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h index 894c210e..1cd005d 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
@@ -193,6 +193,8 @@ String connectionState() const; + void restartIce(); + // A local stream is any stream associated with a sender. MediaStreamVector getLocalStreams() const; // A remote stream is any stream associated with a receiver.
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl index 49a9464..1987ea8 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl +++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.idl
@@ -86,6 +86,7 @@ readonly attribute RTCIceConnectionState iceConnectionState; readonly attribute RTCPeerConnectionState connectionState; // readonly attribute boolean? canTrickleIceCandidates; + void restartIce(); [CallWith=ScriptState] RTCConfiguration getConfiguration(); [CallWith=ScriptState, RaisesException] void setConfiguration(RTCConfiguration configuration); void close();
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc index 149fcd9c..1b15dde 100644 --- a/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc +++ b/third_party/blink/renderer/modules/peerconnection/rtc_quic_transport.cc
@@ -124,7 +124,8 @@ return nullptr; } for (const auto& certificate : certificates) { - if (certificate->expires() < ConvertSecondsToDOMTimeStamp(CurrentTime())) { + if (certificate->expires() < + ConvertSecondsToDOMTimeStamp(base::Time::Now().ToDoubleT())) { exception_state.ThrowTypeError( "Cannot construct an RTCQuicTransport with an expired " "certificate.");
diff --git a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.cc b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.cc index 5ffd5ba3..eecfa9c 100644 --- a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.cc +++ b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.cc
@@ -214,7 +214,7 @@ } void ScreenOrientationControllerImpl::ContextDestroyed(ExecutionContext*) { - screen_orientation_service_ = nullptr; + screen_orientation_service_.reset(); active_lock_ = false; } @@ -225,9 +225,11 @@ Supplement<LocalFrame>::Trace(visitor); } -void ScreenOrientationControllerImpl::SetScreenOrientationAssociatedPtrForTests( - ScreenOrientationAssociatedPtr screen_orientation_associated_ptr) { - screen_orientation_service_ = std::move(screen_orientation_associated_ptr); +void ScreenOrientationControllerImpl:: + SetScreenOrientationAssociatedRemoteForTests( + mojo::AssociatedRemote<device::mojom::blink::ScreenOrientation> + remote) { + screen_orientation_service_ = std::move(remote); } void ScreenOrientationControllerImpl::OnLockOrientationResult(
diff --git a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.h b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.h index 23a9e4a..55adcb80 100644 --- a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.h +++ b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "mojo/public/cpp/bindings/associated_remote.h" #include "services/device/public/mojom/screen_orientation.mojom-blink.h" #include "third_party/blink/public/common/screen_orientation/web_screen_orientation_lock_type.h" #include "third_party/blink/public/common/screen_orientation/web_screen_orientation_type.h" @@ -21,7 +22,6 @@ class ScreenOrientation; -using device::mojom::blink::ScreenOrientationAssociatedPtr; using device::mojom::blink::ScreenOrientationLockResult; class MODULES_EXPORT ScreenOrientationControllerImpl final @@ -46,8 +46,8 @@ static void ProvideTo(LocalFrame&); static ScreenOrientationControllerImpl* From(LocalFrame&); - void SetScreenOrientationAssociatedPtrForTests( - ScreenOrientationAssociatedPtr); + void SetScreenOrientationAssociatedRemoteForTests( + mojo::AssociatedRemote<device::mojom::blink::ScreenOrientation>); void Trace(blink::Visitor*) override; @@ -73,7 +73,8 @@ Member<ScreenOrientation> orientation_; bool active_lock_ = false; - ScreenOrientationAssociatedPtr screen_orientation_service_; + mojo::AssociatedRemote<device::mojom::blink::ScreenOrientation> + screen_orientation_service_; std::unique_ptr<WebLockOrientationCallback> pending_callback_; int request_id_ = 0;
diff --git a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl_test.cc b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl_test.cc index bc0ccd0..1cb575c 100644 --- a/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl_test.cc +++ b/third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller_impl_test.cc
@@ -6,7 +6,7 @@ #include <memory> -#include "mojo/public/cpp/bindings/associated_interface_ptr.h" +#include "mojo/public/cpp/bindings/associated_remote.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/modules/screen_orientation/web_lock_orientation_callback.h" @@ -54,14 +54,17 @@ void SetUp() override { PageTestBase::SetUp(IntSize()); ScreenOrientationControllerImpl::ProvideTo(GetFrame()); - device::mojom::blink::ScreenOrientationAssociatedPtr screen_orientation; - mojo::MakeRequestAssociatedWithDedicatedPipe(&screen_orientation); - Controller()->SetScreenOrientationAssociatedPtrForTests( + mojo::AssociatedRemote<device::mojom::blink::ScreenOrientation> + screen_orientation; + ignore_result( + screen_orientation.BindNewEndpointAndPassDedicatedReceiverForTesting()); + Controller()->SetScreenOrientationAssociatedRemoteForTests( std::move(screen_orientation)); } void TearDown() override { - Controller()->SetScreenOrientationAssociatedPtrForTests(nullptr); + Controller()->SetScreenOrientationAssociatedRemoteForTests( + mojo::AssociatedRemote<device::mojom::blink::ScreenOrientation>()); } ScreenOrientationControllerImpl* Controller() {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc index 6049ac24..ef8408c 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -380,7 +380,7 @@ void ServiceWorkerGlobalScope::Dispose() { DCHECK(IsContextThread()); - controller_bindings_.CloseAllBindings(); + controller_receivers_.Clear(); timeout_timer_.reset(); service_worker_host_.reset(); binding_.Close(); @@ -626,14 +626,14 @@ } void ServiceWorkerGlobalScope::BindControllerServiceWorker( - mojom::blink::ControllerServiceWorkerRequest request) { + mojo::PendingReceiver<mojom::blink::ControllerServiceWorker> receiver) { DCHECK(IsContextThread()); - DCHECK(controller_bindings_.empty()); + DCHECK(controller_receivers_.empty()); // TODO(falken): Consider adding task types for "the handle fetch task source" // and "handle functional event task source" defined in the service worker // spec and use them when dispatching events. - controller_bindings_.AddBinding( - this, std::move(request), + controller_receivers_.Add( + this, std::move(receiver), GetThread()->GetTaskRunner(TaskType::kInternalDefault)); } @@ -1440,10 +1440,10 @@ } void ServiceWorkerGlobalScope::Clone( - mojom::blink::ControllerServiceWorkerRequest request) { + mojo::PendingReceiver<mojom::blink::ControllerServiceWorker> receiver) { DCHECK(IsContextThread()); - controller_bindings_.AddBinding( - this, std::move(request), + controller_receivers_.Add( + this, std::move(receiver), GetThread()->GetTaskRunner(TaskType::kInternalDefault)); }
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h index d6fbc9e..3ea3f4f 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -32,7 +32,8 @@ #include <memory> #include "mojo/public/cpp/bindings/binding.h" -#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/public/cpp/bindings/pending_receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h" #include "third_party/blink/public/mojom/service_worker/controller_service_worker.mojom-blink.h" #include "third_party/blink/public/mojom/service_worker/service_worker.mojom-blink.h" @@ -148,7 +149,7 @@ void BindServiceWorker(mojom::blink::ServiceWorkerRequest); void BindControllerServiceWorker( - mojom::blink::ControllerServiceWorkerRequest); + mojo::PendingReceiver<mojom::blink::ControllerServiceWorker>); void OnNavigationPreloadResponse( int fetch_event_id, std::unique_ptr<WebURLResponse>, @@ -355,7 +356,8 @@ mojom::blink::DispatchFetchEventParamsPtr params, mojom::blink::ServiceWorkerFetchResponseCallbackPtr response_callback, DispatchFetchEventForSubresourceCallback callback) override; - void Clone(mojom::blink::ControllerServiceWorkerRequest request) override; + void Clone(mojo::PendingReceiver<mojom::blink::ControllerServiceWorker> + reciever) override; // Implements mojom::blink::ServiceWorker. void InitializeGlobalScope( @@ -522,7 +524,8 @@ // |timeout_timer_| since the pipe needs to be disconnected before callbacks // passed by DispatchSomeEvent() get destructed, which may be stored in // |timeout_timer_| - mojo::BindingSet<mojom::blink::ControllerServiceWorker> controller_bindings_; + mojo::ReceiverSet<mojom::blink::ControllerServiceWorker> + controller_receivers_; }; template <>
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc index 63762d1..d1a89c0 100644 --- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc +++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -89,7 +89,8 @@ mojo::ScopedMessagePipeHandle request) { DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_); WorkerGlobalScope()->BindControllerServiceWorker( - mojom::blink::ControllerServiceWorkerRequest(std::move(request))); + mojo::PendingReceiver<mojom::blink::ControllerServiceWorker>( + std::move(request))); } void ServiceWorkerGlobalScopeProxy::OnNavigationPreloadResponse(
diff --git a/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc b/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc index e3007ce..27c599799 100644 --- a/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc +++ b/third_party/blink/renderer/modules/shapedetection/barcode_detector.cc
@@ -131,7 +131,7 @@ point->setY(corner_point.y); corner_points.push_back(point); } - detected_barcodes.push_back(DetectedBarcode::Create( + detected_barcodes.push_back(MakeGarbageCollected<DetectedBarcode>( barcode->raw_value, DOMRectReadOnly::Create( barcode->bounding_box.x, barcode->bounding_box.y,
diff --git a/third_party/blink/renderer/modules/shapedetection/barcode_detector.idl b/third_party/blink/renderer/modules/shapedetection/barcode_detector.idl index 86f6a7f..f7c5ce69 100644 --- a/third_party/blink/renderer/modules/shapedetection/barcode_detector.idl +++ b/third_party/blink/renderer/modules/shapedetection/barcode_detector.idl
@@ -8,6 +8,7 @@ Constructor(optional BarcodeDetectorOptions barcodeDetectorOptions), ConstructorCallWith=ExecutionContext, Exposed=(Window,Worker), + SecureContext, MeasureAs=ShapeDetection_BarcodeDetectorConstructor, RaisesException=Constructor, RuntimeEnabled=ShapeDetection
diff --git a/third_party/blink/renderer/modules/shapedetection/detected_barcode.cc b/third_party/blink/renderer/modules/shapedetection/detected_barcode.cc index c4a1bb2..9d2467c 100644 --- a/third_party/blink/renderer/modules/shapedetection/detected_barcode.cc +++ b/third_party/blink/renderer/modules/shapedetection/detected_barcode.cc
@@ -4,79 +4,44 @@ #include "third_party/blink/renderer/modules/shapedetection/detected_barcode.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" #include "third_party/blink/renderer/core/geometry/dom_rect.h" +#include "third_party/blink/renderer/modules/imagecapture/point_2d.h" namespace blink { -DetectedBarcode* DetectedBarcode::Create() { - HeapVector<Member<Point2D>> empty_list; - return MakeGarbageCollected<DetectedBarcode>( - g_empty_string, DOMRectReadOnly::Create(0, 0, 0, 0), - shape_detection::mojom::BarcodeFormat::UNKNOWN, empty_list); -} - -DetectedBarcode* DetectedBarcode::Create( - String raw_value, - DOMRectReadOnly* bounding_box, - shape_detection::mojom::BarcodeFormat format, - HeapVector<Member<Point2D>> corner_points) { - return MakeGarbageCollected<DetectedBarcode>(raw_value, bounding_box, format, - corner_points); -} - // static -WebString DetectedBarcode::BarcodeFormatToString( +String DetectedBarcode::BarcodeFormatToString( const shape_detection::mojom::BarcodeFormat format) { switch (format) { case shape_detection::mojom::BarcodeFormat::AZTEC: - return WebString::FromUTF8("aztec"); + return "aztec"; case shape_detection::mojom::BarcodeFormat::CODE_128: - return WebString::FromUTF8("code_128"); + return "code_128"; case shape_detection::mojom::BarcodeFormat::CODE_39: - return WebString::FromUTF8("code_39"); + return "code_39"; case shape_detection::mojom::BarcodeFormat::CODE_93: - return WebString::FromUTF8("code_93"); + return "code_93"; case shape_detection::mojom::BarcodeFormat::CODABAR: - return WebString::FromUTF8("codabar"); + return "codabar"; case shape_detection::mojom::BarcodeFormat::DATA_MATRIX: - return WebString::FromUTF8("data_matrix"); + return "data_matrix"; case shape_detection::mojom::BarcodeFormat::EAN_13: - return WebString::FromUTF8("ean_13"); + return "ean_13"; case shape_detection::mojom::BarcodeFormat::EAN_8: - return WebString::FromUTF8("ean_8"); + return "ean_8"; case shape_detection::mojom::BarcodeFormat::ITF: - return WebString::FromUTF8("itf"); + return "itf"; case shape_detection::mojom::BarcodeFormat::PDF417: - return WebString::FromUTF8("pdf417"); + return "pdf417"; case shape_detection::mojom::BarcodeFormat::QR_CODE: - return WebString::FromUTF8("qr_code"); + return "qr_code"; case shape_detection::mojom::BarcodeFormat::UNKNOWN: - return WebString::FromUTF8("unknown"); + return "unknown"; case shape_detection::mojom::BarcodeFormat::UPC_A: - return WebString::FromUTF8("upc_a"); + return "upc_a"; case shape_detection::mojom::BarcodeFormat::UPC_E: - return WebString::FromUTF8("upc_e"); - default: - NOTREACHED() << "Invalid BarcodeFormat"; + return "upc_e"; } - return WebString(); -} - -const String& DetectedBarcode::rawValue() const { - return raw_value_; -} - -DOMRectReadOnly* DetectedBarcode::boundingBox() const { - return bounding_box_.Get(); -} - -const HeapVector<Member<Point2D>>& DetectedBarcode::cornerPoints() const { - return corner_points_; -} - -String DetectedBarcode::format() const { - return DetectedBarcode::BarcodeFormatToString(format_); } DetectedBarcode::DetectedBarcode(String raw_value, @@ -88,22 +53,6 @@ format_(format), corner_points_(corner_points) {} -ScriptValue DetectedBarcode::toJSONForBinding(ScriptState* script_state) const { - V8ObjectBuilder result(script_state); - result.AddString("rawValue", rawValue()); - result.Add("boundingBox", boundingBox()->toJSONForBinding(script_state)); - result.AddString("format", format()); - Vector<ScriptValue> corner_points; - for (const auto& corner_point : corner_points_) { - V8ObjectBuilder builder(script_state); - builder.AddNumber("x", corner_point->x()); - builder.AddNumber("y", corner_point->y()); - corner_points.push_back(builder.GetScriptValue()); - } - result.Add("cornerPoints", corner_points); - return result.GetScriptValue(); -} - void DetectedBarcode::Trace(blink::Visitor* visitor) { visitor->Trace(bounding_box_); visitor->Trace(corner_points_);
diff --git a/third_party/blink/renderer/modules/shapedetection/detected_barcode.h b/third_party/blink/renderer/modules/shapedetection/detected_barcode.h index d4eaeef..560433c 100644 --- a/third_party/blink/renderer/modules/shapedetection/detected_barcode.h +++ b/third_party/blink/renderer/modules/shapedetection/detected_barcode.h
@@ -6,9 +6,6 @@ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_BARCODE_H_ #include "services/shape_detection/public/mojom/barcodedetection_provider.mojom-blink.h" -#include "third_party/blink/public/platform/web_string.h" -#include "third_party/blink/renderer/bindings/core/v8/script_value.h" -#include "third_party/blink/renderer/modules/imagecapture/point_2d.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -16,17 +13,13 @@ namespace blink { class DOMRectReadOnly; +class Point2D; class MODULES_EXPORT DetectedBarcode final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - static DetectedBarcode* Create(); - static DetectedBarcode* Create(String, - DOMRectReadOnly*, - shape_detection::mojom::BarcodeFormat, - HeapVector<Member<Point2D>>); - static WebString BarcodeFormatToString( + static String BarcodeFormatToString( const shape_detection::mojom::BarcodeFormat format); DetectedBarcode(String, @@ -34,12 +27,13 @@ shape_detection::mojom::BarcodeFormat, HeapVector<Member<Point2D>>); - const String& rawValue() const; - DOMRectReadOnly* boundingBox() const; - String format() const; - const HeapVector<Member<Point2D>>& cornerPoints() const; + const String& rawValue() const { return raw_value_; } + DOMRectReadOnly* boundingBox() const { return bounding_box_; } + String format() const { return BarcodeFormatToString(format_); } + const HeapVector<Member<Point2D>>& cornerPoints() const { + return corner_points_; + } - ScriptValue toJSONForBinding(ScriptState*) const; void Trace(blink::Visitor*) override; private:
diff --git a/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl b/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl index aa14784..740717e 100644 --- a/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl +++ b/third_party/blink/renderer/modules/shapedetection/detected_barcode.idl
@@ -5,8 +5,9 @@ // https://wicg.github.io/shape-detection-api/#barcode-detection-api [ - Constructor, Serializable, + Exposed=(Window,Worker), + SecureContext, RuntimeEnabled=ShapeDetection ] interface DetectedBarcode { // TODO(mcasas): Implement missing fields. https://crbug.com/646083 @@ -16,7 +17,4 @@ // 4 corner points in clockwise direction starting with top-left. Due to // possible perspective distortions, this is not necessarily a rectangle. [SameObject, SaveSameObject] readonly attribute FrozenArray<Point2D> cornerPoints; - - // TODO(peria): toJSON is not in spec. https://crbug.com/736332 - [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON(); };
diff --git a/third_party/blink/renderer/modules/shapedetection/detected_face.cc b/third_party/blink/renderer/modules/shapedetection/detected_face.cc index beb88c6..bf873d9 100644 --- a/third_party/blink/renderer/modules/shapedetection/detected_face.cc +++ b/third_party/blink/renderer/modules/shapedetection/detected_face.cc
@@ -4,62 +4,15 @@ #include "third_party/blink/renderer/modules/shapedetection/detected_face.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" #include "third_party/blink/renderer/core/geometry/dom_rect.h" +#include "third_party/blink/renderer/modules/shapedetection/landmark.h" namespace blink { -DetectedFace* DetectedFace::Create() { - return MakeGarbageCollected<DetectedFace>( - DOMRectReadOnly::Create(0, 0, 0, 0)); -} - -DetectedFace* DetectedFace::Create(DOMRectReadOnly* bounding_box) { - return MakeGarbageCollected<DetectedFace>(bounding_box); -} - -DetectedFace* DetectedFace::Create( - DOMRectReadOnly* bounding_box, - const HeapVector<Member<Landmark>>& landmarks) { - return MakeGarbageCollected<DetectedFace>(bounding_box, landmarks); -} - -DOMRectReadOnly* DetectedFace::boundingBox() const { - return bounding_box_.Get(); -} - -const HeapVector<Member<Landmark>>& DetectedFace::landmarks() const { - return landmarks_; -} - -DetectedFace::DetectedFace(DOMRectReadOnly* bounding_box) - : bounding_box_(bounding_box) {} - DetectedFace::DetectedFace(DOMRectReadOnly* bounding_box, const HeapVector<Member<Landmark>>& landmarks) : bounding_box_(bounding_box), landmarks_(landmarks) {} -ScriptValue DetectedFace::toJSONForBinding(ScriptState* script_state) const { - V8ObjectBuilder result(script_state); - result.Add("boundingBox", boundingBox()->toJSONForBinding(script_state)); - Vector<ScriptValue> landmarks; - for (const auto& landmark : landmarks_) { - V8ObjectBuilder landmark_builder(script_state); - landmark_builder.AddString("type", landmark->type()); - Vector<ScriptValue> locations; - for (const auto& location : landmark->locations()) { - V8ObjectBuilder location_builder(script_state); - location_builder.AddNumber("x", location->x()); - location_builder.AddNumber("y", location->y()); - locations.push_back(location_builder.GetScriptValue()); - } - landmark_builder.Add("locations", locations); - landmarks.push_back(landmark_builder.GetScriptValue()); - } - result.Add("landmarks", landmarks); - return result.GetScriptValue(); -} - void DetectedFace::Trace(blink::Visitor* visitor) { visitor->Trace(bounding_box_); visitor->Trace(landmarks_);
diff --git a/third_party/blink/renderer/modules/shapedetection/detected_face.h b/third_party/blink/renderer/modules/shapedetection/detected_face.h index 40be303..db8828f 100644 --- a/third_party/blink/renderer/modules/shapedetection/detected_face.h +++ b/third_party/blink/renderer/modules/shapedetection/detected_face.h
@@ -5,31 +5,23 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_FACE_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_FACE_H_ -#include "third_party/blink/renderer/bindings/core/v8/script_value.h" #include "third_party/blink/renderer/modules/modules_export.h" -#include "third_party/blink/renderer/modules/shapedetection/landmark.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" namespace blink { class DOMRectReadOnly; +class Landmark; class MODULES_EXPORT DetectedFace final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - static DetectedFace* Create(); - static DetectedFace* Create(DOMRectReadOnly*); - static DetectedFace* Create(DOMRectReadOnly*, - const HeapVector<Member<Landmark>>&); - - explicit DetectedFace(DOMRectReadOnly*); DetectedFace(DOMRectReadOnly*, const HeapVector<Member<Landmark>>&); - DOMRectReadOnly* boundingBox() const; - const HeapVector<Member<Landmark>>& landmarks() const; + DOMRectReadOnly* boundingBox() const { return bounding_box_; } + const HeapVector<Member<Landmark>>& landmarks() const { return landmarks_; } - ScriptValue toJSONForBinding(ScriptState*) const; void Trace(blink::Visitor*) override; private:
diff --git a/third_party/blink/renderer/modules/shapedetection/detected_face.idl b/third_party/blink/renderer/modules/shapedetection/detected_face.idl index c4b2559..ada91d8 100644 --- a/third_party/blink/renderer/modules/shapedetection/detected_face.idl +++ b/third_party/blink/renderer/modules/shapedetection/detected_face.idl
@@ -5,14 +5,12 @@ // https://wicg.github.io/shape-detection-api/#face-detection-api [ - Constructor, Serializable, + Exposed=(Window,Worker), + SecureContext, RuntimeEnabled=ShapeDetection ] interface DetectedFace { // TODO(xianglu): Implement any other fields. https://crbug.com/646083 [SameObject] readonly attribute DOMRectReadOnly boundingBox; [SameObject, SaveSameObject] readonly attribute FrozenArray<Landmark> landmarks; - - // TODO(peria): toJSON is not in spec. https://crbug.com/736332 - [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON(); };
diff --git a/third_party/blink/renderer/modules/shapedetection/detected_text.cc b/third_party/blink/renderer/modules/shapedetection/detected_text.cc index dfd3de3..ba1b3f7 100644 --- a/third_party/blink/renderer/modules/shapedetection/detected_text.cc +++ b/third_party/blink/renderer/modules/shapedetection/detected_text.cc
@@ -4,36 +4,11 @@ #include "third_party/blink/renderer/modules/shapedetection/detected_text.h" -#include "third_party/blink/renderer/bindings/core/v8/v8_object_builder.h" #include "third_party/blink/renderer/core/geometry/dom_rect.h" +#include "third_party/blink/renderer/modules/imagecapture/point_2d.h" namespace blink { -DetectedText* DetectedText::Create() { - HeapVector<Member<Point2D>> empty_list; - return MakeGarbageCollected<DetectedText>( - g_empty_string, DOMRectReadOnly::Create(0, 0, 0, 0), empty_list); -} - -DetectedText* DetectedText::Create(String raw_value, - DOMRectReadOnly* bounding_box, - HeapVector<Member<Point2D>> corner_points) { - return MakeGarbageCollected<DetectedText>(raw_value, bounding_box, - corner_points); -} - -const String& DetectedText::rawValue() const { - return raw_value_; -} - -DOMRectReadOnly* DetectedText::boundingBox() const { - return bounding_box_.Get(); -} - -const HeapVector<Member<Point2D>>& DetectedText::cornerPoints() const { - return corner_points_; -} - DetectedText::DetectedText(String raw_value, DOMRectReadOnly* bounding_box, HeapVector<Member<Point2D>> corner_points) @@ -41,21 +16,6 @@ bounding_box_(bounding_box), corner_points_(corner_points) {} -ScriptValue DetectedText::toJSONForBinding(ScriptState* script_state) const { - V8ObjectBuilder result(script_state); - result.AddString("rawValue", rawValue()); - result.Add("boundingBox", boundingBox()->toJSONForBinding(script_state)); - Vector<ScriptValue> corner_points; - for (const auto& corner_point : corner_points_) { - V8ObjectBuilder builder(script_state); - builder.AddNumber("x", corner_point->x()); - builder.AddNumber("y", corner_point->y()); - corner_points.push_back(builder.GetScriptValue()); - } - result.Add("cornerPoints", corner_points); - return result.GetScriptValue(); -} - void DetectedText::Trace(blink::Visitor* visitor) { visitor->Trace(bounding_box_); visitor->Trace(corner_points_);
diff --git a/third_party/blink/renderer/modules/shapedetection/detected_text.h b/third_party/blink/renderer/modules/shapedetection/detected_text.h index 8af515e..bddec683 100644 --- a/third_party/blink/renderer/modules/shapedetection/detected_text.h +++ b/third_party/blink/renderer/modules/shapedetection/detected_text.h
@@ -5,8 +5,6 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_TEXT_H_ #define THIRD_PARTY_BLINK_RENDERER_MODULES_SHAPEDETECTION_DETECTED_TEXT_H_ -#include "third_party/blink/renderer/bindings/core/v8/script_value.h" -#include "third_party/blink/renderer/modules/imagecapture/point_2d.h" #include "third_party/blink/renderer/modules/modules_export.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" @@ -14,23 +12,20 @@ namespace blink { class DOMRectReadOnly; +class Point2D; class MODULES_EXPORT DetectedText final : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - static DetectedText* Create(); - static DetectedText* Create(String, - DOMRectReadOnly*, - HeapVector<Member<Point2D>>); - DetectedText(String, DOMRectReadOnly*, HeapVector<Member<Point2D>>); - const String& rawValue() const; - DOMRectReadOnly* boundingBox() const; - const HeapVector<Member<Point2D>>& cornerPoints() const; + const String& rawValue() const { return raw_value_; } + DOMRectReadOnly* boundingBox() const { return bounding_box_; } + const HeapVector<Member<Point2D>>& cornerPoints() const { + return corner_points_; + } - ScriptValue toJSONForBinding(ScriptState*) const; void Trace(blink::Visitor*) override; private:
diff --git a/third_party/blink/renderer/modules/shapedetection/detected_text.idl b/third_party/blink/renderer/modules/shapedetection/detected_text.idl index dcbc270..aa8b1ecd 100644 --- a/third_party/blink/renderer/modules/shapedetection/detected_text.idl +++ b/third_party/blink/renderer/modules/shapedetection/detected_text.idl
@@ -5,8 +5,9 @@ // https://wicg.github.io/shape-detection-api/text.html#detectedtext-section [ - Constructor, Serializable, + Exposed=(Window,Worker), + SecureContext, RuntimeEnabled=ShapeDetection ] interface DetectedText { [SameObject] readonly attribute DOMString rawValue; @@ -14,7 +15,4 @@ // 4 corner points in clockwise direction starting with top-left. Due to // possible perspective distortions, this is not necessarily a rectangle. [SameObject] readonly attribute FrozenArray<Point2D> cornerPoints; - - // TODO(peria): toJSON is not in spec. https://crbug.com/736332 - [CallWith=ScriptState, ImplementedAs=toJSONForBinding] object toJSON(); };
diff --git a/third_party/blink/renderer/modules/shapedetection/face_detector.cc b/third_party/blink/renderer/modules/shapedetection/face_detector.cc index 008fda9..a0a130d 100644 --- a/third_party/blink/renderer/modules/shapedetection/face_detector.cc +++ b/third_party/blink/renderer/modules/shapedetection/face_detector.cc
@@ -93,7 +93,7 @@ landmarks.push_back(web_landmark); } - detected_faces.push_back(DetectedFace::Create( + detected_faces.push_back(MakeGarbageCollected<DetectedFace>( DOMRectReadOnly::Create(face->bounding_box.x, face->bounding_box.y, face->bounding_box.width, face->bounding_box.height),
diff --git a/third_party/blink/renderer/modules/shapedetection/face_detector.idl b/third_party/blink/renderer/modules/shapedetection/face_detector.idl index 7b943fdb4..574c1a51 100644 --- a/third_party/blink/renderer/modules/shapedetection/face_detector.idl +++ b/third_party/blink/renderer/modules/shapedetection/face_detector.idl
@@ -8,6 +8,7 @@ Constructor(optional FaceDetectorOptions faceDetectorOptions), ConstructorCallWith=ExecutionContext, Exposed=(Window,Worker), + SecureContext, MeasureAs=ShapeDetection_FaceDetectorConstructor, RuntimeEnabled=ShapeDetection ] interface FaceDetector {
diff --git a/third_party/blink/renderer/modules/shapedetection/text_detector.cc b/third_party/blink/renderer/modules/shapedetection/text_detector.cc index 46f08a2e..0db9dc3 100644 --- a/third_party/blink/renderer/modules/shapedetection/text_detector.cc +++ b/third_party/blink/renderer/modules/shapedetection/text_detector.cc
@@ -67,7 +67,7 @@ point->setY(corner_point.y); corner_points.push_back(point); } - detected_text.push_back(DetectedText::Create( + detected_text.push_back(MakeGarbageCollected<DetectedText>( text->raw_value, DOMRectReadOnly::Create(text->bounding_box.x, text->bounding_box.y, text->bounding_box.width,
diff --git a/third_party/blink/renderer/modules/shapedetection/text_detector.idl b/third_party/blink/renderer/modules/shapedetection/text_detector.idl index e24bf9ac..3fb9ff4a 100644 --- a/third_party/blink/renderer/modules/shapedetection/text_detector.idl +++ b/third_party/blink/renderer/modules/shapedetection/text_detector.idl
@@ -8,6 +8,7 @@ Constructor, ConstructorCallWith=ExecutionContext, Exposed=(Window,Worker), + SecureContext, MeasureAs=ShapeDetection_TextDetectorConstructor, RuntimeEnabled=ShapeDetection ] interface TextDetector {
diff --git a/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc b/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc index 4f2929d..e6385ef 100644 --- a/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc +++ b/third_party/blink/renderer/modules/webaudio/media_stream_audio_source_node.cc
@@ -142,8 +142,14 @@ return nullptr; } - // Use the first audio track in the media stream. + // Find the first track, which is the track whose id comes first given a + // lexicographic ordering of the code units of the track id. MediaStreamTrack* audio_track = audio_tracks[0]; + for (auto track : audio_tracks) { + if (CodeUnitCompareLessThan(track->id(), audio_track->id())) { + audio_track = track; + } + } std::unique_ptr<AudioSourceProvider> provider = audio_track->CreateWebAudioSource(context.sampleRate());
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 13b5eb4..282a1c62 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1609,7 +1609,7 @@ if (resource_provider->IsAccelerated()) { base::WeakPtr<WebGraphicsContext3DProviderWrapper> shared_context_wrapper = SharedGpuContext::ContextProviderWrapper(); - if (!shared_context_wrapper) + if (!shared_context_wrapper || !shared_context_wrapper->ContextProvider()) return false; gpu::gles2::GLES2Interface* gl = shared_context_wrapper->ContextProvider()->ContextGL();
diff --git a/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc b/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc index 5b757df..f9ff4995 100644 --- a/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc +++ b/third_party/blink/renderer/modules/xr/xr_rigid_transform.cc
@@ -24,22 +24,18 @@ // decompose matrix to position and orientation TransformationMatrix::DecomposedType decomposed; bool succeeded = matrix_->Decompose(decomposed); - if (succeeded) { - position_ = - DOMPointReadOnly::Create(decomposed.translate_x, decomposed.translate_y, - decomposed.translate_z, 1.0); + DCHECK(succeeded) << "Matrix decompose failed for " << matrix_->ToString(); - // TODO(https://crbug.com/929841): Minuses are needed as a workaround for - // bug in TransformationMatrix so that callers can still pass non-inverted - // quaternions. - orientation_ = makeNormalizedQuaternion( - -decomposed.quaternion_x, -decomposed.quaternion_y, - -decomposed.quaternion_z, decomposed.quaternion_w); - } else { - // TODO(crbug.com/969149): Is this the correct way to handle a failure here? - position_ = DOMPointReadOnly::Create(0.0, 0.0, 0.0, 1.0); - orientation_ = DOMPointReadOnly::Create(0.0, 0.0, 0.0, 1.0); - } + position_ = + DOMPointReadOnly::Create(decomposed.translate_x, decomposed.translate_y, + decomposed.translate_z, 1.0); + + // TODO(https://crbug.com/929841): Minuses are needed as a workaround for + // bug in TransformationMatrix so that callers can still pass non-inverted + // quaternions. + orientation_ = makeNormalizedQuaternion( + -decomposed.quaternion_x, -decomposed.quaternion_y, + -decomposed.quaternion_z, decomposed.quaternion_w); } XRRigidTransform::XRRigidTransform(DOMPointInit* position,
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc index ac884299..8b7232f 100644 --- a/third_party/blink/renderer/modules/xr/xr_session.cc +++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -879,12 +879,20 @@ if (display_info_->stage_parameters && display_info->stage_parameters && !display_info_->stage_parameters->Equals( - *(display_info->stage_parameters))) + *(display_info->stage_parameters))) { + // Stage parameters changed. stage_parameters_id_++; - } else { - if (display_info && display_info->stage_parameters) { + } else if (!!(display_info_->stage_parameters) != + !!(display_info->stage_parameters)) { + // Either stage parameters just became available (sometimes happens if + // detecting the bounds doesn't happen until a few seconds into the + // session for platforms such as WMR), or the stage parameters just went + // away (probably due to tracking loss). stage_parameters_id_++; } + } else if (display_info && display_info->stage_parameters) { + // Got stage parameters for the first time this session. + stage_parameters_id_++; } display_info_id_++;
diff --git a/third_party/blink/renderer/platform/blob/blob_data_test.cc b/third_party/blink/renderer/platform/blob/blob_data_test.cc index 6933be5a..4d8821425 100644 --- a/third_party/blink/renderer/platform/blob/blob_data_test.cc +++ b/third_party/blink/renderer/platform/blob/blob_data_test.cc
@@ -360,7 +360,7 @@ } TEST_F(BlobDataHandleTest, CreateFromFileAndFileSystemURL) { - double timestamp1 = CurrentTime(); + double timestamp1 = base::Time::Now().ToDoubleT(); double timestamp2 = timestamp1 + 1; KURL url(NullURL(), "http://example.com/"); auto data = std::make_unique<BlobData>(); @@ -386,7 +386,7 @@ } TEST_F(BlobDataHandleTest, CreateFromFilesystemFileWithUnknownSize) { - double timestamp = CurrentTime(); + double timestamp = base::Time::Now().ToDoubleT(); KURL url(NullURL(), "http://example.com/"); Vector<ExpectedElement> expected_elements; expected_elements.push_back(ExpectedElement::FileFilesystem(
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc index 76df417..3164c9b 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -778,14 +778,15 @@ // 1. It is not the root transform node. // 2. It is a 2d translation only. // 3. The transform is not used for scrolling - its ScrollNode() is nullptr. -// 4. It has no direct compositing reasons, other than k3DTransform. Note +// 4. The transform is not a StickyTranslation node. +// 5. It has no direct compositing reasons, other than k3DTransform. Note // that if it has a k3DTransform reason, check #2 above ensures that it // isn't really 3D. -// 5. It has FlattensInheritedTransform matching that of its direct parent. -// 6. It has backface visibility matching its direct parent. -// 7. No clips have local_transform_space referring to this transform node. -// 8. No effects have local_transform_space referring to this transform node. -// 9. All child transform nodes are also able to be de-composited. +// 6. It has FlattensInheritedTransform matching that of its direct parent. +// 7. It has backface visibility matching its direct parent. +// 8. No clips have local_transform_space referring to this transform node. +// 9. No effects have local_transform_space referring to this transform node. +// 10. All child transform nodes are also able to be de-composited. // This algorithm should be O(t+c+e) where t,c,e are the number of transform, // clip, and effect nodes in the full tree. void PaintArtifactCompositor::DecompositeTransforms( @@ -819,6 +820,7 @@ !node->IsRoot() && !can_be_decomposited.Contains(node); node = &node->Parent()->Unalias()) { if (!node->IsIdentityOr2DTranslation() || node->ScrollNode() || + node->GetStickyConstraint() || node->IsAffectedByOuterViewportBoundsDelta() || node->HasDirectCompositingReasonsOtherThan3dTransform() || !node->FlattensInheritedTransformSameAsParent() ||
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc index 2586ce96..e62bc0b 100644 --- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc +++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -333,14 +333,16 @@ root_layer_.SetScrollTreeIndex(scroll_node.id); } -static bool TransformsToAncestorHaveActiveAnimation( +static bool TransformsToAncestorHaveNonAxisAlignedActiveAnimation( const TransformPaintPropertyNode& descendant, const TransformPaintPropertyNode& ancestor) { if (&descendant == &ancestor) return false; for (const auto* n = &descendant; n != &ancestor; n = n->Parent()) { - if (n->HasActiveTransformAnimation()) + if (n->HasActiveTransformAnimation() && + !n->TransformAnimationIsAxisAligned()) { return true; + } } return false; } @@ -354,10 +356,9 @@ if (!translation_2d_or_matrix.IsIdentityOr2DTranslation() && !translation_2d_or_matrix.Matrix().Preserves2dAxisAlignment()) return true; - // Assume any animation can cause 2d axis misalignment. const auto& lca = LowestCommonAncestor(a, b); - if (TransformsToAncestorHaveActiveAnimation(a, lca) || - TransformsToAncestorHaveActiveAnimation(b, lca)) + if (TransformsToAncestorHaveNonAxisAlignedActiveAnimation(a, lca) || + TransformsToAncestorHaveNonAxisAlignedActiveAnimation(b, lca)) return true; return false; }
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 2b6a3dd3..ba34755 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
@@ -128,6 +128,7 @@ bool flattens_inherited_transform = false; bool affected_by_outer_viewport_bounds_delta = false; bool in_subtree_of_page_scale = true; + bool animation_is_axis_aligned = false; BackfaceVisibility backface_visibility = BackfaceVisibility::kInherited; unsigned rendering_context_id = 0; CompositingReasons direct_compositing_reasons = CompositingReason::kNone; @@ -141,6 +142,7 @@ affected_by_outer_viewport_bounds_delta != other.affected_by_outer_viewport_bounds_delta || in_subtree_of_page_scale != other.in_subtree_of_page_scale || + animation_is_axis_aligned != other.animation_is_axis_aligned || backface_visibility != other.backface_visibility || rendering_context_id != other.rendering_context_id || compositor_element_id != other.compositor_element_id || @@ -357,6 +359,9 @@ return state_.direct_compositing_reasons & CompositingReason::kActiveTransformAnimation; } + bool TransformAnimationIsAxisAligned() const { + return state_.animation_is_axis_aligned; + } bool RequiresCompositingForRootScroller() const { return state_.direct_compositing_reasons & CompositingReason::kRootScroller;
diff --git a/third_party/blink/renderer/platform/heap/heap.cc b/third_party/blink/renderer/platform/heap/heap.cc index 94c3050..32222661 100644 --- a/third_party/blink/renderer/platform/heap/heap.cc +++ b/third_party/blink/renderer/platform/heap/heap.cc
@@ -99,6 +99,7 @@ marking_worklist_(nullptr), not_fully_constructed_worklist_(nullptr), weak_callback_worklist_(nullptr), + movable_reference_worklist_(nullptr), vector_backing_arena_index_(BlinkGC::kVector1ArenaIndex), current_arena_ages_(0) { if (ThreadState::Current()->IsMainThread()) @@ -162,16 +163,17 @@ #endif // DCHECK_IS_ON() } -void ThreadHeap::CommitCallbackStacks() { +void ThreadHeap::SetupWorklists() { marking_worklist_.reset(new MarkingWorklist()); not_fully_constructed_worklist_.reset(new NotFullyConstructedWorklist()); previously_not_fully_constructed_worklist_.reset( new NotFullyConstructedWorklist()); weak_callback_worklist_.reset(new WeakCallbackWorklist()); + movable_reference_worklist_.reset(new MovableReferenceWorklist()); DCHECK(ephemeron_callbacks_.IsEmpty()); } -void ThreadHeap::DecommitCallbackStacks(BlinkGC::StackState stack_state) { +void ThreadHeap::DestroyMarkingWorklists(BlinkGC::StackState stack_state) { marking_worklist_.reset(nullptr); previously_not_fully_constructed_worklist_.reset(nullptr); weak_callback_worklist_.reset(nullptr); @@ -206,14 +208,18 @@ not_fully_constructed_worklist_.reset(nullptr); } +void ThreadHeap::DestroyCompactionWorklists() { + movable_reference_worklist_.reset(); +} + HeapCompact* ThreadHeap::Compaction() { if (!compaction_) compaction_ = std::make_unique<HeapCompact>(this); return compaction_.get(); } -void ThreadHeap::RegisterMovingObjectReference(MovableReference* slot) { - Compaction()->RegisterMovingObjectReference(slot); +bool ThreadHeap::ShouldRegisterMovingObjectReference(MovableReference* slot) { + return Compaction()->ShouldRegisterMovingObjectReference(slot); } void ThreadHeap::RegisterMovingObjectCallback(MovableReference* slot,
diff --git a/third_party/blink/renderer/platform/heap/heap.h b/third_party/blink/renderer/platform/heap/heap.h index 872efa0a..0957a12 100644 --- a/third_party/blink/renderer/platform/heap/heap.h +++ b/third_party/blink/renderer/platform/heap/heap.h
@@ -75,6 +75,10 @@ Worklist<NotFullyConstructedItem, 16 /* local entries */>; using WeakCallbackWorklist = Worklist<CustomCallbackItem, 256 /* local entries */>; +// Using large local segments here (sized 512 entries) to avoid throughput +// regressions. +using MovableReferenceWorklist = + Worklist<MovableReference*, 512 /* local entries */>; class PLATFORM_EXPORT HeapAllocHooks { STATIC_ONLY(HeapAllocHooks); @@ -213,17 +217,22 @@ return weak_callback_worklist_.get(); } + MovableReferenceWorklist* GetMovableReferenceWorklist() const { + return movable_reference_worklist_.get(); + } + // Register an ephemeron table for fixed-point iteration. void RegisterWeakTable(void* container_object, EphemeronCallback); // Heap compaction registration methods: - // Register |slot| as containing a reference to a movable heap object. + // Checks whether we need to register |slot| as containing a reference to + // a movable heap object. // // When compaction moves the object pointed to by |*slot| to |newAddress|, // |*slot| must be updated to hold |newAddress| instead. - void RegisterMovingObjectReference(MovableReference*); + bool ShouldRegisterMovingObjectReference(MovableReference*); // Register a callback to be invoked upon moving the object starting at // |reference|; see |MovingObjectCallback| documentation for details. @@ -394,8 +403,9 @@ private: static int ArenaIndexForObjectSize(size_t); - void CommitCallbackStacks(); - void DecommitCallbackStacks(BlinkGC::StackState); + void SetupWorklists(); + void DestroyMarkingWorklists(BlinkGC::StackState); + void DestroyCompactionWorklists(); void InvokeEphemeronCallbacks(Visitor*); @@ -428,6 +438,11 @@ // processed after finishing marking objects. std::unique_ptr<WeakCallbackWorklist> weak_callback_worklist_; + // The worklist is to remember slots that are traced during + // marking phases. The mapping between the slots and the backing stores are + // created at the atomic pause phase. + std::unique_ptr<MovableReferenceWorklist> movable_reference_worklist_; + // No duplicates allowed for ephemeron callbacks. Hence, we use a hashmap // with the key being the HashTable. WTF::HashMap<void*, EphemeronCallback> ephemeron_callbacks_;
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.cc b/third_party/blink/renderer/platform/heap/heap_compact.cc index a2112be..13d7259d 100644 --- a/third_party/blink/renderer/platform/heap/heap_compact.cc +++ b/third_party/blink/renderer/platform/heap/heap_compact.cc
@@ -384,13 +384,10 @@ force_for_next_gc_ = false; } -void HeapCompact::RegisterMovingObjectReference(MovableReference* slot) { +bool HeapCompact::ShouldRegisterMovingObjectReference(MovableReference* slot) { CHECK(heap_->LookupPageForAddress(reinterpret_cast<Address>(slot))); - if (!do_compact_) - return; - - traced_slots_.insert(slot); + return do_compact_; } void HeapCompact::RegisterMovingObjectCallback(MovableReference* slot, @@ -458,13 +455,15 @@ return; last_fixup_count_for_testing_ = 0; - for (auto** slot : traced_slots_) { + MovableReferenceWorklist::View traced_slots( + heap_->GetMovableReferenceWorklist(), WorklistTaskId::MainThread); + MovableReference* slot; + while (traced_slots.Pop(&slot)) { if (*slot) { Fixups().AddOrFilter(slot); last_fixup_count_for_testing_++; } } - traced_slots_.clear(); } void HeapCompact::Finish() { @@ -484,9 +483,9 @@ return; last_fixup_count_for_testing_ = 0; - traced_slots_.clear(); - fixups_.reset(); do_compact_ = false; + heap_->GetMovableReferenceWorklist()->Clear(); + fixups_.reset(); } void HeapCompact::AddCompactingPage(BasePage* page) {
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.h b/third_party/blink/renderer/platform/heap/heap_compact.h index e79e12d6..14f2f4f 100644 --- a/third_party/blink/renderer/platform/heap/heap_compact.h +++ b/third_party/blink/renderer/platform/heap/heap_compact.h
@@ -63,8 +63,8 @@ return do_compact_ && (compactable_arenas_ & (0x1u << arena_index)); } - // See |Heap::RegisterMovingObjectReference()| documentation. - void RegisterMovingObjectReference(MovableReference* slot); + // See |Heap::ShouldRegisterMovingObjectReference()| documentation. + bool ShouldRegisterMovingObjectReference(MovableReference* slot); // See |Heap::RegisterMovingObjectCallback()| documentation. void RegisterMovingObjectCallback(MovableReference*, @@ -134,11 +134,6 @@ ThreadHeap* const heap_; std::unique_ptr<MovableObjectFixups> fixups_; - // The set is to remember slots that traced during - // marking phases. The mapping between the slots and the backing stores are - // created at the atomic pause phase. - HashSet<MovableReference*> traced_slots_; - // Set to |true| when a compacting sweep will go ahead. bool do_compact_ = false; size_t gc_count_since_last_compaction_ = 0;
diff --git a/third_party/blink/renderer/platform/heap/heap_page.cc b/third_party/blink/renderer/platform/heap/heap_page.cc index 3a04dce..cfe3dee8 100644 --- a/third_party/blink/renderer/platform/heap/heap_page.cc +++ b/third_party/blink/renderer/platform/heap/heap_page.cc
@@ -1408,6 +1408,11 @@ unfinalized_freelist_.push_back(std::move(entry)); } else { cached_freelist_.Add(start, size); +#if !DCHECK_IS_ON() && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER) + if (Arena()->GetThreadState()->IsMemoryReducingGC()) { + DiscardPages(start + sizeof(FreeListEntry), start + size); + } +#endif } } @@ -1418,6 +1423,12 @@ for (const FutureFreelistEntry& entry : unfinalized_freelist_) { arena->AddToFreeList(entry.start, entry.size); +#if !DCHECK_IS_ON() && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER) + if (Arena()->GetThreadState()->IsMemoryReducingGC()) { + DiscardPages(entry.start + sizeof(FreeListEntry), + entry.start + entry.size); + } +#endif } unfinalized_freelist_.clear(); } @@ -1467,12 +1478,6 @@ AddToFreeList(start_of_gap, header_address - start_of_gap, finalize_type, found_finalizer); found_finalizer = false; -#if !DCHECK_IS_ON() && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER) - // Discarding pages increases page faults and may regress performance. - // So we enable this only on low-RAM devices. - if (MemoryPressureListenerRegistry::IsLowEndDevice()) - DiscardPages(start_of_gap + sizeof(FreeListEntry), header_address); -#endif } object_start_bit_map()->SetBit(header_address); header->Unmark<HeapObjectHeader::AccessMode::kAtomic>(); @@ -1485,10 +1490,6 @@ if (start_of_gap != Payload() && start_of_gap != PayloadEnd()) { AddToFreeList(start_of_gap, PayloadEnd() - start_of_gap, finalize_type, found_finalizer); -#if !DCHECK_IS_ON() && !defined(LEAK_SANITIZER) && !defined(ADDRESS_SANITIZER) - if (MemoryPressureListenerRegistry::IsLowEndDevice()) - DiscardPages(start_of_gap + sizeof(FreeListEntry), PayloadEnd()); -#endif } return start_of_gap == Payload(); }
diff --git a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc index f420ec3..7d1e01ec 100644 --- a/third_party/blink/renderer/platform/heap/incremental_marking_test.cc +++ b/third_party/blink/renderer/platform/heap/incremental_marking_test.cc
@@ -91,11 +91,12 @@ thread_state_->IsSweepingInProgress()) { TestSupportingGC::PreciselyCollectGarbage(); } - heap_.CommitCallbackStacks(); + heap_.SetupWorklists(); } ~IncrementalMarkingScopeBase() { - heap_.DecommitCallbackStacks(BlinkGC::StackState::kNoHeapPointersOnStack); + heap_.DestroyMarkingWorklists(BlinkGC::StackState::kNoHeapPointersOnStack); + heap_.DestroyCompactionWorklists(); } ThreadHeap& heap() const { return heap_; }
diff --git a/third_party/blink/renderer/platform/heap/marking_visitor.cc b/third_party/blink/renderer/platform/heap/marking_visitor.cc index 1c9bfab..2b1ebf65 100644 --- a/third_party/blink/renderer/platform/heap/marking_visitor.cc +++ b/third_party/blink/renderer/platform/heap/marking_visitor.cc
@@ -26,6 +26,8 @@ WorklistTaskId::MainThread), weak_callback_worklist_(Heap().GetWeakCallbackWorklist(), WorklistTaskId::MainThread), + movable_reference_worklist_(Heap().GetMovableReferenceWorklist(), + WorklistTaskId::MainThread), marking_mode_(marking_mode) { DCHECK(state->InAtomicMarkingPause()); #if DCHECK_IS_ON() @@ -33,6 +35,10 @@ #endif // DCHECK_IS_ON } +void MarkingVisitorBase::FlushCompactionWorklists() { + movable_reference_worklist_.FlushToGlobal(); +} + void MarkingVisitorBase::RegisterWeakCallback(void* object, WeakCallback callback) { // We don't want to run weak processings when taking a snapshot. @@ -44,10 +50,11 @@ void MarkingVisitorBase::RegisterBackingStoreReference(void** slot) { if (marking_mode_ != kGlobalMarkingWithCompaction) return; - // TODO(mlippautz): Do not call into heap directly but rather use a Worklist - // as temporary storage. - Heap().RegisterMovingObjectReference( - reinterpret_cast<MovableReference*>(slot)); + MovableReference* movable_reference = + reinterpret_cast<MovableReference*>(slot); + if (Heap().ShouldRegisterMovingObjectReference(movable_reference)) { + movable_reference_worklist_.Push(movable_reference); + } } void MarkingVisitorBase::RegisterBackingStoreCallback(
diff --git a/third_party/blink/renderer/platform/heap/marking_visitor.h b/third_party/blink/renderer/platform/heap/marking_visitor.h index 3c4a767..79cb1b8 100644 --- a/third_party/blink/renderer/platform/heap/marking_visitor.h +++ b/third_party/blink/renderer/platform/heap/marking_visitor.h
@@ -103,6 +103,9 @@ // Unused cross-component visit methods. void Visit(const TraceWrapperV8Reference<v8::Value>&) override {} + // Flush private segments remaining in visitor's worklists to global pools. + void FlushCompactionWorklists(); + size_t marked_bytes() const { return marked_bytes_; } protected: @@ -125,6 +128,7 @@ MarkingWorklist::View marking_worklist_; NotFullyConstructedWorklist::View not_fully_constructed_worklist_; WeakCallbackWorklist::View weak_callback_worklist_; + MovableReferenceWorklist::View movable_reference_worklist_; size_t marked_bytes_ = 0; const MarkingMode marking_mode_; };
diff --git a/third_party/blink/renderer/platform/heap/thread_state.cc b/third_party/blink/renderer/platform/heap/thread_state.cc index 75a2694..8669aa8 100644 --- a/third_party/blink/renderer/platform/heap/thread_state.cc +++ b/third_party/blink/renderer/platform/heap/thread_state.cc
@@ -1528,6 +1528,7 @@ SweepForbiddenScope scope(this); NoAllocationScope no_allocation_scope(this); Heap().Compact(); + Heap().DestroyCompactionWorklists(); } #if defined(ADDRESS_SANITIZER) @@ -1578,7 +1579,7 @@ BlinkGC::MarkingType marking_type, BlinkGC::GCReason reason) { SetGCPhase(GCPhase::kMarking); - Heap().CommitCallbackStacks(); + Heap().SetupWorklists(); const bool take_snapshot = marking_type == BlinkGC::kTakeSnapshot; @@ -1659,8 +1660,11 @@ VisitWeakPersistents(visitor); Heap().WeakProcessing(visitor); } - Heap().DecommitCallbackStacks(current_gc_data_.stack_state); + Heap().DestroyMarkingWorklists(current_gc_data_.stack_state); + // TODO(omerkatz): When migrating to concurrent marking, the following 3 + // lines will need to be wrapped with a loop iterating over all visitors. + current_gc_data_.visitor->FlushCompactionWorklists(); const size_t marked_bytes = current_gc_data_.visitor->marked_bytes(); current_gc_data_.visitor.reset();
diff --git a/third_party/blink/renderer/platform/heap/thread_state.h b/third_party/blink/renderer/platform/heap/thread_state.h index 5759471..28585e8d 100644 --- a/third_party/blink/renderer/platform/heap/thread_state.h +++ b/third_party/blink/renderer/platform/heap/thread_state.h
@@ -432,6 +432,12 @@ bool VerifyMarkingEnabled() const; + // Returns true if the current GC is a memory reducing GC. + bool IsMemoryReducingGC() { + return current_gc_data_.reason == + BlinkGC::GCReason::kUnifiedHeapForMemoryReductionGC; + } + private: // Stores whether some ThreadState is currently in incremental marking. static AtomicEntryFlag incremental_marking_flag_; @@ -531,10 +537,6 @@ // (aka being under "memory pressure".) bool ShouldForceMemoryPressureGC(); - // Returns true if shouldForceMemoryPressureGC() held and a - // conservative GC was performed to handle the emergency. - bool ForceMemoryPressureGCIfNeeded(); - size_t EstimatedLiveSize(size_t current_size, size_t size_at_last_gc); size_t TotalMemorySize(); double HeapGrowingRate();
diff --git a/third_party/blink/renderer/platform/heap/worklist.h b/third_party/blink/renderer/platform/heap/worklist.h index 5dc2bcf..724b91f 100644 --- a/third_party/blink/renderer/platform/heap/worklist.h +++ b/third_party/blink/renderer/platform/heap/worklist.h
@@ -60,6 +60,8 @@ bool IsGlobalPoolEmpty() { return worklist_->IsGlobalPoolEmpty(); } + void FlushToGlobal() { worklist_->FlushToGlobal(task_id_); } + size_t LocalPushSegmentSize() const { return worklist_->LocalPushSegmentSize(task_id_); }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource.cc b/third_party/blink/renderer/platform/loader/fetch/resource.cc index 6c98c72..c0be93eb 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource.cc
@@ -75,6 +75,20 @@ : blink::mojom::CodeCacheType::kJavascript; } +void GetSharedBufferMemoryDump(SharedBuffer* buffer, + const String& dump_prefix, + WebProcessMemoryDump* memory_dump) { + size_t dump_size; + String dump_name; + buffer->GetMemoryDumpNameAndSize(dump_name, dump_size); + + WebMemoryAllocatorDump* dump = + memory_dump->CreateMemoryAllocatorDump(dump_prefix + dump_name); + dump->AddScalar("size", "bytes", dump_size); + memory_dump->AddSuballocation( + dump->Guid(), String(WTF::Partitions::kAllocatedObjectPoolName)); +} + } // namespace // These response headers are not copied from a revalidated response to the @@ -885,7 +899,7 @@ dump->AddScalar("dead_size", "bytes", encoded_size_memory_usage_); if (data_) - data_->OnMemoryDump(dump_name, memory_dump); + GetSharedBufferMemoryDump(Data(), dump_name, memory_dump); if (level_of_detail == WebMemoryDumpLevelOfDetail::kDetailed) { String url_to_report = Url().GetString();
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 6e086fa..d62a5fac 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -546,6 +546,12 @@ name: "ExpensiveBackgroundTimerThrottling", status: "stable", }, + // Experimental feature to try dynamic delegation of autoplay capability + // through postMessages. + { + name: "ExperimentalAutoplayDynamicDelegation", + origin_trial_feature_name: "ExperimentalAutoplayDynamicDelegation", + }, { name: "ExperimentalContentSecurityPolicyFeatures", status: "experimental", @@ -797,14 +803,14 @@ }, { name: "LargestContentfulPaint", - status: "experimental", + status: "stable", }, { // Exposes layout shift scores to Javascript. See explainer: // http://bit.ly/lsm-explainer. name: "LayoutInstabilityAPI", origin_trial_feature_name: "LayoutJankAPI", - status: "experimental", + status: "stable", }, { name: "LayoutNG",
diff --git a/third_party/blink/renderer/platform/scheduler/common/thread.cc b/third_party/blink/renderer/platform/scheduler/common/thread.cc index 27fb9276..b657a3c8 100644 --- a/third_party/blink/renderer/platform/scheduler/common/thread.cc +++ b/third_party/blink/renderer/platform/scheduler/common/thread.cc
@@ -29,16 +29,6 @@ namespace { -// Controls whether we use ThreadPriority::DISPLAY for compositor thread. -const base::Feature kBlinkCompositorUseDisplayThreadPriority { - "BlinkCompositorUseDisplayThreadPriority", -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) - base::FEATURE_ENABLED_BY_DEFAULT -#else - base::FEATURE_DISABLED_BY_DEFAULT -#endif -}; - // Thread-local storage for "blink::Thread"s. Thread*& ThreadTLSSlot() { DEFINE_THREAD_SAFE_STATIC_LOCAL(WTF::ThreadSpecific<Thread*>, thread_tls_slot, @@ -112,7 +102,8 @@ DCHECK(!GetCompositorThread()); ThreadCreationParams params(WebThreadType::kCompositorThread); - if (base::FeatureList::IsEnabled(kBlinkCompositorUseDisplayThreadPriority)) + if (base::FeatureList::IsEnabled( + features::kBlinkCompositorUseDisplayThreadPriority)) params.thread_priority = base::ThreadPriority::DISPLAY; auto compositor_thread = @@ -120,7 +111,8 @@ compositor_thread->Init(); GetCompositorThread() = std::move(compositor_thread); - if (base::FeatureList::IsEnabled(kBlinkCompositorUseDisplayThreadPriority)) { + if (base::FeatureList::IsEnabled( + features::kBlinkCompositorUseDisplayThreadPriority)) { // Chrome OS moves tasks between control groups on thread priority changes. // This is not possible inside the sandbox, so ask the browser to do it. // TODO(spang): Check if we can remove this on non-Chrome OS builds.
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.h index d16357c..4739e0e 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.h
@@ -16,7 +16,6 @@ kMainFrame = 0, kSameOriginFrame = 1, kCrossOriginFrame = 2, - kCount = 3 };
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc index 25e86aa..321fb83c 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -1094,7 +1094,8 @@ .SetCanBeThrottled(true) .SetCanBeFrozen(true) .SetCanBeDeferred(true) - .SetCanBePaused(true); + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true); } // static @@ -1104,15 +1105,18 @@ .SetCanBeDeferred(true) .SetCanBeFrozen(base::FeatureList::IsEnabled( blink::features::kStopNonTimersInBackground)) - .SetCanBePaused(true); + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true); } // static -MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::PausableTaskQueueTraits() { +MainThreadTaskQueue::QueueTraits +FrameSchedulerImpl::PausableTaskQueueTraits() { return QueueTraits() .SetCanBeFrozen(base::FeatureList::IsEnabled( blink::features::kStopNonTimersInBackground)) - .SetCanBePaused(true); + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true); } // static @@ -1120,23 +1124,25 @@ FrameSchedulerImpl::FreezableTaskQueueTraits() { // Should not use VirtualTime because using VirtualTime would make the task // execution non-deterministic and produce timeouts failures. - return QueueTraits().SetCanBeFrozen(true).SetShouldUseVirtualTime(false); + return QueueTraits().SetCanBeFrozen(true); } // static MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::UnpausableTaskQueueTraits() { - return QueueTraits(); + return QueueTraits().SetShouldUseVirtualTime(true); } MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::ForegroundOnlyTaskQueueTraits() { - return ThrottleableTaskQueueTraits().SetCanRunInBackground(false); + return ThrottleableTaskQueueTraits() + .SetCanRunInBackground(false) + .SetShouldUseVirtualTime(true); } MainThreadTaskQueue::QueueTraits FrameSchedulerImpl::DoesNotUseVirtualTimeTaskQueueTraits() { - return UnpausableTaskQueueTraits().SetShouldUseVirtualTime(false); + return QueueTraits().SetShouldUseVirtualTime(false); } } // namespace scheduler
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc index 403c405..43303c8 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -1775,36 +1775,41 @@ EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() .SetCanBeThrottled(true) .SetCanBeFrozen(true) - .SetCanBePaused(true)); + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); task_queue = GetTaskQueue(TaskType::kMediaElementEvent); - EXPECT_EQ( - task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBeFrozen(true).SetCanBePaused( - true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBeFrozen(true) + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); task_queue = GetTaskQueue(TaskType::kDatabaseAccess); - EXPECT_EQ(task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBePaused(true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); task_queue = GetTaskQueue(TaskType::kDOMManipulation); EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() .SetCanBeFrozen(true) .SetCanBeDeferred(true) - .SetCanBePaused(true)); + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); // Test some task types that were not configured through field trial // parameters. task_queue = GetTaskQueue(TaskType::kInternalIPC); - EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits()); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetShouldUseVirtualTime(true)); task_queue = GetTaskQueue(TaskType::kMiscPlatformAPI); - EXPECT_EQ( - task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBeDeferred(true).SetCanBePaused( - true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBeDeferred(true) + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); } + class FreezableOnlyTaskTypesTest : public ThrottleAndFreezeTaskTypesExperimentTest { public: @@ -1826,20 +1831,18 @@ // Check that the overrides work. auto task_queue = GetTaskQueue(TaskType::kPostedMessage); - EXPECT_EQ( - task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBeFrozen(true).SetCanBePaused( - true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBeFrozen(true) + .SetCanBePaused(true)); task_queue = GetTaskQueue(TaskType::kMediaElementEvent); - EXPECT_EQ( - task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBeFrozen(true).SetCanBePaused( - true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBeFrozen(true) + .SetCanBePaused(true)); task_queue = GetTaskQueue(TaskType::kDatabaseAccess); - EXPECT_EQ(task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBePaused(true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBePaused(true)); task_queue = GetTaskQueue(TaskType::kDOMManipulation); EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() @@ -1853,10 +1856,9 @@ EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits()); task_queue = GetTaskQueue(TaskType::kMiscPlatformAPI); - EXPECT_EQ( - task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBeDeferred(true).SetCanBePaused( - true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBeDeferred(true) + .SetCanBePaused(true)); } class ThrottleableOnlyTaskTypesTest @@ -1879,35 +1881,38 @@ // Check that the overrides work. auto task_queue = GetTaskQueue(TaskType::kPostedMessage); - EXPECT_EQ( - task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBeThrottled(true).SetCanBePaused( - true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBeThrottled(true) + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); task_queue = GetTaskQueue(TaskType::kMediaElementEvent); - EXPECT_EQ(task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBePaused(true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); task_queue = GetTaskQueue(TaskType::kDatabaseAccess); - EXPECT_EQ(task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBePaused(true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); task_queue = GetTaskQueue(TaskType::kDOMManipulation); - EXPECT_EQ( - task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBeDeferred(true).SetCanBePaused( - true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBeDeferred(true) + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); // Test some task types that were not configured through field trial // parameters. task_queue = GetTaskQueue(TaskType::kInternalIPC); - EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits()); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetShouldUseVirtualTime(true)); task_queue = GetTaskQueue(TaskType::kMiscPlatformAPI); - EXPECT_EQ( - task_queue->GetQueueTraits(), - MainThreadTaskQueue::QueueTraits().SetCanBeDeferred(true).SetCanBePaused( - true)); + EXPECT_EQ(task_queue->GetQueueTraits(), MainThreadTaskQueue::QueueTraits() + .SetCanBeDeferred(true) + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); } class FrameSchedulerImplDatabaseAccessWithoutHighPriority
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc index d2ea65b..e7273ae 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc
@@ -123,23 +123,29 @@ .SetCanBeThrottled(true) .SetCanBeDeferred(true) .SetCanBeFrozen(true) - .SetCanBePaused(true)); + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); EXPECT_FALSE(all_task_queues.Contains(task_queue)); all_task_queues.insert(task_queue.get(), QueueCheckResult::kDidNotSeeQueue); EXPECT_EQ(all_task_queues.size(), task_queue_created_count()); - task_queue = NonLoadingTaskQueue( - QueueTraits().SetCanBeDeferred(true).SetCanBePaused(true)); + task_queue = NonLoadingTaskQueue(QueueTraits() + .SetCanBeDeferred(true) + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); EXPECT_FALSE(all_task_queues.Contains(task_queue)); all_task_queues.insert(task_queue.get(), QueueCheckResult::kDidNotSeeQueue); EXPECT_EQ(all_task_queues.size(), task_queue_created_count()); - task_queue = NonLoadingTaskQueue(QueueTraits().SetCanBePaused(true)); + task_queue = NonLoadingTaskQueue(QueueTraits() + .SetCanBePaused(true) + .SetShouldUseVirtualTime(true)); EXPECT_FALSE(all_task_queues.Contains(task_queue)); all_task_queues.insert(task_queue.get(), QueueCheckResult::kDidNotSeeQueue); EXPECT_EQ(all_task_queues.size(), task_queue_created_count()); - task_queue = NonLoadingTaskQueue(QueueTraits()); + task_queue = NonLoadingTaskQueue(QueueTraits() + .SetShouldUseVirtualTime(true)); EXPECT_FALSE(all_task_queues.Contains(task_queue)); all_task_queues.insert(task_queue.get(), QueueCheckResult::kDidNotSeeQueue); EXPECT_EQ(all_task_queues.size(), task_queue_created_count());
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc index 44106d40..2fca44c 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -730,8 +730,7 @@ // If this is a timer queue, and virtual time is enabled and paused, it should // be suspended by adding a fence to prevent immediate tasks from running when // they're not supposed to. - if (queue_class == MainThreadTaskQueue::QueueClass::kTimer && - main_thread_only().virtual_time_stopped && + if (main_thread_only().virtual_time_stopped && main_thread_only().use_virtual_time && task_queue->ShouldUseVirtualTime()) { task_queue->InsertFence(TaskQueue::InsertFencePosition::kNow); @@ -762,7 +761,8 @@ .SetCanBeFrozen(true) .SetCanBeDeferred(true) .SetCanBeThrottled(true) - .SetFrameScheduler(frame_scheduler)); + .SetFrameScheduler(frame_scheduler) + .SetShouldUseVirtualTime(true)); } std::unique_ptr<WebRenderWidgetSchedulingState> @@ -1810,10 +1810,8 @@ for (const auto& pair : task_runners_) { if (!pair.first->ShouldUseVirtualTime()) continue; - if (pair.first->queue_class() == MainThreadTaskQueue::QueueClass::kTimer) { - DCHECK(!task_queue_throttler_->IsThrottled(pair.first.get())); - pair.first->InsertFence(TaskQueue::InsertFencePosition::kNow); - } + DCHECK(!task_queue_throttler_->IsThrottled(pair.first.get())); + pair.first->InsertFence(TaskQueue::InsertFencePosition::kNow); } } @@ -1821,11 +1819,9 @@ for (const auto& pair : task_runners_) { if (!pair.first->ShouldUseVirtualTime()) continue; - if (pair.first->queue_class() == MainThreadTaskQueue::QueueClass::kTimer) { - DCHECK(!task_queue_throttler_->IsThrottled(pair.first.get())); - DCHECK(pair.first->HasActiveFence()); - pair.first->RemoveFence(); - } + DCHECK(!task_queue_throttler_->IsThrottled(pair.first.get())); + DCHECK(pair.first->HasActiveFence()); + pair.first->RemoveFence(); } } @@ -2046,7 +2042,7 @@ MainThreadSchedulerImpl::TimeDomainType MainThreadSchedulerImpl::TaskQueuePolicy::GetTimeDomainType( MainThreadTaskQueue* task_queue) const { - if (use_virtual_time && task_queue->ShouldUseVirtualTime()) + if (use_virtual_time) return TimeDomainType::kVirtual; return TimeDomainType::kReal; }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h index 2b577d4..23a4a06 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -104,7 +104,7 @@ can_be_paused(false), can_be_frozen(false), can_run_in_background(true), - should_use_virtual_time(true), + should_use_virtual_time(false), is_high_priority(false) {} QueueTraits(const QueueTraits&) = default;
diff --git a/third_party/blink/renderer/platform/shared_buffer.cc b/third_party/blink/renderer/platform/shared_buffer.cc index 6b9e68f..9c1c77e 100644 --- a/third_party/blink/renderer/platform/shared_buffer.cc +++ b/third_party/blink/renderer/platform/shared_buffer.cc
@@ -234,23 +234,11 @@ return data; } -void SharedBuffer::OnMemoryDump(const String& dump_prefix, - WebProcessMemoryDump* memory_dump) const { - if (buffer_.size()) { - WebMemoryAllocatorDump* dump = - memory_dump->CreateMemoryAllocatorDump(dump_prefix + "/shared_buffer"); - dump->AddScalar("size", "bytes", buffer_.size()); - memory_dump->AddSuballocation( - dump->Guid(), String(WTF::Partitions::kAllocatedObjectPoolName)); - } else { - // If there is data in the segments, then it should have been allocated - // using fastMalloc. - const String data_dump_name = dump_prefix + "/segments"; - auto* dump = memory_dump->CreateMemoryAllocatorDump(data_dump_name); - dump->AddScalar("size", "bytes", size_); - memory_dump->AddSuballocation( - dump->Guid(), String(WTF::Partitions::kAllocatedObjectPoolName)); - } +void SharedBuffer::GetMemoryDumpNameAndSize(String& dump_name, + size_t& dump_size) const { + size_t buffer_size = buffer_.size(); + dump_name = buffer_size ? "/shared_buffer" : "/segments"; + dump_size = buffer_size ? buffer_size : size_; } SharedBuffer::DeprecatedFlatData::DeprecatedFlatData(
diff --git a/third_party/blink/renderer/platform/shared_buffer.h b/third_party/blink/renderer/platform/shared_buffer.h index d5310b2e..71cdd0c 100644 --- a/third_party/blink/renderer/platform/shared_buffer.h +++ b/third_party/blink/renderer/platform/shared_buffer.h
@@ -45,8 +45,6 @@ namespace blink { -class WebProcessMemoryDump; - class PLATFORM_EXPORT SharedBuffer : public RefCounted<SharedBuffer> { public: // Iterator for ShreadBuffer contents. An Iterator will get invalid once the @@ -182,7 +180,7 @@ // SkData without merging segmented buffers into a flat buffer. sk_sp<SkData> GetAsSkData() const; - void OnMemoryDump(const String& dump_prefix, WebProcessMemoryDump*) const; + void GetMemoryDumpNameAndSize(String& dump_name, size_t& dump_size) const; // Helper for providing a contiguous view of the data. If the SharedBuffer is // segmented, this will copy/merge all segments into a temporary buffer.
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc index 768c64b2..598aa03 100644 --- a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc +++ b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.cc
@@ -316,6 +316,8 @@ return webrtc::RTCErrorType::NONE; } +void MockWebRTCPeerConnectionHandler::RestartIce() {} + void MockWebRTCPeerConnectionHandler::GetStats(const WebRTCStatsRequest&) {} void MockWebRTCPeerConnectionHandler::GetStats(
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h index 058efc0..39d569dc 100644 --- a/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h +++ b/third_party/blink/renderer/platform/testing/testing_platform_support_with_web_rtc.h
@@ -51,6 +51,7 @@ const override; webrtc::RTCErrorType SetConfiguration( const webrtc::PeerConnectionInterface::RTCConfiguration&) override; + void RestartIce() override; void GetStats(const WebRTCStatsRequest&) override; void GetStats(WebRTCStatsReportCallback, const WebVector<webrtc::NonStandardGroupId>&) override;
diff --git a/third_party/blink/renderer/platform/transforms/identity_transform_operation.h b/third_party/blink/renderer/platform/transforms/identity_transform_operation.h index c28d2be..b3d2cab 100644 --- a/third_party/blink/renderer/platform/transforms/identity_transform_operation.h +++ b/third_party/blink/renderer/platform/transforms/identity_transform_operation.h
@@ -58,6 +58,8 @@ scoped_refptr<TransformOperation> Zoom(double factor) final { return this; } + bool PreservesAxisAlignment() const final { return true; } + IdentityTransformOperation() = default; };
diff --git a/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h b/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h index 9a2875e7..5b82a7d3 100644 --- a/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h +++ b/third_party/blink/renderer/platform/transforms/interpolated_transform_operation.h
@@ -69,6 +69,10 @@ progress_); } + bool PreservesAxisAlignment() const final { + return from_.PreservesAxisAlignment() && to_.PreservesAxisAlignment(); + } + bool DependsOnBoxSize() const override { return from_.DependsOnBoxSize() || to_.DependsOnBoxSize(); }
diff --git a/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h b/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h index 304425e..c5fd803 100644 --- a/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h +++ b/third_party/blink/renderer/platform/transforms/matrix_3d_transform_operation.h
@@ -69,6 +69,10 @@ bool blend_to_identity = false) override; scoped_refptr<TransformOperation> Zoom(double factor) final; + bool PreservesAxisAlignment() const final { + return matrix_.Preserves2dAxisAlignment(); + } + Matrix3DTransformOperation(const TransformationMatrix& mat) { matrix_ = mat; } TransformationMatrix matrix_;
diff --git a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h index 409dd21..2c3c43a3 100644 --- a/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h +++ b/third_party/blink/renderer/platform/transforms/matrix_transform_operation.h
@@ -83,6 +83,10 @@ bool blend_to_identity = false) override; scoped_refptr<TransformOperation> Zoom(double factor) final; + bool PreservesAxisAlignment() const final { + return Matrix().Preserves2dAxisAlignment(); + } + MatrixTransformOperation(double a, double b, double c,
diff --git a/third_party/blink/renderer/platform/transforms/scale_transform_operation.h b/third_party/blink/renderer/platform/transforms/scale_transform_operation.h index d21dd97..9ad90334 100644 --- a/third_party/blink/renderer/platform/transforms/scale_transform_operation.h +++ b/third_party/blink/renderer/platform/transforms/scale_transform_operation.h
@@ -84,6 +84,8 @@ scoped_refptr<TransformOperation> Zoom(double factor) final { return this; } + bool PreservesAxisAlignment() const final { return true; } + ScaleTransformOperation(double sx, double sy, double sz, OperationType type) : x_(sx), y_(sy), z_(sz), type_(type) { DCHECK(IsMatchingOperationType(type));
diff --git a/third_party/blink/renderer/platform/transforms/transform_operation.h b/third_party/blink/renderer/platform/transforms/transform_operation.h index acafaeb..ad257d3 100644 --- a/third_party/blink/renderer/platform/transforms/transform_operation.h +++ b/third_party/blink/renderer/platform/transforms/transform_operation.h
@@ -90,6 +90,8 @@ } virtual bool CanBlendWith(const TransformOperation& other) const = 0; + virtual bool PreservesAxisAlignment() const { return false; } + bool Is3DOperation() const { OperationType op_type = GetType(); return op_type == kScaleZ || op_type == kScale3D ||
diff --git a/third_party/blink/renderer/platform/transforms/transform_operations.h b/third_party/blink/renderer/platform/transforms/transform_operations.h index 65e646b6..c7ef91f 100644 --- a/third_party/blink/renderer/platform/transforms/transform_operations.h +++ b/third_party/blink/renderer/platform/transforms/transform_operations.h
@@ -72,6 +72,14 @@ return false; } + bool PreservesAxisAlignment() const { + for (auto& operation : operations_) { + if (!operation->PreservesAxisAlignment()) + return false; + } + return true; + } + // Returns true if any operation has a non-trivial component in the Z // axis. bool HasNonTrivial3DComponent() const {
diff --git a/third_party/blink/renderer/platform/transforms/translate_transform_operation.h b/third_party/blink/renderer/platform/transforms/translate_transform_operation.h index ebb90a23..6ead517a 100644 --- a/third_party/blink/renderer/platform/transforms/translate_transform_operation.h +++ b/third_party/blink/renderer/platform/transforms/translate_transform_operation.h
@@ -99,6 +99,8 @@ return ZoomTranslate(factor); } + bool PreservesAxisAlignment() const final { return true; } + TranslateTransformOperation(const Length& tx, const Length& ty, double tz,
diff --git a/third_party/blink/renderer/platform/wtf/hash_traits.h b/third_party/blink/renderer/platform/wtf/hash_traits.h index 0c75e386..ab32232 100644 --- a/third_party/blink/renderer/platform/wtf/hash_traits.h +++ b/third_party/blink/renderer/platform/wtf/hash_traits.h
@@ -57,7 +57,10 @@ // The starting table size. Can be overridden when we know beforehand that a // hash table will have at least N entries. -#if defined(MEMORY_SANITIZER_INITIAL_SIZE) +#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) + // The allocation pool for nodes is one big chunk that ASAN has no insight + // into, so it can cloak errors. Make it as small as possible to force nodes + // to be allocated individually where ASAN can see them. static const unsigned kMinimumTableSize = 1; #else static const unsigned kMinimumTableSize = 8;
diff --git a/third_party/blink/renderer/platform/wtf/list_hash_set.h b/third_party/blink/renderer/platform/wtf/list_hash_set.h index 4c93a04..046d8390 100644 --- a/third_party/blink/renderer/platform/wtf/list_hash_set.h +++ b/third_party/blink/renderer/platform/wtf/list_hash_set.h
@@ -386,7 +386,7 @@ Node* free_list_; bool is_done_with_initial_free_list_; -#if defined(MEMORY_SANITIZER_INITIAL_SIZE) +#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) // The allocation pool for nodes is one big chunk that ASAN has no insight // into, so it can cloak errors. Make it as small as possible to force nodes // to be allocated individually where ASAN can see them.
diff --git a/third_party/blink/renderer/platform/wtf/time.cc b/third_party/blink/renderer/platform/wtf/time.cc index 7ae6220..21b2e194 100644 --- a/third_party/blink/renderer/platform/wtf/time.cc +++ b/third_party/blink/renderer/platform/wtf/time.cc
@@ -27,15 +27,3 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -#include "third_party/blink/renderer/platform/wtf/time.h" - -#include "base/time/time.h" - -namespace WTF { - -double CurrentTime() { - return base::Time::Now().ToDoubleT(); -} - -} // namespace WTF
diff --git a/third_party/blink/renderer/platform/wtf/time.h b/third_party/blink/renderer/platform/wtf/time.h index 9c03b6c..a5075b7 100644 --- a/third_party/blink/renderer/platform/wtf/time.h +++ b/third_party/blink/renderer/platform/wtf/time.h
@@ -5,24 +5,4 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TIME_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TIME_H_ -#include "base/time/time.h" -#include "third_party/blink/renderer/platform/wtf/wtf_export.h" - -namespace WTF { - -// Returns the current UTC time in seconds, counted from January 1, 1970. -// Precision varies depending on platform but is usually as good or better -// than a millisecond. -WTF_EXPORT double CurrentTime(); - -// Same thing, in milliseconds. -inline double CurrentTimeMS() { - return CurrentTime() * 1000.0; -} - -} // namespace WTF - -using WTF::CurrentTime; -using WTF::CurrentTimeMS; - #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TIME_H_
diff --git a/third_party/blink/renderer/platform/wtf/vector.h b/third_party/blink/renderer/platform/wtf/vector.h index fbe2e3d7..dde7d59 100644 --- a/third_party/blink/renderer/platform/wtf/vector.h +++ b/third_party/blink/renderer/platform/wtf/vector.h
@@ -49,13 +49,13 @@ namespace WTF { -#if defined(MEMORY_SANITIZER_INITIAL_SIZE) +#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) +// The allocation pool for nodes is one big chunk that ASAN has no insight +// into, so it can cloak errors. Make it as small as possible to force nodes +// to be allocated individually where ASAN can see them. static const wtf_size_t kInitialVectorSize = 1; #else -#ifndef WTF_VECTOR_INITIAL_SIZE -#define WTF_VECTOR_INITIAL_SIZE 4 -#endif -static const wtf_size_t kInitialVectorSize = WTF_VECTOR_INITIAL_SIZE; +static const wtf_size_t kInitialVectorSize = 4; #endif template <typename T, wtf_size_t inlineBuffer, typename Allocator>
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py index 692f1bf..37b3463 100755 --- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py +++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -82,6 +82,7 @@ 'base::size', 'base::span', 'logging::GetVlogLevel', + 'util::PassKey', # //base/observer_list.h. 'base::ObserverList',
diff --git a/third_party/blink/web_tests/FlagExpectations/disable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/disable-blink-features=LayoutNG index 00215128..617d074 100644 --- a/third_party/blink/web_tests/FlagExpectations/disable-blink-features=LayoutNG +++ b/third_party/blink/web_tests/FlagExpectations/disable-blink-features=LayoutNG
@@ -297,3 +297,7 @@ crbug.com/591099 virtual/gpu/fast/canvas/image-object-in-canvas.html [ Failure ] crbug.com/591099 virtual/prefer_compositing_to_lcd_text/compositing/overflow/scrollbar-layer-placement-negative-z-index-child.html [ Failure ] +# Just because these need a re-baseline from "LayoutNGBlockFlow" to "LayoutBlockFlow" +crbug.com/591099 paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html [ Failure ] +crbug.com/591099 virtual/compositor_threaded_scrollbar_scrolling/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html [ Failure ] +crbug.com/591099 virtual/disable-blink-gen-property-trees/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html [ Failure ]
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint index 5cda685..66c80dc 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint +++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=CompositeAfterPaint
@@ -350,6 +350,8 @@ crbug.com/931486 paint/invalidation/scroll/scrollbar-damage-and-full-viewport-repaint.html [ Failure ] crbug.com/931486 paint/invalidation/text-match-document-change.html [ Failure ] crbug.com/931486 paint/invalidation/invalidation-on-foreground-graphics-layer.html [ Failure ] +crbug.com/931486 paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html [ Failure ] +crbug.com/931486 virtual/compositor_threaded_scrollbar_scrolling/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html [ Failure ] # See comment regarding this test in NeverFixTests. It also fails for other # reasons, in particular that the composited layerization algorithm provides
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests index ac7879a..4e5380f 100644 --- a/third_party/blink/web_tests/NeverFixTests +++ b/third_party/blink/web_tests/NeverFixTests
@@ -2145,6 +2145,9 @@ virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ WontFix ] virtual/not-omt-sw-fetch/external/wpt/xhr/send-authentication-existing-session-manual.htm [ WontFix ] virtual/not-omt-sw-fetch/external/wpt/xhr/send-authentication-prompt-2-manual.htm [ WontFix ] +virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ WontFix ] +virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ WontFix ] +virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ WontFix ] virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ WontFix ] virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ WontFix ] virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-event-is-reload-navigation-manual.https.html [ WontFix ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index c36fa39..d0d13c9 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -142,6 +142,7 @@ # Subpixel differences crbug.com/771643 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-color-5.html [ Failure ] crbug.com/771643 external/wpt/css/css-backgrounds/background-attachment-local/attachment-local-clipping-image-5.html [ Failure ] +crbug.com/986110 external/wpt/css/css-transforms/perspective-transforms-equivalence.html [ Failure ] crbug.com/807395 fast/multicol/mixed-opacity-test.html [ Failure ] @@ -2219,7 +2220,6 @@ ### sheriff 2019-07-16 crbug.com/983799 [ Win ] http/tests/navigation/redirect-on-back-updates-history-item.html [ Timeout Pass ] crbug.com/983799 [ Win ] virtual/blink-cors/http/tests/navigation/redirect-on-back-updates-history-item.html [ Timeout Pass ] -crbug.com/983790 external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html [ Pass Failure Timeout ] crbug.com/983789 [ Win7 ] http/tests/cookies/js-set-null.html [ Pass Failure ] crbug.com/983788 http/tests/cookies/http-get-cookie-set-in-js.html [ Pass Failure ] crbug.com/983788 http/tests/cookies/same-site/popup-cross-site.html [ Pass Timeout ] @@ -3123,6 +3123,7 @@ crbug.com/832071 virtual/blink-cors/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] crbug.com/832071 virtual/navigation-mojo-response/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] crbug.com/832071 virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] +crbug.com/832071 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] crbug.com/832071 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Failure ] # failures in external/wpt/css/css-animations/ and web-animations/ from Mozilla tests @@ -3541,6 +3542,7 @@ crbug.com/626703 virtual/blink-cors/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ] crbug.com/626703 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ] crbug.com/626703 virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ] +crbug.com/626703 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ] crbug.com/626703 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/ready.https.html [ Timeout ] crbug.com/626703 [ Linux ] external/wpt/css/css-fonts/math-script-level-and-math-style/math-script-level-auto-and-math-style-002.tentative.html [ Failure ] crbug.com/626703 [ Mac ] external/wpt/css/css-fonts/math-script-level-and-math-style/math-script-level-auto-and-math-style-002.tentative.html [ Failure ] @@ -4372,6 +4374,7 @@ crbug.com/648295 virtual/blink-cors/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ] crbug.com/648295 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ] crbug.com/648295 virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ] +crbug.com/648295 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ] crbug.com/648295 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ] crbug.com/626703 external/wpt/svg/linking/reftests/href-filter-element.html [ Failure ] crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_completely_move_up.html [ Failure ] @@ -4713,10 +4716,6 @@ # Needs investigation. These are timing out. crbug.com/835717 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/sandboxed-iframe-fetch-event.https.html [ Skip ] crbug.com/835717 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html [ Skip ] -# These are timing out because filesystem: URL is not supported yet with -# PlzDedicatedWorker. -crbug.com/980451 virtual/omt-worker-fetch/external/wpt/content-security-policy/inside-worker/dedicated-script.html [ Skip ] -crbug.com/980451 virtual/omt-worker-fetch/external/wpt/content-security-policy/inside-worker/dedicated-inheritance.html [ Skip ] # This fails because AllowedByNoSniff::MimeTypeAsScript() blocks the nested worker's # worker script, because the script url has a .html file extension. @@ -4780,6 +4779,7 @@ crbug.com/691944 virtual/blink-cors/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ] crbug.com/691944 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ] crbug.com/691944 virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ] +crbug.com/691944 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ] crbug.com/691944 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ] # These tests (erroneously) see a platform-specific User-Agent header @@ -4787,6 +4787,7 @@ crbug.com/595993 virtual/blink-cors/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] crbug.com/595993 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] crbug.com/595993 virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] +crbug.com/595993 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] crbug.com/595993 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ] crbug.com/619427 [ Mac ] fast/overflow/overflow-height-float-not-removed-crash3.html [ Pass Failure ] @@ -5039,6 +5040,7 @@ # Service worker updates need to handle redirect appropriately. crbug.com/889798 external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] crbug.com/889798 virtual/blink-cors/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] +crbug.com/889798 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] crbug.com/889798 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] crbug.com/889798 virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] crbug.com/889798 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/import-scripts-redirect.https.html [ Skip ] @@ -5594,6 +5596,8 @@ crbug.com/873873 external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ] crbug.com/873873 virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video.https.html [ Timeout Pass ] crbug.com/873873 virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ] +crbug.com/873873 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video.https.html [ Timeout Pass ] +crbug.com/873873 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ] crbug.com/873873 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video.https.html [ Timeout Pass ] crbug.com/873873 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/fetch-canvas-tainting-video-cache.https.html [ Timeout Pass ] @@ -5943,6 +5947,7 @@ crbug.com/933880 virtual/blink-cors/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ] crbug.com/933880 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ] crbug.com/933880 virtual/not-omt-sw-fetch/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ] +crbug.com/933880 virtual/cache-storage-parallel/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ] crbug.com/933880 virtual/cache-storage-sequence/external/wpt/service-workers/service-worker/request-end-to-end.https.html [ Failure ] crbug.com/933880 http/tests/inspector-protocol/network/interception-take-stream.js [ Failure ] crbug.com/933880 http/tests/inspector-protocol/network/xhr-interception-auth-fail.js [ Failure ] @@ -6320,6 +6325,9 @@ crbug.com/982149 [ Win7 ] virtual/not-omt-sw-fetch/external/wpt/referrer-policy/unsafe-url/http-rp/cross-origin/http-http/img-tag/no-redirect/generic.http.html [ Pass Timeout ] crbug.com/982149 [ Win7 ] virtual/omt-worker-fetch/external/wpt/referrer-policy/unsafe-url/http-rp/cross-origin/http-http/img-tag/no-redirect/generic.http.html [ Pass Timeout ] +# WebRTC "onnegotiationneeded" firing too early causing us to miss the event. +crbug.com/985797 external/wpt/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html [ Timeout ] + # Sheriff 2019-07-18 crbug.com/985232 [ Win7 ] external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html [ Pass Failure ] crbug.com/985232 [ Win7 ] virtual/streaming-preload/external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/dynamic-imports-credentials.sub.html [ Pass Failure ] @@ -6334,7 +6342,6 @@ crbug.com/986018 fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html [ Pass Failure ] # ecosystem-infra sheriff 2019-07-22 -crbug.com/986457 [ Linux ] http/tests/misc/object-image-error-with-onload.html [ Pass Failure ] crbug.com/986477 [ Win ] external/wpt/cookies/path/match.html [ Pass Timeout ] crbug.com/986477 [ Win ] virtual/samesite-by-default-cookies/external/wpt/cookies/path/match.html [ Pass Timeout ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index dd618504..45b1de5e 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -526,6 +526,12 @@ "--disable-smooth-scrolling"] }, { + "prefix": "compositor_threaded_scrollbar_scrolling", + "base": "paint/invalidation/scroll/sticky", + "args": ["--enable-threaded-compositing", + "--enable-prefer-compositing-to-lcd-text"] + }, + { "prefix": "main_thread_scrollbar_gestures", "base": "fast/scrolling/scrollbars", "args": ["--enable-features=ScrollbarInjectScrollGestures"] @@ -1188,6 +1194,13 @@ "args": ["--enable-blink-features=CSSVariables2AtProperty"] }, { + "prefix": "cache-storage-parallel", + "base": "external/wpt/service-workers", + "args": ["--enable-features=CacheStorageParallelOps<CSPO", + "--force-fieldtrials=CSPO/G1", + "--force-fieldtrial-params=CSPO.G1:max_shared_ops/64"] + }, + { "prefix": "cache-storage-sequence", "base": "external/wpt/service-workers", "args": ["--enable-features=CacheStorageSequence"]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json index a7196641..c43973d 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -31801,6 +31801,18 @@ {} ] ], + "css/css-backgrounds/background-color-body-propagation-007.html": [ + [ + "css/css-backgrounds/background-color-body-propagation-007.html", + [ + [ + "/css/reference/blank.html", + "==" + ] + ], + {} + ] + ], "css/css-backgrounds/background-color-clip.html": [ [ "css/css-backgrounds/background-color-clip.html", @@ -53075,6 +53087,18 @@ {} ] ], + "css/css-lists/li-insert-child.html": [ + [ + "css/css-lists/li-insert-child.html", + [ + [ + "/css/css-lists/li-insert-child-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-lists/li-list-item-counter.html": [ [ "css/css-lists/li-list-item-counter.html", @@ -58067,6 +58091,54 @@ {} ] ], + "css/css-overflow/overflow-body-propagation-001.tentative.html": [ + [ + "css/css-overflow/overflow-body-propagation-001.tentative.html", + [ + [ + "/css/css-overflow/reference/overflow-body-propagation-ref.html", + "==" + ] + ], + {} + ] + ], + "css/css-overflow/overflow-body-propagation-002.tentative.html": [ + [ + "css/css-overflow/overflow-body-propagation-002.tentative.html", + [ + [ + "/css/reference/blank.html", + "==" + ] + ], + {} + ] + ], + "css/css-overflow/overflow-body-propagation-003.tentative.html": [ + [ + "css/css-overflow/overflow-body-propagation-003.tentative.html", + [ + [ + "/css/reference/blank.html", + "==" + ] + ], + {} + ] + ], + "css/css-overflow/overflow-body-propagation-004.tentative.html": [ + [ + "css/css-overflow/overflow-body-propagation-004.tentative.html", + [ + [ + "/css/css-overflow/reference/overflow-body-no-propagation-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-overflow/webkit-line-clamp-001.html": [ [ "css/css-overflow/webkit-line-clamp-001.html", @@ -138492,6 +138564,9 @@ "css/css-lists/counter-set-002-ref.html": [ [] ], + "css/css-lists/li-insert-child-ref.html": [ + [] + ], "css/css-lists/li-list-item-counter-ref.html": [ [] ], @@ -139461,6 +139536,12 @@ "css/css-overflow/reference/input-scrollable-region-001-ref.html": [ [] ], + "css/css-overflow/reference/overflow-body-no-propagation-ref.html": [ + [] + ], + "css/css-overflow/reference/overflow-body-propagation-ref.html": [ + [] + ], "css/css-overflow/reference/webkit-line-clamp-001-ref.html": [ [] ], @@ -140112,6 +140193,12 @@ "css/css-shapes/OWNERS": [ [] ], + "css/css-shapes/parsing/shape-image-threshold-computed-expected.txt": [ + [] + ], + "css/css-shapes/parsing/shape-image-threshold-valid-expected.txt": [ + [] + ], "css/css-shapes/parsing/shape-outside-computed-expected.txt": [ [] ], @@ -150729,6 +150816,9 @@ "element-timing/META.yml": [ [] ], + "element-timing/idlharness.window-expected.txt": [ + [] + ], "element-timing/resources/TAOImage.py": [ [] ], @@ -150738,6 +150828,9 @@ "element-timing/resources/element-timing-helpers.js": [ [] ], + "element-timing/resources/iframe-stores-entry.html": [ + [] + ], "element-timing/resources/iframe-with-square-sends-entry.html": [ [] ], @@ -160980,6 +161073,9 @@ "interfaces/dom.idl": [ [] ], + "interfaces/element-timing.idl": [ + [] + ], "interfaces/encoding.idl": [ [] ], @@ -161049,6 +161145,9 @@ "interfaces/keyboard-map.idl": [ [] ], + "interfaces/largest-contentful-paint.idl": [ + [] + ], "interfaces/longtasks.idl": [ [] ], @@ -161358,6 +161457,9 @@ "kv-storage/secure-context/side-effects-expected.txt": [ [] ], + "largest-contentful-paint/resources/iframe-stores-entry.html": [ + [] + ], "layout-instability/resources/slow-image.py": [ [] ], @@ -161676,6 +161778,9 @@ "mathml/relations/text-and-math/use-typo-metrics-1-ref.html": [ [] ], + "mathml/support/feature-detection.js": [ + [] + ], "mathml/tools/axisheight.py": [ [] ], @@ -173517,12 +173622,6 @@ "web-nfc/OWNERS": [ [] ], - "web-nfc/idlharness.https.window-expected.txt": [ - [] - ], - "web-nfc/nfc_hw_disabled-manual.https-expected.txt": [ - [] - ], "web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt": [ [] ], @@ -185091,6 +185190,48 @@ {} ] ], + "IndexedDB/structured-clone.any.js": [ + [ + "IndexedDB/structured-clone.any.html", + { + "script_metadata": [ + [ + "script", + "support-promises.js" + ], + [ + "title", + "Indexed DB and Structured Serializing/Deserializing" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ], + [ + "IndexedDB/structured-clone.any.worker.html", + { + "script_metadata": [ + [ + "script", + "support-promises.js" + ], + [ + "title", + "Indexed DB and Structured Serializing/Deserializing" + ], + [ + "timeout", + "long" + ] + ], + "timeout": "long" + } + ] + ], "IndexedDB/transaction-abort-generator-revert.html": [ [ "IndexedDB/transaction-abort-generator-revert.html", @@ -199463,9 +199604,9 @@ {} ] ], - "css/css-backgrounds/parsing/border-image-source-computed.html": [ + "css/css-backgrounds/parsing/border-image-source-computed.sub.html": [ [ - "css/css-backgrounds/parsing/border-image-source-computed.html", + "css/css-backgrounds/parsing/border-image-source-computed.sub.html", {} ] ], @@ -203633,9 +203774,9 @@ {} ] ], - "css/css-lists/parsing/list-style-computed.html": [ + "css/css-lists/parsing/list-style-computed.sub.html": [ [ - "css/css-lists/parsing/list-style-computed.html", + "css/css-lists/parsing/list-style-computed.sub.html", {} ] ], @@ -219142,6 +219283,29 @@ {} ] ], + "element-timing/element-only-when-fully-active.html": [ + [ + "element-timing/element-only-when-fully-active.html", + {} + ] + ], + "element-timing/idlharness.window.js": [ + [ + "element-timing/idlharness.window.html", + { + "script_metadata": [ + [ + "script", + "/resources/WebIDLParser.js" + ], + [ + "script", + "/resources/idlharness.js" + ] + ] + } + ] + ], "element-timing/image-TAO.sub.html": [ [ "element-timing/image-TAO.sub.html", @@ -248570,6 +248734,12 @@ {} ] ], + "intersection-observer/rtl-clipped-root.html": [ + [ + "intersection-observer/rtl-clipped-root.html", + {} + ] + ], "intersection-observer/same-document-no-root.html": [ [ "intersection-observer/same-document-no-root.html", @@ -248938,12 +249108,24 @@ {} ] ], + "largest-contentful-paint/element-only-when-fully-active.html": [ + [ + "largest-contentful-paint/element-only-when-fully-active.html", + {} + ] + ], "largest-contentful-paint/expanded-image.html": [ [ "largest-contentful-paint/expanded-image.html", {} ] ], + "largest-contentful-paint/idlharness.html": [ + [ + "largest-contentful-paint/idlharness.html", + {} + ] + ], "largest-contentful-paint/image-src-change.html": [ [ "largest-contentful-paint/image-src-change.html", @@ -248956,6 +249138,12 @@ {} ] ], + "largest-contentful-paint/observe-after-untrusted-scroll.html": [ + [ + "largest-contentful-paint/observe-after-untrusted-scroll.html", + {} + ] + ], "largest-contentful-paint/observe-image.html": [ [ "largest-contentful-paint/observe-image.html", @@ -249306,6 +249494,18 @@ {} ] ], + "mathml/presentation-markup/operators/embellished-operator-001.html": [ + [ + "mathml/presentation-markup/operators/embellished-operator-001.html", + {} + ] + ], + "mathml/presentation-markup/operators/embellished-operator-002.html": [ + [ + "mathml/presentation-markup/operators/embellished-operator-002.html", + {} + ] + ], "mathml/presentation-markup/operators/mo-axis-height-1.html": [ [ "mathml/presentation-markup/operators/mo-axis-height-1.html", @@ -253372,19 +253572,6 @@ } ] ], - "native-file-system/NativeFileSystemWritableFileStream.tentative.https.window.js": [ - [ - "native-file-system/NativeFileSystemWritableFileStream.tentative.https.window.html", - { - "script_metadata": [ - [ - "script", - "resources/test-helpers.js" - ] - ] - } - ] - ], "navigation-timing/buffered-flag.window.js": [ [ "navigation-timing/buffered-flag.window.html", @@ -294297,6 +294484,12 @@ {} ] ], + "webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html": [ + [ + "webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html", + {} + ] + ], "webrtc/RTCPeerConnection-restartIce.https.html": [ [ "webrtc/RTCPeerConnection-restartIce.https.html", @@ -299276,6 +299469,12 @@ {} ] ], + "webxr/exclusive_requestFrame_nolayer.https.html": [ + [ + "webxr/exclusive_requestFrame_nolayer.https.html", + {} + ] + ], "webxr/getInputPose_handedness.https.html": [ [ "webxr/getInputPose_handedness.https.html", @@ -299305,6 +299504,18 @@ } ] ], + "webxr/render_state_vertical_fov_immersive.https.html": [ + [ + "webxr/render_state_vertical_fov_immersive.https.html", + {} + ] + ], + "webxr/render_state_vertical_fov_inline.https.html": [ + [ + "webxr/render_state_vertical_fov_inline.https.html", + {} + ] + ], "webxr/webGLCanvasContext_create_xrcompatible.https.html": [ [ "webxr/webGLCanvasContext_create_xrcompatible.https.html", @@ -299521,6 +299732,12 @@ {} ] ], + "webxr/xrSession_requestAnimationFrame_timestamp.https.html": [ + [ + "webxr/xrSession_requestAnimationFrame_timestamp.https.html", + {} + ] + ], "webxr/xrSession_requestReferenceSpace.https.html": [ [ "webxr/xrSession_requestReferenceSpace.https.html", @@ -299551,12 +299768,54 @@ {} ] ], + "webxr/xrView_match.https.html": [ + [ + "webxr/xrView_match.https.html", + {} + ] + ], + "webxr/xrView_oneframeupdate.https.html": [ + [ + "webxr/xrView_oneframeupdate.https.html", + {} + ] + ], + "webxr/xrViewport_valid.https.html": [ + [ + "webxr/xrViewport_valid.https.html", + {} + ] + ], + "webxr/xrWebGLLayer_constructor.https.html": [ + [ + "webxr/xrWebGLLayer_constructor.https.html", + {} + ] + ], "webxr/xrWebGLLayer_framebuffer.https.html": [ [ "webxr/xrWebGLLayer_framebuffer.https.html", {} ] ], + "webxr/xrWebGLLayer_framebuffer_draw.https.html": [ + [ + "webxr/xrWebGLLayer_framebuffer_draw.https.html", + {} + ] + ], + "webxr/xrWebGLLayer_framebuffer_scale.https.html": [ + [ + "webxr/xrWebGLLayer_framebuffer_scale.https.html", + {} + ] + ], + "webxr/xrWebGLLayer_opaque_framebuffer.https.html": [ + [ + "webxr/xrWebGLLayer_opaque_framebuffer.https.html", + {} + ] + ], "webxr/xrWebGLLayer_viewports.https.html": [ [ "webxr/xrWebGLLayer_viewports.https.html", @@ -317848,6 +318107,10 @@ "cc905e56ecf83ea4cd4f1fe2ccfac425cdc5f9d0", "testharness" ], + "IndexedDB/structured-clone.any.js": [ + "8078aaf796b843aaf9f23be5889febbe4c8fb960", + "testharness" + ], "IndexedDB/support-promises.js": [ "8195be341e18860865c072bc78a1efa1f25f2d56", "support" @@ -320809,7 +321072,7 @@ "support" ], "common/security-features/tools/generate.py": [ - "50c3a2c250c9d992377809cb731441fd6588263d", + "50f08a75ca220917cdf484906f43cc139e10e09f", "support" ], "common/security-features/tools/template/disclaimer.template": [ @@ -320829,7 +321092,7 @@ "support" ], "common/security-features/tools/util.py": [ - "77b89769ca27f606ae6adb080fbdc5ee9df8966d", + "1f6c86e6efcc3bb5dbde41ba484a026d55a5961e", "support" ], "common/sleep.py": [ @@ -342309,15 +342572,19 @@ "reftest" ], "css/css-backgrounds/background-color-body-propagation-004.html": [ - "c4b21959626ad4ddfe8edb5065c57369920ea772", + "ede419096ff1faedd91b4f712e238a76101ca081", "reftest" ], "css/css-backgrounds/background-color-body-propagation-005.html": [ - "702b2b29ae3cb20358b3c125f5b0cd69a1477d0b", + "05c5421977e74259189bab32b85e35c94daadddb", "reftest" ], "css/css-backgrounds/background-color-body-propagation-006.html": [ - "b575891382c8b9f21998996a48fc7581a0f9e115", + "4c58cb9dc212f9b02a94b5bc7121cb50bd70cb61", + "reftest" + ], + "css/css-backgrounds/background-color-body-propagation-007.html": [ + "6deda8dcdb581e6f064ed522c036e5f1d72ea474", "reftest" ], "css/css-backgrounds/background-color-body-propagation-ref.html": [ @@ -344956,8 +345223,8 @@ "671120b41b7e55bddd2c286dc7ce4807ce9c3665", "testharness" ], - "css/css-backgrounds/parsing/border-image-source-computed.html": [ - "96e6bdf2f09ee50e8649e7a918debeaf06902e32", + "css/css-backgrounds/parsing/border-image-source-computed.sub.html": [ + "20343882096f2ce3fe1f0dbfb6d2164279e8aade", "testharness" ], "css/css-backgrounds/parsing/border-image-source-invalid.html": [ @@ -364332,6 +364599,14 @@ "0fae6e3f6036c46b8f658304787da5879913296f", "testharness" ], + "css/css-lists/li-insert-child-ref.html": [ + "bbf2e66a0dfddd3f399eea4889fd867444b7eca4", + "support" + ], + "css/css-lists/li-insert-child.html": [ + "d82bf1374aebc47740285a54a7532b6b7242377f", + "reftest" + ], "css/css-lists/li-list-item-counter-ref.html": [ "96ca6c1122188015d6e40e01102bdb4fecfb0567", "support" @@ -364456,8 +364731,8 @@ "9627ce936ae570325b430a1ac673cd66ae7d4252", "reftest" ], - "css/css-lists/parsing/list-style-computed.html": [ - "67bdc46f8c11ae085d5ee8449ee97ddba319a8b4", + "css/css-lists/parsing/list-style-computed.sub.html": [ + "611fae5bf93636cd4d3402e91b1cd47148303617", "testharness" ], "css/css-lists/parsing/list-style-image-computed.sub-expected.txt": [ @@ -367872,6 +368147,22 @@ "df1128316f6010f010e6d27c395d7751fa05d7b1", "testharness" ], + "css/css-overflow/overflow-body-propagation-001.tentative.html": [ + "0998fe68e007d5a46ff11d5ff87fdbad12d1dfe2", + "reftest" + ], + "css/css-overflow/overflow-body-propagation-002.tentative.html": [ + "5991dd52e8b6aec74f55780587f15c2b9399c968", + "reftest" + ], + "css/css-overflow/overflow-body-propagation-003.tentative.html": [ + "a329a8dfe3e44c92368bf0496897f74ccec5a63a", + "reftest" + ], + "css/css-overflow/overflow-body-propagation-004.tentative.html": [ + "2ed8d2687a33608e0e70884ad2ea59330d2b09e3", + "reftest" + ], "css/css-overflow/overflow-inline-transform-relative.html": [ "4df7b6389432cc6c65bae3fe3b5b9c2f00ba7bde", "testharness" @@ -367980,6 +368271,14 @@ "d7125ee2ef3285d461b2172208e23d8d4cc27a64", "support" ], + "css/css-overflow/reference/overflow-body-no-propagation-ref.html": [ + "9795d1f5861f0affaeb3a36b3644d17fd60e1f4d", + "support" + ], + "css/css-overflow/reference/overflow-body-propagation-ref.html": [ + "340bda9de92352fe1ef6633610da31e867013299", + "support" + ], "css/css-overflow/reference/webkit-line-clamp-001-ref.html": [ "ef28e01dac0223c9a2768d3fd1415fb9ef2f1c6b", "support" @@ -369661,7 +369960,7 @@ "support" ], "css/css-properties-values-api/typedom.html": [ - "2fc6447f22b0078d57e6e54eed751323c322a090", + "b8e6f4aaf840c017ff7e49c14333c635c8483c50", "testharness" ], "css/css-properties-values-api/unit-cycles.html": [ @@ -371020,16 +371319,24 @@ "490775dd8ce24721046f89234237d8f7c200623c", "testharness" ], + "css/css-shapes/parsing/shape-image-threshold-computed-expected.txt": [ + "8a246fca5bbb8077ddf3a9a0cb9c989b9540eb59", + "support" + ], "css/css-shapes/parsing/shape-image-threshold-computed.html": [ - "a90d23a6044af840cc8b4251e8825097f6a43646", + "81bc0ccb8453109ca99fed496ef607ee99e95035", "testharness" ], "css/css-shapes/parsing/shape-image-threshold-invalid.html": [ - "6299e2ecaad8247affa1e54ace4aea276322c114", + "c0cac033fb6d10a00275fcce6bb5e27ed4514984", "testharness" ], + "css/css-shapes/parsing/shape-image-threshold-valid-expected.txt": [ + "b6e14a08a5931acc9a4c701ec12c845edde1ba2a", + "support" + ], "css/css-shapes/parsing/shape-image-threshold-valid.html": [ - "914abd02210d4db881017c9453d3bcb68fd8e9f2", + "4ed1fb9fbaf1bd4aed1cdb89753d4f15c6a72fd9", "testharness" ], "css/css-shapes/parsing/shape-margin-computed.html": [ @@ -412992,6 +413299,18 @@ "82e7461b0417fb6f667ad266c08789b58f06c457", "testharness" ], + "element-timing/element-only-when-fully-active.html": [ + "5608685a34219d831dd6c57743e829967d3ed247", + "testharness" + ], + "element-timing/idlharness.window-expected.txt": [ + "97021720108cbc18cb4adea42959525e34f002c6", + "support" + ], + "element-timing/idlharness.window.js": [ + "f0e5d06658e773fd5f9ebf85511636e74c92dc80", + "testharness" + ], "element-timing/image-TAO.sub.html": [ "032ae6b12198b76107ab3dfcc2ab3b7f92b13c00", "testharness" @@ -413100,6 +413419,10 @@ "8933732616c116f1617c64f07182c9cbeb9f59fe", "support" ], + "element-timing/resources/iframe-stores-entry.html": [ + "2fa24769729f705547aa526cf4eca16c483cad78", + "support" + ], "element-timing/resources/iframe-with-square-sends-entry.html": [ "b8af505d32bc68d7f98b79bf2d2575778a49b26e", "support" @@ -427537,7 +427860,7 @@ "support" ], "html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html": [ - "d42599661bf595d27de82db892b17a5ec400062d", + "e3e0778c97a2a04ded5a151d31b1dc4f82334187", "testharness" ], "html/infrastructure/common-dom-interfaces/collections/htmlformcontrolscollection.html": [ @@ -440716,6 +441039,10 @@ "1788faae5207bb7a21b23771bf2b0e978ea49a69", "support" ], + "interfaces/element-timing.idl": [ + "dc3b886cfe5b6da608cc71fbc13c97e3d7695b76", + "support" + ], "interfaces/encoding.idl": [ "b3086b8588cdfec129a4c038c074021cacff83c5", "support" @@ -440808,6 +441135,10 @@ "70aaaffd3cfb5781b77f92eedf57bd4205e308bc", "support" ], + "interfaces/largest-contentful-paint.idl": [ + "f16a7ff812c96ab28f7d3b8d0f1b92d141e552a0", + "support" + ], "interfaces/longtasks.idl": [ "333b842f86e5d41f6f1aab8827cf086356c5a782", "support" @@ -440889,7 +441220,7 @@ "support" ], "interfaces/performance-timeline.idl": [ - "8ded59d8a269f83037a8845417c1275dd91ec538", + "d9362ea27516ac4e40caa7632d9aa1e2ed9edb11", "support" ], "interfaces/permissions.idl": [ @@ -441005,7 +441336,7 @@ "support" ], "interfaces/user-timing.idl": [ - "4130803ff9c45c15ef670813127657a98bd5631a", + "8b0f813ba8e6efc34b979ac7323afcbcac41e72b", "support" ], "interfaces/vibration.idl": [ @@ -441041,7 +441372,7 @@ "support" ], "interfaces/web-share.idl": [ - "e275aac96fe9b0daad6a35b21db15c725698d6d7", + "ae1f3f8580c0ff038ebe798bd66437ca3eb3fefc", "support" ], "interfaces/webaudio.idl": [ @@ -441252,6 +441583,10 @@ "898454c4f385794d78ef4635612b6754cdd060af", "testharness" ], + "intersection-observer/rtl-clipped-root.html": [ + "a30c6e38c5a02df96215cfea2e40be78a871cb20", + "testharness" + ], "intersection-observer/same-document-no-root.html": [ "63e9f86d9c60533a2b4b193cf4e2860ef712ee4f", "testharness" @@ -441540,10 +441875,18 @@ "88775b861a6b98b1af0fb5163222a1025a6df02e", "testharness" ], + "largest-contentful-paint/element-only-when-fully-active.html": [ + "41bdc8f8b984e61ab62f39734a1e19342697ef4e", + "testharness" + ], "largest-contentful-paint/expanded-image.html": [ "766b61d013da2cefddb9e35398648d4fa2a2bded", "testharness" ], + "largest-contentful-paint/idlharness.html": [ + "273fef80ce2d855075781512a9a8ab0a736af420", + "testharness" + ], "largest-contentful-paint/image-src-change.html": [ "3e083625bdc1812a2c344b8eefaaa10d3b31e623", "testharness" @@ -441552,6 +441895,10 @@ "fb0eddb220ec660d529a43b112c576bf146a87e8", "testharness" ], + "largest-contentful-paint/observe-after-untrusted-scroll.html": [ + "abe753fc14a33f88a398900632146ae3b8e8ee13", + "testharness" + ], "largest-contentful-paint/observe-image.html": [ "16b3502eb340cbce179bf440c245cafafe4beea4", "testharness" @@ -441564,6 +441911,10 @@ "94406b20d62b417a690ce6a96d909bb29c791081", "testharness" ], + "largest-contentful-paint/resources/iframe-stores-entry.html": [ + "cd600254805570deab8447ea843657d7f268b7c5", + "support" + ], "largest-contentful-paint/supported-lcp-type.html": [ "25d4eaa0367f45440d286c6c1c14de4458465d7b", "testharness" @@ -441917,7 +442268,7 @@ "testharness" ], "mathml/presentation-markup/fractions/frac-1.html": [ - "6be38d5439da9181ee53464abcf22863a9d176ce", + "5ecb66ecf6aabec264d8452a1277eb7769dde3fd", "testharness" ], "mathml/presentation-markup/fractions/frac-bar-001-ref.html": [ @@ -442013,11 +442364,11 @@ "reftest" ], "mathml/presentation-markup/fractions/frac-parameters-1.html": [ - "55404fa562c4dd304eb84702bee4578d02ae7925", + "b8bc405107bd643519fef9e0fb0dba1ba0a66762", "testharness" ], "mathml/presentation-markup/fractions/frac-parameters-2.html": [ - "63ab97760fc03161b9b3c63d09819463131864ad", + "ce2d299f281b639c1e4026caa9354a8bc8c5298d", "testharness" ], "mathml/presentation-markup/fractions/frac-parameters-gap-001-ref.html": [ @@ -442077,11 +442428,19 @@ "reftest" ], "mathml/presentation-markup/mrow/inferred-mrow-baseline.html": [ - "672d90de93363331a418f33ecac8f2380bd5fb5f", + "1541b2d6ce17c90a52c15f3ce5461a5c7d42920f", "testharness" ], "mathml/presentation-markup/mrow/inferred-mrow-stretchy.html": [ - "75587d076c2790608133b7a81558a42dc2581cff", + "ee40561a634c00eb9e29dd66d4a28f579a78af59", + "testharness" + ], + "mathml/presentation-markup/operators/embellished-operator-001.html": [ + "78c5069b90cab40ec2703c6c01c5d8643b5f836d", + "testharness" + ], + "mathml/presentation-markup/operators/embellished-operator-002.html": [ + "da343dd0bc35a79e0f309c38bbff34a69aa7df34", "testharness" ], "mathml/presentation-markup/operators/mo-axis-height-1.html": [ @@ -442153,55 +442512,55 @@ "reftest" ], "mathml/presentation-markup/radicals/root-parameters-1.html": [ - "5ad0b7315e02b9d893937a376b0545ff7bb0eada", + "d09d117b8ad5b52ea3c8778dcd6c4dd56a7b9270", "testharness" ], "mathml/presentation-markup/scripts/subsup-1.html": [ - "01a6b0e1ed1fed2d069ac2b8b3e3716ffeee08b7", + "e5321d6c4a3c3dafca68caacdb651fed5c778c9b", "testharness" ], "mathml/presentation-markup/scripts/subsup-2.html": [ - "2fd6963b6a7906aaeabd17a16a53a9ebbe56116f", + "1a5b80d34397962c2e7d3400c782bed8cd6f149b", "testharness" ], "mathml/presentation-markup/scripts/subsup-3.html": [ - "60df24a799027c0704be4622976ea8e2ae2a3d22", + "5494bb0c919cba3c02320d4f59481dc4eebed74f", "testharness" ], "mathml/presentation-markup/scripts/subsup-4.html": [ - "6886766097cecff350ddcf3ce81bb87e70b4ce28", + "00bd45413c85667a028394c3b3f983a3b11fed75", "testharness" ], "mathml/presentation-markup/scripts/subsup-5.html": [ - "2cc4e6d9554a1f6fde6c16e37fec2a39c441a0e8", + "566b0133ec68d12c69e6f70d8a9205e2336f8936", "testharness" ], "mathml/presentation-markup/scripts/subsup-parameters-1.html": [ - "7503ad166af33745701ab379cf51fd5cda8ce7dc", + "a5f21ec5458f0cce4b6517e39572d3e928585e20", "testharness" ], "mathml/presentation-markup/scripts/subsup-parameters-2.html": [ - "62aa7a9dc3be90a343dbcb4810e5cb479707be2e", + "0abf01838c8c8c05f1c6cb4bf72e9fea57bca8d9", "testharness" ], "mathml/presentation-markup/scripts/underover-1.html": [ - "b17835528a0ed8d78d643ef9f24dd7822b62f559", + "5b718707de9ab316c6abb0ae7bf26667af191447", "testharness" ], "mathml/presentation-markup/scripts/underover-parameters-1.html": [ - "d8a564a1159518195e889694aee8d0b167efec91", + "26a1b3964cc10ced8762314390840db94efdb970", "testharness" ], "mathml/presentation-markup/scripts/underover-parameters-2.html": [ - "c10f77ee2c807b8a24566574f6ff6377736ae514", + "aed22235b8c192ee69237c63face745e7e35e1bd", "testharness" ], "mathml/presentation-markup/scripts/underover-parameters-3.html": [ - "86562fd374bdb44983657954f5b554ae62db8984", + "6a1e51cdc4516ae1fdd2784c0e77682222773b2f", "testharness" ], "mathml/presentation-markup/scripts/underover-parameters-4.html": [ - "f7fb389b59feb23276773a91b854fd6ab105fc15", + "e569c15a6993321051b2490f62c5b6ae39666b7a", "testharness" ], "mathml/presentation-markup/spaces/mspace-children-ref.html": [ @@ -442225,23 +442584,23 @@ "reftest" ], "mathml/presentation-markup/spaces/space-like-001.html": [ - "d2db45657ad5f89c6b6fadfc443c203caf9558c9", + "61375bcd8e320be57e471815891c68aa01e76065", "testharness" ], "mathml/presentation-markup/spaces/space-like-002.html": [ - "78f4c927c276a60beaefb219d3d73114e7ae5cee", + "f5f4e5a84b248184bf33aa46ffacf35241209ce3", "testharness" ], "mathml/presentation-markup/spaces/space-like-003.html": [ - "8831657a3eb9dfa6ba7131534f6baee495a0ffb3", + "6d3d007744e7a346cee178187f39928407ac1511", "testharness" ], "mathml/presentation-markup/spaces/space-like-004.html": [ - "28a2871b1368a2fb3654b8f08d622512fc8dc61e", + "091a3ea0a628c9b18b4b262aef737d7a7c9dac0a", "testharness" ], "mathml/presentation-markup/tables/table-axis-height.html": [ - "feb29077e8e34bcd3155f0661f4878bb93bdbf19", + "3eaf9c8fff483232eb6794b603f270bb86c47d3d", "testharness" ], "mathml/relations/css-styling/color-1-ref.html": [ @@ -442580,6 +442939,10 @@ "4e92a846461b65d150cef9a9444de27abf40a26d", "reftest" ], + "mathml/support/feature-detection.js": [ + "5beb78c2776153e586ff6ffa1265a00bceba3f67", + "support" + ], "mathml/tools/axisheight.py": [ "43827e7031665bdd57ee54e208ea0f875a9a60ec", "support" @@ -444297,7 +444660,7 @@ "support" ], "mixed-content/generic/tools/generate.py": [ - "fe4305c4eea53b1e0317e92303078f0b6875c772", + "1edc22908c0c815b875eba81e09f430599ea7494", "support" ], "mixed-content/generic/tools/regenerate": [ @@ -444305,7 +444668,7 @@ "support" ], "mixed-content/generic/tools/spec_validator.py": [ - "686579ece5797abfdb5441e080db85758fe1b220", + "fe24657e78a678b1c73382313e4d4b4e00fad5d0", "support" ], "mixed-content/imageset.https.sub.html": [ @@ -446508,10 +446871,6 @@ "f2c2fc82866b83953e2783f8dc56ceaa0803b097", "testharness" ], - "native-file-system/NativeFileSystemWritableFileStream.tentative.https.window.js": [ - "1dbcb2b136220954c777b2cc3b0197039cf730be", - "testharness" - ], "native-file-system/README.md": [ "6905a68e7901ce26bc1a363062304e1536604400", "support" @@ -456217,7 +456576,7 @@ "support" ], "referrer-policy/generic/tools/generate.py": [ - "b3e3340d97b346c3f2aa787dd55635dffa63f929", + "71d5ad37de134e9b07b53b8ed08244e0afd98dc9", "support" ], "referrer-policy/generic/tools/regenerate": [ @@ -456225,7 +456584,7 @@ "support" ], "referrer-policy/generic/tools/spec_validator.py": [ - "70656db25d2ce4f09c3fbb8a90294cb7fa20ba97", + "569afc305f43ed9fc9f939769e4c8313276e5cb8", "support" ], "referrer-policy/generic/unsupported-csp-referrer-directive.html": [ @@ -471137,7 +471496,7 @@ "testharness" ], "std-toast/options.html": [ - "b75ff72cb9e86857e249a50f1ccb0713ad5c9144", + "9f53bf88601ce914b1acf4054121d9420370fffa", "testharness" ], "std-toast/ref-tests/toast-slotting-expected.html": [ @@ -474489,11 +474848,11 @@ "support" ], "tools/requirements_flake8.txt": [ - "480aacd466257f82068f5c133ec90e59a2b1eb4f", + "d73e7c3dbbe2f0cf20637e639c449b0fa4538caf", "support" ], "tools/requirements_mypy.txt": [ - "8f1d67cd21230939a2ff4fe09f7e3960b58ca560", + "c1bf4bc088e7003d7ea2b362a28048e8952d2031", "support" ], "tools/runner/css/bootstrap-theme.min.css": [ @@ -478337,7 +478696,7 @@ "support" ], "tools/tox.ini": [ - "ba6dc038a172895f0bda838c6456a5db95a75952", + "63fb8ed9832ba9d11dae965e3c335e3d26289720", "support" ], "tools/webdriver/README.md": [ @@ -478401,7 +478760,7 @@ "support" ], "tools/wpt/run.py": [ - "6acc5b8e7400f5726538657239de5710ecea396d", + "d5d7e7a21f5f3b195ce5b93141d6798bdfeb5e2d", "support" ], "tools/wpt/testfiles.py": [ @@ -478425,7 +478784,7 @@ "support" ], "tools/wpt/wpt.py": [ - "4130e1eecf8ae52dbc0b68f6cd59010dd4e435e4", + "93301dd86b4ffe202902a492204eba6537fb50d5", "support" ], "tools/wptrunner/LICENSE": [ @@ -478441,7 +478800,7 @@ "support" ], "tools/wptrunner/requirements.txt": [ - "e25eec38283e0825a7a402912376c3a396d6de70", + "d6c7a4ff3983663d088c64f6608e3fcf7de3bbfe", "support" ], "tools/wptrunner/requirements_chrome.txt": [ @@ -478589,7 +478948,7 @@ "support" ], "tools/wptrunner/wptrunner/environment.py": [ - "2493f1fa4407a39aad3ac3c2a724322b75b0944a", + "924409216411050b038b61c7402eab687b122429", "support" ], "tools/wptrunner/wptrunner/executors/__init__.py": [ @@ -478797,7 +479156,7 @@ "support" ], "tools/wptrunner/wptrunner/update/update.py": [ - "a0f42377734b1963d7df1ce1dcb3472be4b7781c", + "0bcaf823b72c30e346a64f3c0344bc2275df64f5", "support" ], "tools/wptrunner/wptrunner/vcs.py": [ @@ -479265,11 +479624,11 @@ "support" ], "trusted-types/trusted-types-reporting.tentative.https.html": [ - "3074895ba13f7f734d00898e723b4b604234a9cb", + "8dda8b23c8f06bfa375b6c6de874c7de0fbfc3c3", "testharness" ], "trusted-types/trusted-types-reporting.tentative.https.html.headers": [ - "8093b8474d686fd665c6e835c6d0ed8f337cf2cd", + "947a151c874ce9d372baa786c1b2964cbd9bc279", "support" ], "uievents/META.yml": [ @@ -481529,7 +481888,7 @@ "testharness" ], "web-nfc/NFCReader_options_mediaType-manual.https-expected.txt": [ - "129e4ce74bcb9d8296dd6d2223ae06d4acec807a", + "091fef83617159b165adb6cc6d434d2a33352013", "support" ], "web-nfc/NFCReader_options_mediaType-manual.https.html": [ @@ -481537,7 +481896,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt": [ - "438f4b6793f044b90d7614a099a29eb243096c7c", + "ec071f4f19f9b96ab44e47457bc96abfe8b0fe8a", "support" ], "web-nfc/NFCReader_options_recordType_empty-manual.https.html": [ @@ -481545,7 +481904,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt": [ - "a8f75b34c373b47bf1ac65de29bf802ffcab0012", + "f0d8fa8ec368df1fb4c04626a89c36e99f88c082", "support" ], "web-nfc/NFCReader_options_recordType_json-manual.https.html": [ @@ -481553,7 +481912,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt": [ - "bd09f8bd971319c6a39dde64c993c4f21339d269", + "9020bf9b4f1334e36c9ee86ca2a82d1f51db28cc", "support" ], "web-nfc/NFCReader_options_recordType_opaque-manual.https.html": [ @@ -481561,7 +481920,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt": [ - "b2b18c5455fef22f83b55bf9657210fcd214a0ad", + "57045f0e2992c42b526c2b411a98c7cca90e1fb9", "support" ], "web-nfc/NFCReader_options_recordType_text-manual.https.html": [ @@ -481569,7 +481928,7 @@ "manual" ], "web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt": [ - "f53c2e72e5af9901a5cd3d896fe92c99b5622918", + "8ef29659d814e7e54d8a4777c86ad0f62b370e5e", "support" ], "web-nfc/NFCReader_options_recordType_url-manual.https.html": [ @@ -481577,7 +481936,7 @@ "manual" ], "web-nfc/NFCReader_options_url-manual.https-expected.txt": [ - "fdf8c72499da615f36431e0f5b1e3bfa869ea3df", + "5a8462e66cc208a5727a0950783a87b0c8f7630c", "support" ], "web-nfc/NFCReader_options_url-manual.https.html": [ @@ -481597,7 +481956,7 @@ "testharness" ], "web-nfc/NFCWriter_push_signal-manual.https-expected.txt": [ - "27dd82df88a4bb43fc02733183e89d6ce57b337d", + "ff64f6129d67cb99b1eb5c505e1a91b03ab96169", "support" ], "web-nfc/NFCWriter_push_signal-manual.https.html": [ @@ -481608,18 +481967,10 @@ "2a0e82019549591b88878ca70fc6baf616d34c29", "support" ], - "web-nfc/idlharness.https.window-expected.txt": [ - "5e3a1003a9a46e8b9df411a370cda6985f7ed558", - "support" - ], "web-nfc/idlharness.https.window.js": [ "c19458aed83f505472e35c8f3affa3247a814989", "testharness" ], - "web-nfc/nfc_hw_disabled-manual.https-expected.txt": [ - "fd955dd5886bc597b07ff0d05dd4f70ba106c160", - "support" - ], "web-nfc/nfc_hw_disabled-manual.https.html": [ "bb2cd42f1e65cca49b03385e9e553cc8077aa08d", "manual" @@ -481629,7 +481980,7 @@ "testharness" ], "web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt": [ - "9f00a673b4f983c6c0a1d1222dd382108836b6a6", + "0377296be29411c97f8115f591c08a369055ab0a", "support" ], "web-nfc/nfc_push_ArrayBuffer-manual.https.html": [ @@ -481637,7 +481988,7 @@ "manual" ], "web-nfc/nfc_push_DOMString-manual.https-expected.txt": [ - "29791a39dd73e276d92febd8ea82f467e73b6a64", + "c4e37077e0e058cb2e18575190701ae766852b0f", "support" ], "web-nfc/nfc_push_DOMString-manual.https.html": [ @@ -484668,12 +485019,16 @@ "f2add7f0d34bada5c156cafeac399e104b2a414a", "testharness" ], + "webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html": [ + "4dcce451995597ea072c7e491f0cef908014cf0c", + "testharness" + ], "webrtc/RTCPeerConnection-restartIce.https-expected.txt": [ - "0ec3508566898d37d8c97c1fb26053ac58b0f290", + "2c0c15ceca3a4e960d4230bda6bb86849256f103", "support" ], "webrtc/RTCPeerConnection-restartIce.https.html": [ - "6b66975fdad2b5b11159baf921bdcae93d6deb23", + "c069736fa0b37be2bff7174e5ea65aaf91fb5b61", "testharness" ], "webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt": [ @@ -484989,7 +485344,7 @@ "testharness" ], "webrtc/idlharness.https.window-expected.txt": [ - "1f26f0d506c51105c2e769caa4270ebc6d3e472a", + "2671b880c6f8d24e05efab15bf321b7064419ca3", "support" ], "webrtc/idlharness.https.window.js": [ @@ -489732,6 +490087,10 @@ "0e2c23424c0893b6a563c2aa2fbd999e50b1cfef", "testharness" ], + "webxr/exclusive_requestFrame_nolayer.https.html": [ + "d31b927631f91128933c1badd56747315c767780", + "testharness" + ], "webxr/getInputPose_handedness.https.html": [ "5a310c6dd77274631d0ef9e751c6f195def9c3d3", "testharness" @@ -489748,6 +490107,14 @@ "3e54e367787cb95dada398790fe23b10174df29f", "testharness" ], + "webxr/render_state_vertical_fov_immersive.https.html": [ + "485438cabf6a633df42a0f94c04922e7274013e1", + "testharness" + ], + "webxr/render_state_vertical_fov_inline.https.html": [ + "8bf384f4f150b0b2e841b33d67e290011694c0f4", + "testharness" + ], "webxr/resources/webxr_check.html": [ "2d8e5b387dc88588921ccfa49dd14db58009900c", "support" @@ -489916,6 +490283,10 @@ "bdb5edda566704c4d1434b328d3adbe46d3501ba", "testharness" ], + "webxr/xrSession_requestAnimationFrame_timestamp.https.html": [ + "daa786b368627dfc60663470e9e339f97eff729c", + "testharness" + ], "webxr/xrSession_requestReferenceSpace.https.html": [ "51aa8885f5e853ca4bf225134dee120b71d28011", "testharness" @@ -489936,6 +490307,22 @@ "956edba98365d90eb180ad3c9697dae098bd25db", "testharness" ], + "webxr/xrView_match.https.html": [ + "142f272d36f812c49455a78bfc62f285f9e64818", + "testharness" + ], + "webxr/xrView_oneframeupdate.https.html": [ + "9404fcb8aaf33876f2918d3796190f16feafe506", + "testharness" + ], + "webxr/xrViewport_valid.https.html": [ + "1b7d982d596187f1381bee73eac2990900a37f8f", + "testharness" + ], + "webxr/xrWebGLLayer_constructor.https.html": [ + "74f0e7611e5e201a275b1a444a6d4b367af3e53d", + "testharness" + ], "webxr/xrWebGLLayer_framebuffer.https-expected.txt": [ "54e5aa445b27baa62ee3c94a64c96b942edfdbb6", "support" @@ -489944,6 +490331,18 @@ "ba6b7dc0b922ae45aa714de8d3ca6f4ffbaf414c", "testharness" ], + "webxr/xrWebGLLayer_framebuffer_draw.https.html": [ + "dd40865e445aafce88f5941f4127236c36f01f2d", + "testharness" + ], + "webxr/xrWebGLLayer_framebuffer_scale.https.html": [ + "7b5cedb1c83987daf435f662e5687cf6e1bb0559", + "testharness" + ], + "webxr/xrWebGLLayer_opaque_framebuffer.https.html": [ + "ceff6251d565726ddb56798da7bbbef649d96d2f", + "testharness" + ], "webxr/xrWebGLLayer_viewports.https.html": [ "94a23dcdb427298722a989987a02f35a8d98d055", "testharness"
diff --git a/third_party/blink/web_tests/external/wpt/common/security-features/tools/format_spec_src_json.py b/third_party/blink/web_tests/external/wpt/common/security-features/tools/format_spec_src_json.py new file mode 100644 index 0000000..1276c78 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/common/security-features/tools/format_spec_src_json.py
@@ -0,0 +1,20 @@ +import collections +import json +import os + + +def main(): + '''Formats spec.src.json.''' + script_directory = os.path.dirname(os.path.abspath(__file__)) + for dir in ['mixed-content', 'referrer-policy']: + filename = os.path.join(script_directory, '..', '..', '..', dir, + 'spec.src.json') + spec = json.load( + open(filename, 'r'), object_pairs_hook=collections.OrderedDict) + with open(filename, 'w') as f: + f.write(json.dumps(spec, indent=2, separators=(',', ': '))) + f.write('\n') + + +if __name__ == '__main__': + main()
diff --git a/third_party/blink/web_tests/external/wpt/common/security-features/tools/generate.py b/third_party/blink/web_tests/external/wpt/common/security-features/tools/generate.py index 50c3a2c..fc10e63 100644 --- a/third_party/blink/web_tests/external/wpt/common/security-features/tools/generate.py +++ b/third_party/blink/web_tests/external/wpt/common/security-features/tools/generate.py
@@ -28,7 +28,10 @@ return expansion -def permute_expansion(expansion, artifact_order, selection = {}, artifact_index = 0): +def permute_expansion(expansion, + artifact_order, + selection={}, + artifact_index=0): assert isinstance(artifact_order, list), "artifact_order should be a list" if artifact_index >= len(artifact_order): @@ -39,20 +42,23 @@ for artifact_value in expansion[artifact_key]: selection[artifact_key] = artifact_value - for next_selection in permute_expansion(expansion, - artifact_order, - selection, - artifact_index + 1): + for next_selection in permute_expansion(expansion, artifact_order, + selection, artifact_index + 1): yield next_selection -def generate_selection(config, selection, spec, test_html_template_basename): - # TODO: Refactor out this referrer-policy-specific part. - if 'referrer_policy' in spec: - # Oddball: it can be None, so in JS it's null. - selection['referrer_policy'] = spec['referrer_policy'] +# Dumps the test config `selection` into a serialized JSON string. +# We omit `name` parameter because it is not used by tests. +def dump_test_parameters(selection): + selection = dict(selection) + del selection['name'] - test_parameters = json.dumps(selection, indent=2, separators=(',', ':')) + return json.dumps( + selection, indent=2, separators=(',', ': '), sort_keys=True) + + +def generate_selection(config, selection, spec, test_html_template_basename): + test_parameters = dump_test_parameters(selection) # Adjust the template for the test invoking JS. Indent it to look nice. indent = "\n" + " " * 8 test_parameters = test_parameters.replace("\n", indent) @@ -66,14 +72,16 @@ ''' % (config.test_case_name, test_parameters) selection['spec_name'] = spec['name'] - selection['test_page_title'] = config.test_page_title_template % spec['title'] + selection[ + 'test_page_title'] = config.test_page_title_template % spec['title'] selection['spec_description'] = spec['description'] selection['spec_specification_url'] = spec['specification_url'] selection['helper_js'] = config.helper_js selection['sanity_checker_js'] = config.sanity_checker_js selection['spec_json_js'] = config.spec_json_js - test_filename = os.path.join(config.spec_directory, config.test_file_path_pattern % selection) + test_filename = os.path.join(config.spec_directory, + config.test_file_path_pattern % selection) test_headers_filename = test_filename + ".headers" test_directory = os.path.dirname(test_filename) @@ -83,14 +91,15 @@ html_template_filename = os.path.join(util.template_directory, test_html_template_basename) generated_disclaimer = disclaimer_template \ - % {'generating_script_filename': os.path.relpath(__file__, + % {'generating_script_filename': os.path.relpath(sys.argv[0], util.test_root_directory), 'html_template_filename': os.path.relpath(html_template_filename, util.test_root_directory)} # Adjust the template for the test invoking JS. Indent it to look nice. selection['generated_disclaimer'] = generated_disclaimer.rstrip() - selection['test_description'] = config.test_description_template % selection + selection[ + 'test_description'] = config.test_description_template % selection selection['test_description'] = \ selection['test_description'].rstrip().replace("\n", "\n" + " " * 33) @@ -123,9 +132,11 @@ specification = spec_json['specification'] spec_json_js_template = util.get_template('spec_json.js.template') - generated_spec_json_filename = os.path.join(config.spec_directory, "spec_json.js") - util.write_file(generated_spec_json_filename, - spec_json_js_template % {'spec_json': json.dumps(spec_json)}) + generated_spec_json_filename = os.path.join(config.spec_directory, + "spec_json.js") + util.write_file( + generated_spec_json_filename, + spec_json_js_template % {'spec_json': json.dumps(spec_json)}) # Choose a debug/release template depending on the target. html_template = "test.%s.html.template" % target @@ -149,13 +160,18 @@ output_dict = {} for expansion_pattern in spec['test_expansion']: - expansion = expand_pattern(expansion_pattern, test_expansion_schema) + expansion = expand_pattern(expansion_pattern, + test_expansion_schema) for selection in permute_expansion(expansion, artifact_order): + selection['delivery_key'] = spec_json['delivery_key'] selection_path = config.selection_pattern % selection if not selection_path in exclusion_dict: if selection_path in output_dict: if expansion_pattern['expansion'] != 'override': - print("Error: %s's expansion is default but overrides %s" % (selection['name'], output_dict[selection_path]['name'])) + print( + "Error: %s's expansion is default but overrides %s" + % (selection['name'], + output_dict[selection_path]['name'])) sys.exit(1) output_dict[selection_path] = copy.deepcopy(selection) else: @@ -163,24 +179,30 @@ for selection_path in output_dict: selection = output_dict[selection_path] - generate_selection(config, - selection, - spec, - html_template) + generate_selection(config, selection, spec, html_template) def main(config): - parser = argparse.ArgumentParser(description='Test suite generator utility') - parser.add_argument('-t', '--target', type = str, - choices = ("release", "debug"), default = "release", - help = 'Sets the appropriate template for generating tests') - parser.add_argument('-s', '--spec', type = str, default = None, - help = 'Specify a file used for describing and generating the tests') + parser = argparse.ArgumentParser( + description='Test suite generator utility') + parser.add_argument( + '-t', + '--target', + type=str, + choices=("release", "debug"), + default="release", + help='Sets the appropriate template for generating tests') + parser.add_argument( + '-s', + '--spec', + type=str, + default=None, + help='Specify a file used for describing and generating the tests') # TODO(kristijanburnik): Add option for the spec_json file. args = parser.parse_args() if args.spec: - config.spec_directory = args.spec + config.spec_directory = args.spec spec_filename = os.path.join(config.spec_directory, "spec.src.json") spec_json = util.load_spec_json(spec_filename)
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/generic/tools/spec_validator.py b/third_party/blink/web_tests/external/wpt/common/security-features/tools/spec_validator.py similarity index 77% rename from third_party/blink/web_tests/external/wpt/mixed-content/generic/tools/spec_validator.py rename to third_party/blink/web_tests/external/wpt/common/security-features/tools/spec_validator.py index 686579ec..2c966478 100755 --- a/third_party/blink/web_tests/external/wpt/mixed-content/generic/tools/spec_validator.py +++ b/third_party/blink/web_tests/external/wpt/common/security-features/tools/spec_validator.py
@@ -3,7 +3,7 @@ from __future__ import print_function import json, sys -from common_paths import * + def assert_non_empty_string(obj, field): assert field in obj, 'Missing field "%s"' % field @@ -31,12 +31,13 @@ def assert_value_from(obj, field, items): - assert obj[field] in items, \ - 'Field "%s" must be from: %s' % (field, str(items)) + assert obj[field] in items, \ + 'Field "%s" must be from: %s' % (field, str(items)) def assert_atom_or_list_items_from(obj, field, items): - if isinstance(obj[field], basestring) or isinstance(obj[field], int): + if isinstance(obj[field], basestring) or isinstance( + obj[field], int) or obj[field] is None: assert_value_from(obj, field, items) return @@ -71,13 +72,15 @@ assert_valid_artifact(exp_pattern[artifact_key], sub_artifact_key, sub_schema) + def validate(spec_json, details): """ Validates the json specification for generating tests. """ details['object'] = spec_json - assert_contains_only_fields(spec_json, ["specification", - "test_expansion_schema", - "excluded_tests"]) + assert_contains_only_fields(spec_json, [ + "specification", "delivery_key", "test_expansion_schema", + "excluded_tests" + ]) assert_non_empty_list(spec_json, "specification") assert_non_empty_dict(spec_json, "test_expansion_schema") assert_non_empty_list(spec_json, "excluded_tests") @@ -93,11 +96,10 @@ details['object'] = spec # Validate required fields for a single spec. - assert_contains_only_fields(spec, ['name', - 'title', - 'description', - 'specification_url', - 'test_expansion']) + assert_contains_only_fields(spec, [ + 'name', 'title', 'description', 'specification_url', + 'test_expansion' + ]) assert_non_empty_string(spec, 'name') assert_non_empty_string(spec, 'title') assert_non_empty_string(spec, 'description') @@ -123,14 +125,10 @@ # Validate the test_expansion schema members. details['object'] = test_expansion_schema - assert_contains_only_fields(test_expansion_schema, ['expansion', - 'source_scheme', - 'opt_in_method', - 'context_nesting', - 'redirection', - 'subresource', - 'origin', - 'expectation']) + assert_contains_only_fields(test_expansion_schema, [ + 'expansion', 'source_scheme', 'delivery_type', 'delivery_value', + 'redirection', 'subresource', 'origin', 'expectation' + ]) # Validate excluded tests. details['object'] = excluded_tests for excluded_test_expansion in excluded_tests: @@ -139,10 +137,8 @@ details['object'] = excluded_test_expansion for artifact in test_expansion_schema: details['test_expansion_field'] = artifact - assert_valid_artifact( - excluded_test_expansion, - artifact, - test_expansion_schema[artifact]) + assert_valid_artifact(excluded_test_expansion, artifact, + test_expansion_schema[artifact]) del details['test_expansion_field'] del details['object'] @@ -159,7 +155,7 @@ def main(): - spec_json = load_spec_json(); + spec_json = load_spec_json() assert_valid_spec_json(spec_json) print("Spec JSON is valid.")
diff --git a/third_party/blink/web_tests/external/wpt/common/security-features/tools/util.py b/third_party/blink/web_tests/external/wpt/common/security-features/tools/util.py index 77b89769ca..1f6c86e 100644 --- a/third_party/blink/web_tests/external/wpt/common/security-features/tools/util.py +++ b/third_party/blink/web_tests/external/wpt/common/security-features/tools/util.py
@@ -3,10 +3,10 @@ import os, sys, json, re script_directory = os.path.dirname(os.path.abspath(__file__)) -template_directory = os.path.abspath(os.path.join(script_directory, - 'template')) -test_root_directory = os.path.abspath(os.path.join(script_directory, - '..', '..', '..')) +template_directory = os.path.abspath( + os.path.join(script_directory, 'template')) +test_root_directory = os.path.abspath( + os.path.join(script_directory, '..', '..', '..')) def get_template(basename): @@ -20,22 +20,22 @@ def read_nth_line(fp, line_number): - fp.seek(0) - for i, line in enumerate(fp): - if (i + 1) == line_number: - return line + fp.seek(0) + for i, line in enumerate(fp): + if (i + 1) == line_number: + return line def load_spec_json(path_to_spec): re_error_location = re.compile('line ([0-9]+) column ([0-9]+)') with open(path_to_spec, "r") as f: try: - return json.load(f) + return json.load(f) except ValueError as ex: - print(ex.message) - match = re_error_location.search(ex.message) - if match: - line_number, column = int(match.group(1)), int(match.group(2)) - print(read_nth_line(f, line_number).rstrip()) - print(" " * (column - 1) + "^") - sys.exit(1) + print(ex.message) + match = re_error_location.search(ex.message) + if match: + line_number, column = int(match.group(1)), int(match.group(2)) + print(read_nth_line(f, line_number).rstrip()) + print(" " * (column - 1) + "^") + sys.exit(1)
diff --git a/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_insecure.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_insecure.tentative.https.window.js new file mode 100644 index 0000000..bb1907f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/cookie-store/cookieStore_delete_insecure.tentative.https.window.js
@@ -0,0 +1,19 @@ +'use strict'; + +promise_test(async t => { + await cookieStore.set('cookie-name', 'cookie-value', { secure: false }); + t.add_cleanup(async () => { await cookieStore.delete('cookie-name'); }); + + await cookieStore.delete('cookie-name'); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie, null); +}, 'cookieStore.delete(name) can delete an insecure cookie'); + +promise_test(async t => { + await cookieStore.set('cookie-name', 'cookie-value', { secure: false }); + t.add_cleanup(async () => { await cookieStore.delete('cookie-name'); }); + + await cookieStore.delete({ name: 'cookie-name' }); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie, null); +}, 'cookieStore.delete(options) can delete an insecure cookie'); \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-004.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-004.html index c4b2195..ede41909 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-004.html +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-004.html
@@ -8,3 +8,4 @@ display: none } </style> +<body></body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-005.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-005.html index 702b2b2..05c5421 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-005.html +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-005.html
@@ -6,3 +6,4 @@ html { display: none; } body { background: red; } </style> +<body></body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-006.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-006.html index b575891..4c58cb9d 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-006.html +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-006.html
@@ -14,3 +14,4 @@ })); }; </script> +<body></body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-007.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-007.html new file mode 100644 index 0000000..6deda8d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-color-body-propagation-007.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<title>CSS Backgrounds and Borders Test: don't propagate body background when display:contents</title> +<link rel="help" href="https://drafts.csswg.org/css-backgrounds/#special-backgrounds"> +<link rel="match" href="../reference/blank.html"> +<style> + body { + background: red; + display: contents + } +</style> +<body></body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-source-computed.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-source-computed.sub.html similarity index 92% rename from third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-source-computed.html rename to third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-source-computed.sub.html index 96e6bdf..20343882 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-source-computed.html +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/parsing/border-image-source-computed.sub.html
@@ -13,7 +13,7 @@ <div id="target"></div> <script> test_computed_value("border-image-source", "none"); -test_computed_value("border-image-source", 'url("http://www.example.com/")'); +test_computed_value("border-image-source", 'url("http://{{host}}/")'); test(() => { const target = document.getElementById('target');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-insert-child-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-insert-child-ref.html new file mode 100644 index 0000000..bbf2e66a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-insert-child-ref.html
@@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<html><head> + <meta charset="utf-8"> + <title>Reference: Insert text node as first child in LI</title> + <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org"> + <style> + ul.inside { list-style-position: inside; } + .before::before { content: "before"; } + .after::after { content: "after"; } + </style> +</head> +<body> + +<ul class="inside"> + <li>AB</li> +</ul> + +<ul class="inside"> + <li class="before">AB</li> +</ul> + +<ul class="inside"> + <li class="after">AB</li> +</ul> + +<ul class="inside"> + <li class="before after">AB</li> +</ul> + +<ul> + <li>AB</li> +</ul> + +<ul> + <li class="before">AB</li> +</ul> + +<ul> + <li class="after">AB</li> +</ul> + +<ul> + <li class="before after">AB</li> +</ul> + +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-insert-child.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-insert-child.html new file mode 100644 index 0000000..d82bf13 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-insert-child.html
@@ -0,0 +1,60 @@ +<!DOCTYPE HTML> +<!-- + Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ +--> +<html class="reftest-wait"><head> + <meta charset="utf-8"> + <title>Test: Insert text node as first child in LI</title> + <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org"> + <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1567773"> + <link rel="match" href="li-insert-child-ref.html"> + <style> + ul.inside { list-style-position: inside; } + .before::before { content: "before"; } + .after::after { content: "after"; } + </style> +</head> +<body> + +<ul class="inside"> + <li>B</li> +</ul> + +<ul class="inside"> + <li class="before">B</li> +</ul> + +<ul class="inside"> + <li class="after">B</li> +</ul> + +<ul class="inside"> + <li class="before after">B</li> +</ul> + +<ul> + <li>B</li> +</ul> + +<ul> + <li class="before">B</li> +</ul> + +<ul> + <li class="after">B</li> +</ul> + +<ul> + <li class="before after">B</li> +</ul> + +<script> +document.body.offsetHeight; +let items = Array.prototype.slice.call(document.querySelectorAll('li')); +items.map(li => li.insertBefore(document.createTextNode('A'), li.firstChild)); +document.documentElement.className = ''; +</script> + +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-computed.html b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-computed.sub.html similarity index 78% rename from third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-computed.html rename to third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-computed.sub.html index 67bdc46..611fae5b 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-computed.html +++ b/third_party/blink/web_tests/external/wpt/css/css-lists/parsing/list-style-computed.sub.html
@@ -15,10 +15,10 @@ test_computed_value('list-style', 'none', 'outside none none'); test_computed_value('list-style', 'inside', 'inside none disc'); -test_computed_value('list-style', 'url("https://example.com/")', 'outside url("https://example.com/") disc'); +test_computed_value('list-style', 'url("https://{{host}}/")', 'outside url("https://{{host}}/") disc'); test_computed_value('list-style', 'square', 'outside none square'); -test_computed_value('list-style', 'inside url("https://example.com/") square'); +test_computed_value('list-style', 'inside url("https://{{host}}/") square'); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-001.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-001.tentative.html new file mode 100644 index 0000000..0998fe6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-001.tentative.html
@@ -0,0 +1,12 @@ +<!doctype html> +<title>CSS Overflow Test: Propagation of body overflow to viewport</title> +<link rel="help" href="https://drafts.csswg.org/css-overflow/#overflow-propagation"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/pull/4148"> +<link rel="match" href="reference/overflow-body-propagation-ref.html"> +<style> + body { + overflow: scroll; + margin-top: 100px; + } +</style> +<body>The viewport should have scrollbars, not the body.</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-002.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-002.tentative.html new file mode 100644 index 0000000..5991dd5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-002.tentative.html
@@ -0,0 +1,6 @@ +<!doctype html> +<title>CSS Overflow Test: Do not propagate overflow of display:none body to viewport</title> +<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#overflow-propagation"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/pull/4148"> +<link rel="match" href="/css/reference/blank.html"> +<body style="display:none; overflow:scroll"></body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-003.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-003.tentative.html new file mode 100644 index 0000000..a329a8df --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-003.tentative.html
@@ -0,0 +1,6 @@ +<!doctype html> +<title>CSS Overflow Test: Do not propagate overflow of display:contents body to viewport</title> +<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#overflow-propagation"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/pull/4148"> +<link rel="match" href="/css/reference/blank.html"> +<body style="display:contents; overflow:scroll"></body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-004.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-004.tentative.html new file mode 100644 index 0000000..2ed8d268 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-body-propagation-004.tentative.html
@@ -0,0 +1,14 @@ +<!doctype html> +<link rel="help" href="https://drafts.csswg.org/css-overflow/#overflow-propagation"> +<link rel="help" href="https://github.com/w3c/csswg-drafts/pull/4148"> +<link rel="match" href="reference/overflow-body-no-propagation-ref.html"> +<style> + html { + overflow: hidden; + } + body { + overflow: scroll; + margin-top: 100px; + } +</style> +<body>The body should have scrollbars, not the viewport.</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/overflow-body-no-propagation-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/overflow-body-no-propagation-ref.html new file mode 100644 index 0000000..9795d1f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/overflow-body-no-propagation-ref.html
@@ -0,0 +1,5 @@ +<!doctype html> +<html style="overflow:auto"> +<title>CSS Overflow Test Reference</title> +<body style="margin-top:100px;overflow:scroll">The body should have scrollbars, not the viewport.</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/overflow-body-propagation-ref.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/overflow-body-propagation-ref.html new file mode 100644 index 0000000..340bda9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/reference/overflow-body-propagation-ref.html
@@ -0,0 +1,5 @@ +<!doctype html> +<html style="overflow:scroll"> +<title>CSS Overflow Test Reference</title> +<body style="margin-top:100px">The viewport should have scrollbars, not the body.</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scrollbars/scrollbars-chrome-bug-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-scrollbars/scrollbars-chrome-bug-001-ref.html new file mode 100644 index 0000000..1bf59f90 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scrollbars/scrollbars-chrome-bug-001-ref.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<link rel="help" href="https://crbug.com/926167"> +<style> + +#container { + width: 200px; + height: 150px; + border: 1px solid black; + overflow: scroll; +} +#target { + width: 100px; + height: 50px; + background: green; + transform: scale(4); +} +</style> +<!-- --> +<div id="container"> + <div id="target"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scrollbars/scrollbars-chrome-bug-001.html b/third_party/blink/web_tests/external/wpt/css/css-scrollbars/scrollbars-chrome-bug-001.html new file mode 100644 index 0000000..643781b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scrollbars/scrollbars-chrome-bug-001.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>CSS Overflow: css-overflow-3</title> +<link rel="author" href="mailto:atotic@google.com"> +<link rel="help" href="https://crbug.com/926167"> +<link rel="match" href="scrollbars-chrome-bug-001-ref.html"> +<meta name="assert" content="scrollbars keep up to date with a changing transform"> +<style> + +#container { + width: 200px; + height: 150px; + border: 1px solid black; + overflow: scroll; +} +#target { + width: 100px; + height: 50px; + background: green; + transform: scale(1); +} +</style> +<!-- --> +<div id="container"> + <div id="target"></div> +</div> +<script> + // 1st transform triggers layer creation, and full layout. + // 2nd transform just updates overflow, which does not update scrollbars. + // This triggers the bug. + document.body.offsetTop; + document.querySelector("#target").style.transform = "scale(1.5)"; + document.body.offsetTop; + document.querySelector("#target").style.transform = "scale(4.0)"; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-computed-expected.txt new file mode 100644 index 0000000..8a246fc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-computed-expected.txt
@@ -0,0 +1,9 @@ +This is a testharness.js-based test. +PASS Property shape-image-threshold value '-7' computes to '0' +PASS Property shape-image-threshold value '0.5' computes to '0.5' +PASS Property shape-image-threshold value '12.5' computes to '1' +PASS Property shape-image-threshold value '-100%' computes to '0' +FAIL Property shape-image-threshold value '50%' computes to '0.5' assert_equals: expected "0.5" but got "0" +FAIL Property shape-image-threshold value '300%' computes to '1' assert_equals: expected "1" but got "0" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-computed.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-computed.html index a90d23a6..81bc0cc 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-computed.html +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-computed.html
@@ -15,6 +15,11 @@ test_computed_value("shape-image-threshold", "-7", "0"); test_computed_value("shape-image-threshold", "0.5"); test_computed_value("shape-image-threshold", "12.5", "1"); + +// https://github.com/w3c/csswg-drafts/issues/4102 +test_computed_value("shape-image-threshold", "-100%", "0"); +test_computed_value("shape-image-threshold", "50%", "0.5"); +test_computed_value("shape-image-threshold", "300%", "1"); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-invalid.html index 6299e2e..c0cac03 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-invalid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-invalid.html
@@ -14,7 +14,6 @@ <script> test_invalid_value("shape-image-threshold", "auto"); test_invalid_value("shape-image-threshold", "10px"); -test_invalid_value("shape-image-threshold", "100%"); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-valid-expected.txt new file mode 100644 index 0000000..b6e14a0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-valid-expected.txt
@@ -0,0 +1,8 @@ +This is a testharness.js-based test. +PASS e.style['shape-image-threshold'] = "12.5" should set the property value +PASS e.style['shape-image-threshold'] = "-7" should set the property value +FAIL e.style['shape-image-threshold'] = "-100%" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['shape-image-threshold'] = "50%" should set the property value assert_not_equals: property should be set got disallowed value "" +FAIL e.style['shape-image-threshold'] = "300%" should set the property value assert_not_equals: property should be set got disallowed value "" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-valid.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-valid.html index 914abd0..4ed1fb9 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-valid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/parsing/shape-image-threshold-valid.html
@@ -14,6 +14,11 @@ <script> test_valid_value("shape-image-threshold", "12.5"); test_valid_value("shape-image-threshold", "-7"); + +// https://github.com/w3c/csswg-drafts/issues/4102 +test_valid_value("shape-image-threshold", "-100%", "-1"); +test_valid_value("shape-image-threshold", "50%", "0.5"); +test_valid_value("shape-image-threshold", "300%", "3"); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/perspective-transforms-equivalence-ref.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/perspective-transforms-equivalence-ref.html new file mode 100644 index 0000000..a4fc022 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/perspective-transforms-equivalence-ref.html
@@ -0,0 +1,40 @@ +<!doctype HTML> +<meta charset="utf8"> +<title>Perspective with transforms equivalencies.</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<style> + +#container { + transform: translate(-200px, -200px); + width: 500px; + height: 500px; + perspective: 500px; +} + +#container > div { + width: 100%; + height: 100%; + transform-style: preserve-3d; + transform: translateZ(-250px) rotateZ(45deg); +} + +#container > div > div { + width: 100%; + height: 100%; + position: absolute; + background-color: rgba(3, 121, 255, 0.3); + box-sizing: border-box; + border: 3px solid black; +} + +#one { transform: rotateY(90deg) translateZ(250px); } +</style> + +<div id="container"> + <div> + <div id="one"></div> + <div id="one"></div> + <div id="one"></div> + <div id="one"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/perspective-transforms-equivalence.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/perspective-transforms-equivalence.html new file mode 100644 index 0000000..2f2ae21 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/perspective-transforms-equivalence.html
@@ -0,0 +1,52 @@ +<!doctype HTML> +<meta charset="utf8"> +<title>Perspective with transforms equivalencies.</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="help" href="http://www.w3.org/TR/css-transforms-2/#perspective-property"> +<link rel="help" href="http://www.w3.org/TR/css-transforms-1/#transform-property"> +<link rel="match" href="perspective-transforms-equivalence-ref.html"> +<!-- +Perspective with different transforms can have small anti-aliasing +pixel differences, so the test should fuzzy patch to the ref. +--> +<meta name="fuzzy" content="maxDifference=10;totalPixels=10"> +<style> + +#container { + transform: translate(-200px, -200px); + width: 500px; + height: 500px; + perspective: 500px; +} + +#container > div { + width: 100%; + height: 100%; + transform-style: preserve-3d; + transform: translateZ(-250px) rotateZ(45deg); +} + +#container > div > div { + width: 100%; + height: 100%; + position: absolute; + background-color: rgba(3, 121, 255, 0.3); + box-sizing: border-box; + border: 3px solid black; +} + +/* The following four should be equivalent. */ +#one { transform: rotateY(90deg) translateZ(250px); } +#two { transform: rotateZ(90deg) rotateX(90deg) translateZ(250px); } +#three { transform: rotateY(-90deg) translateZ(-250px); } +#four { transform: rotateZ(-90deg) rotateX(90deg) translateZ(-250px); } +</style> + +<div id="container"> + <div> + <div id="one"></div> + <div id="two"></div> + <div id="three"></div> + <div id="four"></div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/element-timing/element-only-when-fully-active.html b/third_party/blink/web_tests/external/wpt/element-timing/element-only-when-fully-active.html new file mode 100644 index 0000000..5608685a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/element-timing/element-only-when-fully-active.html
@@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>ElementTiming: element is only exposed for fully active documents.</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe src="resources/iframe-stores-entry.html" id="ifr"></iframe> +<script> + let t = async_test('Only expose element attribute for fully active documents'); + window.triggerTest = t.step_func_done(elementEntry => { + assert_not_equals(elementEntry.element, null); + const iframe = document.getElementById('ifr'); + iframe.remove(); + assert_equals(elementEntry.element, null); + }); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/element-timing/fixed-id-identifier.html b/third_party/blink/web_tests/external/wpt/element-timing/fixed-id-identifier.html new file mode 100644 index 0000000..00d6d4d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/element-timing/fixed-id-identifier.html
@@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Element Timing: entry does not change its id or identifier value</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="resources/element-timing-helpers.js"></script> +<p elementtiming='my_identifier' id='my_id'>Text</p> +<script> + async_test(function (t) { + if (!window.PerformanceElementTiming) { + assert_unreached("PerformanceElementTiming is not implemented"); + } + const observer = new PerformanceObserver( + t.step_func_done(function(entryList) { + assert_equals(entryList.getEntries().length, 1); + const entry = entryList.getEntries()[0]; + assert_equals(entry.id, 'my_id'); + assert_equals(entry.identifier, 'my_identifier'); + const element = document.getElementById('my_id'); + element.id = 'other_id'; + element.setAttribute('elementtiming', 'other_identifier'); + assert_equals(entry.id, 'my_id'); + assert_equals(entry.identifier, 'my_identifier'); + }) + ); + observer.observe({type: 'element', buffered: true}); + }, 'PerformanceElementTiming id and identifier do not change when Element changes.'); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/element-timing/idlharness.window.js b/third_party/blink/web_tests/external/wpt/element-timing/idlharness.window.js new file mode 100644 index 0000000..f0e5d06 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/element-timing/idlharness.window.js
@@ -0,0 +1,16 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +// https://wicg.github.io/element-timing/ + +'use strict'; + +idl_test( + ['element-timing'], + ['performance-timeline', 'dom'], + idl_array => { + idl_array.add_objects({ + // PerformanceElementTiming: [ TODO ] + }); + } +);
diff --git a/third_party/blink/web_tests/external/wpt/element-timing/resources/element-timing-helpers.js b/third_party/blink/web_tests/external/wpt/element-timing/resources/element-timing-helpers.js index 8933732..6328ee7 100644 --- a/third_party/blink/web_tests/external/wpt/element-timing/resources/element-timing-helpers.js +++ b/third_party/blink/web_tests/external/wpt/element-timing/resources/element-timing-helpers.js
@@ -4,13 +4,22 @@ assert_equals(entry.entryType, 'element'); assert_equals(entry.url, expectedUrl); assert_equals(entry.identifier, expectedIdentifier); - assert_equals(entry.startTime, 0); + if (beforeRender != 0) { + // In this case, renderTime is not 0. + assert_equals(entry.startTime, entry.renderTime); + } else { + // In this case, renderTime is 0, so compare to loadTime. + assert_equals(entry.startTime, entry.loadTime); + } assert_equals(entry.duration, 0); assert_equals(entry.id, expectedID); assert_greater_than_equal(entry.renderTime, beforeRender); assert_greater_than_equal(performance.now(), entry.renderTime); - if (expectedElement !== null) + if (expectedElement !== null) { assert_equals(entry.element, expectedElement); + assert_equals(entry.identifier, expectedElement.elementTiming); + assert_equals(entry.id, expectedElement.id); + } } // Checks that this is an ElementTiming entry with url |expectedUrl|. It also
diff --git a/third_party/blink/web_tests/external/wpt/element-timing/resources/iframe-stores-entry.html b/third_party/blink/web_tests/external/wpt/element-timing/resources/iframe-stores-entry.html new file mode 100644 index 0000000..2fa2476 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/element-timing/resources/iframe-stores-entry.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html> +<body> +<p elementtiming='text'>Text</p> +<script> + const observer = new PerformanceObserver(entryList => { + window.parent.triggerTest(entryList.getEntries()[0]); + }); + observer.observe({type: 'element', buffered: true}); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html b/third_party/blink/web_tests/external/wpt/html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html index d425996..e3e0778c9 100644 --- a/third_party/blink/web_tests/external/wpt/html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html +++ b/third_party/blink/web_tests/external/wpt/html/infrastructure/common-dom-interfaces/collections/htmlallcollection.html
@@ -23,6 +23,7 @@ <div id="null"></div> <div name="divwithname"></div> <div id="-0"></div> +<div id="log"></div> <script> var anchors = document.querySelectorAll("a"); var divs = document.querySelectorAll("div"); @@ -34,7 +35,7 @@ }, "document.all is an HTMLAllCollection"); test(function() { - assert_equals(document.all.length, 24); + assert_equals(document.all.length, 25); }, "length attribute"); // indexed property getter @@ -42,12 +43,12 @@ test(function() { assert_equals(document.all[0], document.documentElement); assert_equals(document.all[-0], document.documentElement); - assert_equals(document.all[23], scripts[2]); + assert_equals(document.all[24], scripts[2]); }, "indexed property getter"); test(function() { assert_equals(document.all[-1], undefined); - assert_equals(document.all[24], undefined); + assert_equals(document.all[25], undefined); assert_equals(document.all[42], undefined); assert_equals(document.all[43], undefined); assert_equals(document.all[4294967294], undefined); @@ -86,8 +87,8 @@ test(function() { assert_equals(document.all["0"], document.documentElement); - assert_equals(document.all["23"], document.scripts[2]); - assert_equals(document.all["24"], undefined); + assert_equals(document.all["24"], document.scripts[2]); + assert_equals(document.all["25"], undefined); assert_equals(document.all["42"], undefined); assert_equals(document.all["43"], undefined); }, "named property getter with \"array index property name\""); @@ -187,16 +188,16 @@ test(function() { assert_equals(document.all("0"), document.documentElement); - assert_equals(document.all("23"), document.scripts[2]); - assert_equals(document.all("24"), null); + assert_equals(document.all("24"), document.scripts[2]); + assert_equals(document.all("25"), null); assert_equals(document.all("42"), null); assert_equals(document.all("43"), null); }, "legacy caller with \"array index property name\""); test(function() { assert_equals(document.all(0), document.documentElement); - assert_equals(document.all(23), document.scripts[2]); - assert_equals(document.all(24), null); + assert_equals(document.all(24), document.scripts[2]); + assert_equals(document.all(25), null); assert_equals(document.all(42), null); assert_equals(document.all(43), null); }, "legacy caller with \"array index property name\" as number"); @@ -267,16 +268,16 @@ test(function() { assert_equals(document.all.item("0"), document.documentElement); - assert_equals(document.all.item("23"), document.scripts[2]); - assert_equals(document.all.item("24"), null); + assert_equals(document.all.item("24"), document.scripts[2]); + assert_equals(document.all.item("25"), null); assert_equals(document.all.item("42"), null); assert_equals(document.all.item("43"), null); }, "item method with \"array index property name\""); test(function() { assert_equals(document.all.item(0), document.documentElement); - assert_equals(document.all.item(23), document.scripts[2]); - assert_equals(document.all.item(24), null); + assert_equals(document.all.item(24), document.scripts[2]); + assert_equals(document.all.item(25), null); assert_equals(document.all.item(42), null); assert_equals(document.all.item(43), null); }, "item method with \"array index property name\" as number"); @@ -329,6 +330,5 @@ } }, "collections are new live HTMLCollection instances"); </script> -<div id="log"></div> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/element-timing.idl b/third_party/blink/web_tests/external/wpt/interfaces/element-timing.idl new file mode 100644 index 0000000..dc3b886c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/interfaces/element-timing.idl
@@ -0,0 +1,20 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into reffy-reports +// (https://github.com/tidoust/reffy-reports) +// Source: Element Timing API (https://wicg.github.io/element-timing/) + +interface PerformanceElementTiming : PerformanceEntry { + readonly attribute DOMHighResTimeStamp renderTime; + readonly attribute DOMHighResTimeStamp loadTime; + readonly attribute DOMRectReadOnly intersectionRect; + readonly attribute DOMString identifier; + readonly attribute unsigned long naturalWidth; + readonly attribute unsigned long naturalHeight; + readonly attribute DOMString id; + readonly attribute Element? element; + readonly attribute DOMString url; +}; + +partial interface Element { + [CEReactions] attribute DOMString elementTiming; +};
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/largest-contentful-paint.idl b/third_party/blink/web_tests/external/wpt/interfaces/largest-contentful-paint.idl new file mode 100644 index 0000000..f16a7ff8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/interfaces/largest-contentful-paint.idl
@@ -0,0 +1,13 @@ +// GENERATED CONTENT - DO NOT EDIT +// Content was automatically extracted by Reffy into reffy-reports +// (https://github.com/tidoust/reffy-reports) +// Source: Largest Contentful Paint (https://wicg.github.io/largest-contentful-paint/) + +interface LargestContentfulPaint : PerformanceEntry { + readonly attribute DOMHighResTimeStamp renderTime; + readonly attribute DOMHighResTimeStamp loadTime; + readonly attribute unsigned long size; + readonly attribute DOMString id; + readonly attribute DOMString url; + readonly attribute Element? element; +};
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl b/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl index 8ded59d..d9362ea 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/performance-timeline.idl
@@ -23,8 +23,8 @@ PerformanceObserver observer); [Constructor(PerformanceObserverCallback callback), Exposed=(Window,Worker)] interface PerformanceObserver { - void observe(optional PerformanceObserverInit options); - void disconnect(); + void observe (optional PerformanceObserverInit options = {}); + void disconnect (); PerformanceEntryList takeRecords(); [SameObject] static readonly attribute FrozenArray<DOMString> supportedEntryTypes; };
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/user-timing.idl b/third_party/blink/web_tests/external/wpt/interfaces/user-timing.idl index 4130803f..8b0f813 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/user-timing.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/user-timing.idl
@@ -4,23 +4,23 @@ // Source: User Timing Level 3 (https://w3c.github.io/user-timing/) dictionary PerformanceMarkOptions { - any detail; - DOMHighResTimeStamp startTime; - }; + any detail; + DOMHighResTimeStamp startTime; +}; - dictionary PerformanceMeasureOptions { - any detail; - (DOMString or DOMHighResTimeStamp) start; - DOMHighResTimeStamp duration; - (DOMString or DOMHighResTimeStamp) end; - }; +dictionary PerformanceMeasureOptions { + any detail; + (DOMString or DOMHighResTimeStamp) start; + DOMHighResTimeStamp duration; + (DOMString or DOMHighResTimeStamp) end; +}; - partial interface Performance { - PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions = {}); - void clearMarks(optional DOMString markName); - PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions) startOrMeasureOptions = {}, optional DOMString endMark); - void clearMeasures(optional DOMString measureName); - }; +partial interface Performance { + PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions = {}); + void clearMarks(optional DOMString markName); + PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions) startOrMeasureOptions = {}, optional DOMString endMark); + void clearMeasures(optional DOMString measureName); +}; [Exposed=(Window,Worker), Constructor(DOMString markName, optional PerformanceMarkOptions markOptions)]
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/web-share.idl b/third_party/blink/web_tests/external/wpt/interfaces/web-share.idl index e275aac9..ae1f3f8 100644 --- a/third_party/blink/web_tests/external/wpt/interfaces/web-share.idl +++ b/third_party/blink/web_tests/external/wpt/interfaces/web-share.idl
@@ -3,6 +3,10 @@ // (https://github.com/tidoust/reffy-reports) // Source: Web Share API - Level 1 (https://wicg.github.io/web-share/) +partial interface Navigator { + [SecureContext] Promise<void> share(optional ShareData data = {}); +}; + dictionary ShareData { USVString title; USVString text;
diff --git a/third_party/blink/web_tests/external/wpt/intersection-observer/rtl-clipped-root.html b/third_party/blink/web_tests/external/wpt/intersection-observer/rtl-clipped-root.html new file mode 100644 index 0000000..a30c6e3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/intersection-observer/rtl-clipped-root.html
@@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html dir="rtl"> +<head> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="./resources/intersection-observer-test-utils.js"></script> + + <style> + pre, #log { + position: absolute; + top: 120px; + left: 0; + } + #root { + width: 350px; + height: 100px; + border: 1px solid black; + display: flex; + flex-direction: row; + overflow-x: auto; + } + #target-start, #target-end { + width: 100px; + height: 100px; + flex-shrink: 0; + background-color: green; + text-align: center; + } + #target-end { + margin-inline-start: 500px; + } + </style> +</head> + +<div id="root"> + <div id="target-start">start</div> + <div id="target-end">end</div> +</div> + +<script> +runTestCycle(function() { + let io = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add("intersecting"); + } else { + entry.target.classList.remove("intersecting"); + } + }); + }, { root: document.getElementById("root") }); + document.querySelectorAll("#root > div").forEach(element => { + io.observe(element); + }); + runTestCycle(step0, "First rAF"); +}, "Explicit rtl root with overflow clipping"); + +function step0() { + assert_true( + document.getElementById("target-start").classList.contains("intersecting"), + "Target at scroll start is intersecting"); + assert_false( + document.getElementById("target-end").classList.contains("intersecting"), + "Target at scroll end is not intersecting"); +} +</script>
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/element-only-when-fully-active.html b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/element-only-when-fully-active.html new file mode 100644 index 0000000..41bdc8f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/element-only-when-fully-active.html
@@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Largest Contentful Paint: element is only exposed for fully active documents.</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe src="resources/iframe-stores-entry.html" id="ifr"></iframe> +<script> + let t = async_test('Only expose element attribute for fully active documents'); + window.triggerTest = t.step_func_done(entry => { + assert_not_equals(entry.element, null); + const iframe = document.getElementById('ifr'); + iframe.remove(); + assert_equals(entry.element, null); + }); +</script> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/idlharness.html b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/idlharness.html new file mode 100644 index 0000000..273fef8 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/idlharness.html
@@ -0,0 +1,30 @@ +<!doctype html> +<title>Largest Contentful Paint IDL tests</title> +<link rel="help" href="https://wicg.github.io/largest-contentful-paint/"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/WebIDLParser.js"></script> +<script src="/resources/idlharness.js"></script> +<script> +'use strict'; + +idl_test( + ['largest-contentful-paint'], + ['performance-timeline', 'dom'], + async (idl_array, t) => { + idl_array.add_objects({ + LargestContentfulPaint: ['lcp'] + }); + + window.lcp = await new Promise((resolve, reject) => { + const observer = new PerformanceObserver(entryList => { + resolve(entryList.getEntries()[0]); + }); + observer.observe({type: 'largest-contentful-paint', buffered: true}); + t.step_timeout(() => reject('Timed out waiting for LargestContentfulPaint entry'), 3000); + }); + } +); +</script> +<!-- a contentful element to observe --> +<img src=/images/green-100x50.png>
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html new file mode 100644 index 0000000..abe753f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html
@@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>Largest Contentful Paint: observe image.</title> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + async_test(function (t) { + if (!window.LargestContentfulPaint) { + assert_unreached("LargestContentfulPaint is not implemented"); + } + const beforeRender = performance.now(); + const observer = new PerformanceObserver( + t.step_func_done(function(entryList) { + assert_equals(entryList.getEntries().length, 1); + const entry = entryList.getEntries()[0]; + assert_equals(entry.entryType, 'largest-contentful-paint'); + assert_greater_than_equal(entry.renderTime, beforeRender, + 'The rendering timestamp should occur after script starts running.'); + assert_greater_than_equal(performance.now(), entry.renderTime, + 'The rendering timestamp should occur before the entry is dispatched to the observer.'); + assert_equals(entry.startTime, 0); + assert_equals(entry.duration, 0); + // blue.png is 133 x 106. + assert_equals(entry.size, 14098); + assert_equals(entry.id, 'image_id'); + // 25 is the length of "largest-contentful-paint/". + const index = window.location.href.lastIndexOf('/') - 25; + const pathname = window.location.href.substring(0, index) + '/images/blue.png'; + assert_equals(entry.url, pathname); + assert_greater_than(entry.loadTime, beforeRender, + 'The load timestamp should occur after script starts running.'); + assert_less_than(entry.loadTime, entry.renderTime, + 'The load timestamp should occur before the render timestamp.') + assert_equals(entry.element, document.getElementById('image_id')); + }) + ); + observer.observe({type: 'largest-contentful-paint', buffered: true}); + }, 'Same-origin image after a JS initiated scroll event is observable.'); + document.body.dispatchEvent(new Event('scroll')); + const image = new Image(); + image.id = 'image_id'; + image.src = '/images/blue.png'; + document.body.appendChild(image); +</script> + +</body>
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/resources/iframe-stores-entry.html b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/resources/iframe-stores-entry.html new file mode 100644 index 0000000..cd600254 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/resources/iframe-stores-entry.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html> +<body> +<p>Text</p> +<script> + const observer = new PerformanceObserver(entryList => { + window.parent.triggerTest(entryList.getEntries()[0]); + }); + observer.observe({type: 'largest-contentful-paint', buffered: true}); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-1.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-1.html index 6be38d5..5ecb66e 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-1.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-1.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Verify fraction metrics for different sizes of numerator and denominator."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -33,6 +34,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 3; var mathAxis = getBox("axis").middle; // For stacks, nothing in the OpenType MATH specification seems to ensure @@ -51,6 +54,8 @@ }, "Fraction axis is aligned on the math axis"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + for (var i = 0; i < 10; i++) { assert_less_than(getBox("frac" + i + "num").bottom, getBox("frac" + i + "den").top, "numerator is above denominator"); assert_less_than(getBox("frac" + i + "den").top - getBox("frac" + i + "num").bottom, 5, "The gap between numerator and denominator is not too large"); @@ -58,12 +63,16 @@ }, "Vertical positions of numerator and denominator"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 3; for (var i = 0; i < 10; i++) assert_approx_equals(getBox("frac" + i + "num").center, getBox("frac" + i + "den").center, e, "numerator and denominator are horizontally centered"); }, "Horizontal alignments of numerator and denominator"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 5; for (var i = 0; i < 10; i++) { var frac = getBox("frac" + i);
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-parameters-1.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-parameters-1.html index 55404fa..b8bc4051 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-parameters-1.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-parameters-1.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Element mfrac correctly uses the fraction parameters from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -68,6 +69,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 7000 * emToPx; var v2 = 1000 * emToPx; assert_approx_equals(getBox("ref0001").top - getBox("num0001").bottom, @@ -75,54 +78,72 @@ }, "AxisHeight"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 5000 * emToPx; assert_approx_equals(getBox("den0002").top - getBox("ref0002").bottom, v1, epsilon, "mfrac: denominator gap"); }, "DenominatorDisplayStyleGapMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 6000 * emToPx; assert_approx_equals(getBox("den0003").top - getBox("ref0003").bottom, v1, epsilon, "mfrac: denominator shift"); }, "DenominatorDisplayStyleShiftDown"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 4000 * emToPx; assert_approx_equals(getBox("den0004").top - getBox("ref0004").bottom, v1, epsilon, "mfrac: denominator gap"); }, "DenominatorGapMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 3000 * emToPx; assert_approx_equals(getBox("den0005").top - getBox("ref0005").bottom, v1, epsilon, "mfrac: denominator shift"); }, "DenominatorShiftDown"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 8000 * emToPx; assert_approx_equals(getBox("ref0006").top - getBox("num0006").bottom, v1, epsilon, "mfrac: numerator gap"); }, "NumeratorDisplayStyleGapMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 2000 * emToPx; assert_approx_equals(getBox("ref0007").top - getBox("num0007").bottom, v1, epsilon, "mfrac: numerator shift"); }, "NumeratorDisplayStyleShiftDown"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 9000 * emToPx; assert_approx_equals(getBox("ref0008").top - getBox("num0008").bottom, v1, epsilon, "mfrac: numerator gap"); }, "NumeratorGapMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 11000 * emToPx; assert_approx_equals(getBox("ref0009").top - getBox("num0009").bottom, v1, epsilon, "mfrac: numerator shift"); }, "NumeratorShiftDown"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 10000 * emToPx; assert_approx_equals(getBox("den0010").top - getBox("num0010").bottom, v1, epsilon, "mfrac: rule thickness");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-parameters-2.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-parameters-2.html index 63ab9776..ce2d299 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-parameters-2.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/fractions/frac-parameters-2.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Element mfrac correctly uses the stack parameters from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -56,42 +57,56 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 7000 * emToPx; assert_approx_equals(getBox("ref0001").top - getBox("num0001").bottom, v, epsilon, "mfrac: axis height"); }, "AxisHeight"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 5000 * emToPx; assert_approx_equals(getBox("den0002").top - getBox("ref0002").bottom, v, epsilon, "mfrac: denominator shift"); }, "BottomDisplayStyleShiftDown"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 6000 * emToPx; assert_approx_equals(getBox("den0003").top - getBox("ref0003").bottom, v, epsilon, "mfrac: denominator shift"); }, "BottomShiftDown"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 4000 * emToPx; assert_approx_equals(getBox("den0004").top - getBox("num0004").bottom, v, epsilon, "mfrac: gap"); }, "DisplayStyleGapMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 8000 * emToPx; assert_approx_equals(getBox("den0005").top - getBox("num0005").bottom, v, epsilon, "mfrac: gap"); }, "GapMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 3000 * emToPx; assert_approx_equals(getBox("ref0006").top - getBox("num0006").bottom, v, epsilon, "mfrac: numerator shift"); }, "TopDisplayStyleShiftUp"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 9000 * emToPx; assert_approx_equals(getBox("ref0007").top - getBox("num0007").bottom, v, epsilon, "mfrac: numerator shift");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-baseline.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-baseline.html index 672d90d..1541b2d6 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-baseline.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-baseline.html
@@ -12,6 +12,7 @@ <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#enclose-expression-inside-notation-menclose"> <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#adjust-space-around-content-mpadded"> <meta name="assert" content="Baseline for mrow-like elements is correct."> +<script src="/mathml/support/feature-detection.js"></script> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script type="text/javascript"> @@ -23,6 +24,7 @@ var x = document.getElementById("above" + tag).getBoundingClientRect(); var y = document.getElementById("below" + tag).getBoundingClientRect(); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); assert_equals(x.bottom, y.top); }, "baseline alignment inside " + tag); });
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html index 75587d0..ee40561 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html
@@ -13,6 +13,7 @@ <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#adjust-space-around-content-mpadded"> <link rel="help" href="https://mathml-refresh.github.io/mathml-core/#operator-fence-separator-or-accent-mo"> <meta name="assert" content="Operators can stretch inside mrow-like elements."> +<script src="/mathml/support/feature-detection.js"></script> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <style> @@ -36,6 +37,7 @@ ["Mrow", "Sqrt", "Style", "Error", "Phantom", "Math", "Menclose", "Mpadded"].forEach((tag) => { var mo = document.getElementById("mo" + tag); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); assert_greater_than_equal(mo.getBoundingClientRect().height, 100); }, "operator stretching inside " + tag); });
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/embellished-operator-001.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/embellished-operator-001.html new file mode 100644 index 0000000..78c5069 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/embellished-operator-001.html
@@ -0,0 +1,155 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Embellished operators</title> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#embellished-operators"> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#definition-of-space-like-elements"> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#layout-of-mrow"> +<meta name="assert" content="Verify definition of embellished operators"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> +<style> + /* Default spacing of operator 'X' is 0.2777777777777778em so quite different + from the measured/specified 0em and 1em. */ + math, math * { + font: 25px/1 Ahem; + } + mn { + color: black; + } + .testedElement mo { + color: yellow !important; + } + .testedElement, .testedElement * { + color: blue !important; + background: blue !important; + } +</style> +<script> + function spaceBeforeElement(id) { + var element = document.getElementById(id); + var mnBefore = element.previousElementSibling; + return element.getBoundingClientRect().left - mnBefore.getBoundingClientRect().right; + } + + function spaceBeforeCoreOperator(id) { + var element = document.getElementById(id); + var coreMo = element.getElementsByTagName("mo")[0]; + return coreMo.getBoundingClientRect().left - element.getBoundingClientRect().left; + } + + setup({ explicit_done: true }); + window.addEventListener("load", runTests); + + function runTests() { + var epsilon = 1; + var emToPx = 25; + + ["mrow", "mstyle", "mphantom", "mpadded"].forEach(tag => { + test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); + assert_approx_equals(spaceBeforeElement(`${tag}-op`), 2 * emToPx, epsilon); + assert_approx_equals(spaceBeforeCoreOperator(`${tag}-op`), 0, epsilon); + }, `${tag} (embellished operator)`); + + test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); + assert_approx_equals(spaceBeforeElement(`${tag}-nonop`), 0, epsilon); + assert_approx_equals(spaceBeforeCoreOperator(`${tag}-nonop`), 2 * emToPx, epsilon); + }, `${tag} (not embellished operator)`); + }); + + done(); + } +</script> +</head> +<body> + <div id="log"></div> + <p> + <math> + <mn>X</mn> + <mrow id="mrow-op" class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mtext class="space-like">X</mtext> + </mrow> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mrow id="mrow-nonop" class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> <!-- "mn" is not space-like --> + </mrow> + <mn>X</mn> + </math> + </p> + <!-- mstyle is an embellished operator if its children consist + of one embellished operator and zero or more space-like elements. --> + <p> + <math> + <mn>X</mn> + <mstyle id="mstyle-op" class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + </mstyle> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mstyle id="mstyle-nonop" class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> <!-- "mn" is not space-like --> + </mstyle> + <mn>X</mn> + </math> + </p> + <!-- mphantom is an embellished operator if its children consist + of one embellished operator and zero or more space-like elements. --> + <p> + <math> + <mn>X</mn> + <mphantom id="mphantom-op" class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + </mphantom> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mphantom id="mphantom-nonop" class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> <!-- "mn" is not space-like --> + </mphantom> + <mn>X</mn> + </math> + </p> + <!-- mpadded is an embellished operator if its children consist + of one embellished operator and zero or more space-like elements. --> + <p> + <math> + <mn>X</mn> + <mpadded id="mpadded-op" class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + </mpadded> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mpadded id="mpadded-nonop" class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> <!-- "mn" is not space-like --> + </mpadded> + <mn>X</mn> + </math> + </p> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/embellished-operator-002.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/embellished-operator-002.html new file mode 100644 index 0000000..da343dd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/operators/embellished-operator-002.html
@@ -0,0 +1,286 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Embellished operators</title> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#embellished-operators"> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#definition-of-space-like-elements"> +<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#layout-of-mrow"> +<meta name="assert" content="Verify definition of embellished operators"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> +<style> + /* Default spacing of operator 'X' is 0.2777777777777778em so quite different + from the measured/specified 0em and 1em. */ + math, math * { + font: 25px/1 Ahem; + } + mn { + color: black; + } + mtext.space-like { + color: lightblue !important; + } + .testedElement mo { + color: yellow !important; + } + .testedElement, .testedElement * { + color: blue !important; + background: blue !important; + } +</style> +<script> + function spaceBeforeElement(element) { + var mnBefore = element.previousElementSibling; + return element.getBoundingClientRect().left - mnBefore.getBoundingClientRect().right; + } + + setup({ explicit_done: true }); + window.addEventListener("load", runTests); + + function runTests() { + var epsilon = 1; + var emToPx = 25; + + ["msub", "msup", "msubsup", "munder", "mover", "munderover", + "mmultiscripts", "mfrac", "maction", "semantics"].forEach(tag => { + test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); + var element = document.getElementsByTagName(tag)[0]; + assert_approx_equals(spaceBeforeElement(element), 2 * emToPx, epsilon); + }, `${tag} (embellished operator)`); + + test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); + var element = document.getElementsByTagName(tag)[1]; + assert_approx_equals(spaceBeforeElement(element), 0, epsilon); + }, `${tag} (not embellished operator)`); + }); + done(); + } +</script> +</head> +<body> + <div id="log"></div> + <!-- <msub>, <msup>, <msubsup>, <munder>, <mover>, <munderover>, + <mmultiscripts>, <mfrac>, <semantics> or <maction> are embellished + operators if their first child exists and is an embellished operator --> + <p> + <math> + <mn>X</mn> + <msub class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + </msub> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <msup class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + </msup> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <msubsup class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + <mn>X</mn> + </msubsup> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <munder class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + </munder> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mover class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + </mover> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <munderover class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + </munderover> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mmultiscripts class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + <mn>X</mn> + <mn>X</mn> + <mn>X</mn> + </mmultiscripts> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mfrac class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + </mfrac> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <maction class="testedElement" actiontype="statusline"> + <mo lspace="2em" rspace="0em">X</mo> + <mn>STATUS MESSAGE</mn> + </maction> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <semantics class="testedElement"> + <mo lspace="2em" rspace="0em">X</mo> + <annotation>TEXT ANNOTATION</annotation> + <mn>X</mn> + </semantics> + <mn>X</mn> + </math> + </p> + <!-- <msub>, <msup>, <msubsup>, <munder>, <mover>, <munderover>, + <mmultiscripts>, <mfrac>, <semantics> or <maction> are not embellished + operators if their first child is not an embellished operator --> + <p> + <math> + <mn>X</mn> + <msub class="testedElement"> + <mn>X</mn> + <mo lspace="2em" rspace="0em">X</mo> + </msub> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <msup class="testedElement"> + <mn>X</mn> + <mo lspace="2em" rspace="0em">X</mo> + </msup> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <msubsup class="testedElement"> + <mn>X</mn> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + </msubsup> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <munder class="testedElement"> + <mn>X</mn> + <mo lspace="2em" rspace="0em">X</mo> + </munder> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mover class="testedElement"> + <mn>X</mn> + <mo lspace="2em" rspace="0em">X</mo> + </mover> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <munderover class="testedElement"> + <mn>X</mn> + <mo lspace="2em" rspace="0em">X</mo> + </munderover> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mmultiscripts class="testedElement"> + <mn>X</mn> + <mo lspace="2em" rspace="0em">X</mo> + <mn>X</mn> + <mn>X</mn> + <mn>X</mn> + </mmultiscripts> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <mfrac class="testedElement"> + <mn>X</mn> + <mo lspace="2em" rspace="0em">X</mo> + </mfrac> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <maction class="testedElement" actiontype="statusline"> + <mn>X</mn> + <mo lspace="2em" rspace="0em">STATUS MESSAGE</mo> + </maction> + <mn>X</mn> + </math> + </p> + <p> + <math> + <mn>X</mn> + <semantics class="testedElement"> + <mrow> + <mn>X</mn> + <mo lspace="2em" rspace="0em">X</mo> + </mrow> + <annotation>TEXT ANNOTATION</annotation> + </semantics> + <mn>X</mn> + </math> + </p> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/radicals/root-parameters-1.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/radicals/root-parameters-1.html index 5ad0b73..d09d117 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/radicals/root-parameters-1.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/radicals/root-parameters-1.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Elements msqrt and mroot correctly use the radical parameters from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -56,6 +57,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 25; var v2 = 1000 * emToPx; var radicalHeight = getBox("base001").height + v2; @@ -65,6 +68,8 @@ }, "RadicalDegreeBottomRaisePercent"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 7000 * emToPx; var v2 = 1000 * emToPx; assert_approx_equals(getBox("base0021").top - getBox("radical0021").top, @@ -76,6 +81,8 @@ }, "RadicalDisplayStyleVerticalGap"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 3000 * emToPx; var v2 = 1000 * emToPx; assert_approx_equals(getBox("base0031").top - getBox("radical0031").top, @@ -86,7 +93,9 @@ "mroot: vertical gap"); }, "RadicalExtraAscender"); - test(function() { + test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + // Note: the size variants of U+221A in this font have width 1000. var v1 = 5000 * emToPx; var radicalSymbolWidth = 1000 * emToPx; @@ -97,6 +106,8 @@ }, "RadicalKernAfterDegree"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 4000 * emToPx; assert_approx_equals(getBox("index005").left - getBox("radical005").left, v1, epsilon, @@ -104,6 +115,8 @@ }, "RadicalKernBeforeDegree"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 8000 * emToPx; assert_approx_equals(getBox("base0061").top - getBox("radical0061").top, v, epsilon, @@ -114,6 +127,8 @@ }, "RadicalRuleThickness"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 6000 * emToPx; var v2 = 1000 * emToPx; assert_approx_equals(getBox("base0071").top - getBox("radical0071").top,
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-1.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-1.html index 01a6b0e..e5321d6c 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-1.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-1.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Basic metrics for elements msub, msup and msubsup."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -28,6 +29,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; assert_less_than_equal(getBox("msubBase").right, getBox("msubSub").left, e, "msub: subscript is after base"); assert_less_than_equal(getBox("msupBase").right, getBox("msupSup").left, e, "msup: superscript is after base"); @@ -43,6 +46,8 @@ }, "Respective horizontal positions"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; assert_approx_equals(getBox("msubBase").middle, getBox("baseline").bottom, e, "msub: base is placed on the baseline"); assert_approx_equals(getBox("msupBase").middle, getBox("baseline").bottom, e, "msup: base is placed on the baseline"); @@ -50,6 +55,8 @@ }, "Alignment of the base on the baseline"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 3; assert_approx_equals(getBox("msubSub").middle, getBox("msubBase").bottom, e, "msub: script is placed at the bottom of the base"); assert_approx_equals(getBox("msupSup").middle, getBox("msupBase").top, e, "msup: script is placed at the top of the base"); @@ -58,6 +65,8 @@ }, "Vertical position of scripts"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 3; assert_approx_equals(getBox("msub").width, getBox("msubSub").right - getBox("msubBase").left, e, "msub: width is determined by the left/right sides of base/script (+ some space after script)"); assert_approx_equals(getBox("msup").width, getBox("msupSup").right - getBox("msupBase").left, e, "msup: width is determined by the left/right sides of base/script (+ some space after script)"); @@ -65,6 +74,8 @@ }, "Width of scripted elements"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; assert_greater_than_equal(getBox("msub").height, getBox("msubBase").height, e, "msub: height is at least the one of the base"); assert_greater_than_equal(getBox("msup").height, getBox("msupBase").height, e, "msup: height is at least the one of the base");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-2.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-2.html index 2fd6963..1a5b80d3 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-2.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-2.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Basic metrics for the mmultiscript element."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -28,6 +29,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; assert_less_than_equal(getBox("msubBase").right, getBox("msubSub").left, e, "subscript is after base"); assert_less_than_equal(getBox("msupBase").right, getBox("msupSup").left, e, "superscript is after base"); @@ -54,6 +57,8 @@ }, "Respective horizontal positions"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; assert_approx_equals(getBox("msubBase").middle, getBox("baseline").bottom, e, "base is placed on the baseline"); assert_approx_equals(getBox("msupBase").middle, getBox("baseline").bottom, e, "base is placed on the baseline"); @@ -64,6 +69,8 @@ }, "Alignment of the base on the baseline"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 3; assert_approx_equals(getBox("msubSub").middle, getBox("msubBase").bottom, e, "script is placed at the bottom of the base"); assert_approx_equals(getBox("msupSup").middle, getBox("msupBase").top, e, "script is placed at the top of the base"); @@ -77,6 +84,8 @@ }, "Vertical position of scripts"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 3; assert_approx_equals(getBox("msub").width, getBox("msubSub").right - getBox("msubBase").left, e, "width is determined by the left/right sides of base/script (+ some space after script)"); assert_approx_equals(getBox("msup").width, getBox("msupSup").right - getBox("msupBase").left, e, "width is determined by the left/right sides of base/script (+ some space after script)"); @@ -88,6 +97,8 @@ }, "Width of scripted elements"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; assert_greater_than_equal(getBox("msub").height, getBox("msubBase").height, e, "height is at least the one of the base"); assert_greater_than_equal(getBox("msup").height, getBox("msupBase").height, e, "height is at least the one of the base");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-3.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-3.html index 60df24a..5494bb0c9 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-3.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-3.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Basic metrics for the mmultiscript element with many scripts."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -28,12 +29,16 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; for (var i = 0; i < 5; i++) assert_approx_equals(getBox("multi" + i + "base").middle, getBox("baseline").bottom, e, "base " + i + "is placed on the baseline"); }, "Alignment of the base on the baseline"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 5; assert_approx_equals(getBox("multi0").width, 30, e, "width of multi0"); assert_approx_equals(getBox("multi0").height, 30, e, "height of multi0"); @@ -49,6 +54,8 @@ }, "Dimensions of the scripted elements"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 3; for (var i = 2; i <= 4; i++) { var base = getBox("multi" + i + "base"); @@ -66,6 +73,8 @@ }, "Vertical positions of scripts"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; for (var i = 2; i <= 4; i++) { var base = getBox("multi" + i + "base"); @@ -81,6 +90,8 @@ }, "Horizontal alignment of scripts"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + for (var i = 2; i <= 4; i++) { var base = getBox("multi" + i + "base"); var firstPostScript = getBox("multi" + i + "postsub1");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-4.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-4.html index 68867660..00bd454 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-4.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-4.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Verify metrics of scripted elements for bases of different heights."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -30,6 +31,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; sizeArray.forEach(function(size) { assert_approx_equals(getBox("msub" + size + "base").middle, getBox("baseline").bottom, e, "msub base " + size + "is placed on the baseline"); @@ -40,6 +43,8 @@ }, "Alignment on the baseline for bases of different heights"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 5; sizeArray.forEach(function(size) { assert_approx_equals(getBox("msub" + size + "sub").middle, getBox("msub" + size + "base").bottom, e, "msub script " + size + "is placed at the top of of the base");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-5.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-5.html index 2cc4e6d9..566b0133 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-5.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-5.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Verify metrics of scripted elements with tall scripts."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -30,6 +31,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; assert_approx_equals(getBox("msubbase").middle, getBox("baseline").bottom, e, "msub base is placed on the baseline"); assert_approx_equals(getBox("msupbase").middle, getBox("baseline").bottom, e, "msup base is placed on the baseline"); @@ -38,6 +41,8 @@ }, "Alignment on the baseline with different and large script heights"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + assert_greater_than(getBox("msubsub").top, getBox("msubbase").top, "msub: subscript is below the top of the base"); assert_less_than(getBox("msupsup").bottom, getBox("msupbase").bottom, "msup: supscript is above the bottom of the base"); assert_greater_than(getBox("msubsupsub").top, getBox("msubsupbase").top, "msubsup: subscript is below the top of the base"); @@ -49,6 +54,8 @@ }, "Tall subscripts/superscripts are not placed too high/low"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + assert_greater_than(getBox("msubsupsub").top, getBox("msubsupsup").bottom, "msubsup: subscript is below the superscript"); assert_greater_than(getBox("multipresub").top, getBox("multipresup").bottom, "mmultiscripts: presubscript is below the presuperscript"); assert_greater_than(getBox("multipostsub").top, getBox("multipostsup").bottom, "mmultiscripts: postsubscript is below the postsuperscript");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-1.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-1.html index 7503ad16..a5f21ec5 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-1.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-1.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Elements msub, msup, subsup and msubsup correctly use the subscript and superscript parameters from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -68,6 +69,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 3000 * emToPx; assert_approx_equals(getBox("ref001").left - getBox("sub001").right, v, epsilon, "msub: Space after subscript"); assert_approx_equals(getBox("ref002").left - getBox("sup002").right, v, epsilon, "msup: Space after superscript"); @@ -78,6 +81,8 @@ }, "SpaceAfterScript"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 7000 * emToPx; assert_approx_equals(getBox("ref101").bottom - getBox("sup102").bottom, v, epsilon, "msup: Superscript shift"); assert_approx_equals(getBox("ref101").bottom - getBox("sup103").bottom, v, epsilon, "msubsup: Superscript shift"); @@ -87,6 +92,8 @@ }, "SuperscriptShiftUp"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 5000 * emToPx; assert_approx_equals(getBox("ref201").bottom - getBox("sup202").bottom, v, epsilon, "msup: Superscript shift"); assert_approx_equals(getBox("ref201").bottom - getBox("sup203").bottom, v, epsilon, "msubsup: Superscript shift"); @@ -96,6 +103,8 @@ }, "SuperscriptShiftUpCramped"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 6000 * emToPx; assert_approx_equals(getBox("sub301").bottom - getBox("ref300").bottom, v, epsilon, "msup: Subscript shift"); assert_approx_equals(getBox("sub302").bottom - getBox("ref300").bottom, v, epsilon, "msubsup: Subscript shift"); @@ -104,12 +113,16 @@ }, "SubscriptShiftDown"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 11000 * emToPx; assert_approx_equals(getBox("sub4011").top - getBox("sup4012").bottom, v, epsilon, "msubsup: SubSuperscript gap"); assert_approx_equals(getBox("sub4021").top - getBox("sup4022").bottom, v, epsilon, "mmultiscripts: SubSuperscript gap"); }, "SubSuperscriptGapMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 11000 * emToPx; var v2 = 3000 * emToPx; assert_approx_equals(getBox("sub501").top - getBox("sup501").bottom, v1, epsilon, "msubsup: SubSuperscript gap"); @@ -119,21 +132,29 @@ }, "SuperscriptBottomMaxWithSubscript"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 4000 * emToPx; assert_approx_equals(getBox("ref600").bottom - getBox("sub601").top, v, epsilon, "msub: Subscript top"); }, "SubscriptTopMax"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 8000 * emToPx; assert_approx_equals(getBox("ref700").bottom - getBox("sub701").bottom, v, epsilon, "msub: Superscript bottom"); }, "SuperscriptBottomMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 9000 * emToPx; assert_approx_equals(getBox("sub801").bottom - getBox("base801").bottom, v, epsilon, "msub: Superscript drop"); }, "SubscriptBaselineDrop"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 10000 * emToPx; assert_approx_equals(getBox("sup901").bottom - getBox("base901").top, v, epsilon, "msup: Superscript drop"); }, "SuperscriptBaselineDrop");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-2.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-2.html index 62aa7a9d..0abf0183 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-2.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/subsup-parameters-2.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Elements msub, msup, subsup and msubsup correctly use the italic correction from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -42,6 +43,8 @@ var epsilon = 1; function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 0; assert_approx_equals(getBox("base001").right - getBox("sub001").left, v, epsilon, "msub"); assert_approx_equals(getBox("sup002").left, getBox("base002").right, epsilon, "msup"); @@ -50,6 +53,8 @@ assert_approx_equals(getBox("sup005").left - getBox("sub005").left, 0, epsilon, "mmultiscripts prescripts"); }, "Null Italic Correction"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var emToPx = 10 / 1000; // font-size: 10px, font.em = 1000 var v = 3000 * emToPx; assert_approx_equals(getBox("base011").right - getBox("sub011").left, v, epsilon, "msub");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-1.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-1.html index b178355..5b71870 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-1.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-1.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Elements munder, mover, munderover correctly ."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace, mo { font-size: 10px; @@ -29,6 +30,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; for (var i = 0; i <= 3; i++) { assert_approx_equals(getBox("under" + i + "base").middle, getBox("baseline").bottom, e, "munder " + i + ": base is placed on the baseline"); @@ -40,6 +43,8 @@ }, "Alignment of the base on the baseline"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; for (var i = 0; i <= 3; i++) { assert_approx_equals(getBox("under" + i + "under").center, getBox("under" + i + "base").center, e, "munder " + i + ": base and script are horizontally centered"); @@ -52,6 +57,8 @@ }, "Horizontal alignments of base and scripts"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + for (var i = 0; i <= 3; i++) { assert_greater_than_equal(getBox("under" + i + "under").top, getBox("under" + i + "base").bottom, "munder " + i + ": script is under base"); assert_less_than_equal(getBox("over" + i + "over").bottom, getBox("over" + i + "base").top, "mover " + i + ": script is over base"); @@ -63,6 +70,8 @@ }, "Relative vertical positions of base and scripts"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 1; for (var i = 0; i <= 3; i++) { assert_approx_equals(getBox("under" + i).width, Math.max(getBox("under" + i + "base").width, getBox("under" + i + "under").width), e, "munder " + i + ": width is determined by the maximum of width of base and script"); @@ -74,6 +83,8 @@ }, "Width of scripted elements"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var e = 3.2; for (var i = 0; i <= 3; i++) { assert_approx_equals(getBox("under" + i).height, getBox("under" + i + "base").height + getBox("under" + i + "under").height + e, e, "munder " + i + ": height is determined by the sum of heights of base and script plus some spacing.");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-1.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-1.html index d8a564a..26a1b39 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-1.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-1.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Elements munder, mover, munderover correctly use the limit parameters from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace, mo { font-size: 10px; @@ -44,6 +45,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 3000 * emToPx; assert_approx_equals(getBox("under00011").top - getBox("ref0001").bottom, v, epsilon, "munder: under shift"); @@ -52,6 +55,8 @@ }, "LowerLimitBaselineDropMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 11000 * emToPx; assert_approx_equals(getBox("under00021").top - getBox("ref0002").bottom, v, epsilon, "munder: under gap"); @@ -60,6 +65,8 @@ }, "LowerLimitGapMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 5000 * emToPx; assert_approx_equals(getBox("ref0003").top - getBox("over00031").bottom, v, epsilon, "mover: over shift"); @@ -68,6 +75,8 @@ }, "UpperLimitBaselineRiseMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 7000 * emToPx; assert_approx_equals(getBox("ref0004").top - getBox("over00041").bottom, v, epsilon, "mover: over shift");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-2.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-2.html index c10f77e..aed22235 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-2.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-2.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Elements munder, mover, munderover correctly use the stretch stack parameters from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace, mo { font-size: 10px; @@ -44,6 +45,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 3000 * emToPx; assert_approx_equals(getBox("under00011").top - getBox("ref0001").bottom, v, epsilon, "munder: under shift"); @@ -52,6 +55,8 @@ }, "StretchStackBottomShiftDown"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 11000 * emToPx; assert_approx_equals(getBox("under00021").top - getBox("ref0002").bottom, v, epsilon, "munder: under gap"); @@ -60,6 +65,8 @@ }, "StretchStackGapBelowMin"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 5000 * emToPx; assert_approx_equals(getBox("ref0003").top - getBox("over00031").bottom, v, epsilon, "mover: over shift"); @@ -68,6 +75,8 @@ }, "StretchStackTopShiftUp"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 7000 * emToPx; assert_approx_equals(getBox("ref0004").top - getBox("over00041").bottom, v, epsilon, "mover: over shift");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-3.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-3.html index 86562fd..6a1e51c 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-3.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-3.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Elements munder, mover, munderover correctly use underbar/overbar and AccentBaseHeight parameters from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace, mo { font-size: 10px; @@ -47,6 +48,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + for (var i = 1; i <= 4; i++) { for (var j = 1; j <= 6; j++) { var baseId = ("base00" + i) + j; @@ -59,6 +62,8 @@ }, "Baseline alignment"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + for (var i = 1; i <= 4; i++) { for (var j = 1; j <= 6; j++) { var baseId = ("base00" + i) + j; @@ -72,6 +77,8 @@ }, "Heights of bases"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 5000 * emToPx; assert_approx_equals(getBox("ref001").bottom - getBox("over0014").bottom, shortBaseHeight, epsilon, @@ -96,6 +103,8 @@ }, "AccentBaseHeight, UnderbarExtraDescender"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 7000 * emToPx; assert_approx_equals(getBox("ref002").bottom - getBox("over0024").bottom, shortBaseHeight, epsilon, @@ -118,6 +127,8 @@ }, "AccentBaseHeight, UnderbarVerticalGap"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 3000 * emToPx; assert_approx_equals(getBox("ref003").bottom - getBox("over0031").bottom, shortBaseHeight, epsilon, @@ -154,6 +165,8 @@ }, "AccentBaseHeight, OverbarExtraAscender"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + v = 11000 * emToPx; assert_approx_equals(getBox("ref004").bottom - getBox("over0041").bottom, shortBaseHeight + v, epsilon,
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-4.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-4.html index f7fb389..e569c15 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-4.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/scripts/underover-parameters-4.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Elements munder, mover, munderover correctly use underbar/overbar and AccentBaseHeight parameters from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace, mo { font-size: 10px; @@ -47,6 +48,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + for (var i = 1; i <= 4; i++) { for (var j = 1; j <= 6; j++) { var baseId = ("base00" + i) + j; @@ -59,6 +62,8 @@ }, "Baseline alignment"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + for (var i = 1; i <= 4; i++) { for (var j = 1; j <= 6; j++) { var baseId = ("base00" + i) + j; @@ -72,6 +77,8 @@ }, "Heights of bases"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 5000 * emToPx; assert_approx_equals(getBox("ref001").bottom - getBox("over0014").bottom, shortBaseHeight, epsilon, @@ -96,6 +103,8 @@ }, "AccentBaseHeight, UnderbarExtraDescender"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 7000 * emToPx; assert_approx_equals(getBox("ref002").bottom - getBox("over0024").bottom, shortBaseHeight, epsilon, @@ -118,6 +127,8 @@ }, "AccentBaseHeight, UnderbarVerticalGap"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v = 3000 * emToPx; assert_approx_equals(getBox("ref003").bottom - getBox("over0031").bottom, shortBaseHeight, epsilon, @@ -154,6 +165,8 @@ }, "AccentBaseHeight, OverbarExtraAscender"); test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + v = 11000 * emToPx; assert_approx_equals(getBox("ref004").bottom - getBox("over0041").bottom, shortBaseHeight + v, epsilon,
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-001.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-001.html index d2db456..61375bcd 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-001.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-001.html
@@ -10,6 +10,7 @@ <meta name="assert" content="Verify definition of space-like elements"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> /* Default spacing of operator 'X' is 0.2777777777777778em so quite different from the measured/specified 0em and 1em. */ @@ -48,51 +49,61 @@ var emToPx = 25; test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mtext"), emToPx, epsilon); assert_approx_equals(spaceAfter("mtext"), emToPx, epsilon); }, "mtext is space-like"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mspace"), emToPx, epsilon); assert_approx_equals(spaceAfter("mspace"), emToPx, epsilon); }, "mspace is space-like"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mrow1"), emToPx, epsilon); assert_approx_equals(spaceAfter("mrow1"), emToPx, epsilon); }, "space-like mrow"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mrow2"), 0, epsilon); assert_approx_equals(spaceAfter("mrow2"), 2 * emToPx, epsilon); }, "non-space-like mrow"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mstyle1"), emToPx, epsilon); assert_approx_equals(spaceAfter("mstyle1"), emToPx, epsilon); }, "space-like mstyle"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mstyle2"), 0, epsilon); assert_approx_equals(spaceAfter("mstyle2"), 2 * emToPx, epsilon); }, "non-space-like mstyle"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mphantom1"), emToPx, epsilon); assert_approx_equals(spaceAfter("mphantom1"), emToPx, epsilon); }, "space-like mphantom"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mphantom2"), 0, epsilon); assert_approx_equals(spaceAfter("mphantom2"), 2 * emToPx, epsilon); }, "non-space-like mphantom"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mpadded1"), emToPx, epsilon); assert_approx_equals(spaceAfter("mpadded1"), emToPx, epsilon); }, "space-like mpadded"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("mpadded2"), 0, epsilon); assert_approx_equals(spaceAfter("mpadded2"), 2 * emToPx, epsilon); }, "non-space-like mpadded");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-002.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-002.html index 78f4c92..f5f4e5a8 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-002.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-002.html
@@ -10,6 +10,7 @@ <meta name="assert" content="Verify definition of space-like elements"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> /* Default spacing of operator 'X' is 0.2777777777777778em so quite different from the measured/specified 0em and 1em. */ @@ -48,31 +49,37 @@ var emToPx = 25; test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("maction1"), emToPx, epsilon); assert_approx_equals(spaceAfter("maction1"), emToPx, epsilon); }, "space-like maction"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("maction2"), 0, epsilon); assert_approx_equals(spaceAfter("maction2"), 2 * emToPx, epsilon); }, "non-space like maction (no first child)"); test(function() { assert_approx_equals(spaceBefore("maction3"), 0, epsilon); + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceAfter("maction3"), 2 * emToPx, epsilon); }, "non-space like maction (first child not space-like)"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("semantics1"), emToPx, epsilon); assert_approx_equals(spaceAfter("semantics1"), emToPx, epsilon); }, "space-like semantics"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("semantics2"), 0, epsilon); assert_approx_equals(spaceAfter("semantics2"), 2 * emToPx, epsilon); }, "non-space like semantics (no first child)"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("semantics3"), 0, epsilon); assert_approx_equals(spaceAfter("semantics3"), 2 * emToPx, epsilon); }, "non-space like semantics (first child not space-like)");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-003.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-003.html index 8831657a..6d3d007 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-003.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-003.html
@@ -10,6 +10,7 @@ <meta name="assert" content="Verify definition of space-like elements"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> /* Default spacing of operator 'X' is 0.2777777777777778em so quite different from the measured/specified 0em and 1em. */ @@ -47,6 +48,7 @@ Array.from(document.querySelectorAll(".testedElement")).forEach(el => { test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore(el), 0, epsilon); assert_approx_equals(spaceAfter(el), 2 * emToPx, epsilon); }, `${el.tagName} is not space-like`);
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-004.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-004.html index 28a2871b..091a3ea0 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-004.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/spaces/space-like-004.html
@@ -10,6 +10,7 @@ <meta name="assert" content="Verify definition of space-like elements"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> /* Default spacing of operator 'X' is 0.2777777777777778em so quite different from the measured/specified 0em and 1em. */ @@ -48,11 +49,13 @@ var emToPx = 25; test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("complex1"), emToPx, epsilon); assert_approx_equals(spaceAfter("complex1"), emToPx, epsilon); }, "complex space-like subtree"); test(function() { + assert_true(MathMLFeatureDetection.has_operator_spacing()); assert_approx_equals(spaceBefore("complex2"), 0, epsilon); assert_approx_equals(spaceAfter("complex2"), 2 * emToPx, epsilon); }, "complex non-space-like subtree");
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/tables/table-axis-height.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/tables/table-axis-height.html index feb2907..3eaf9c8f 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/tables/table-axis-height.html +++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/tables/table-axis-height.html
@@ -7,6 +7,7 @@ <meta name="assert" content="Element mtable correctly uses the axis height parameter from the MATH table."> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> +<script src="/mathml/support/feature-detection.js"></script> <style> math, mspace { font-size: 10px; @@ -32,6 +33,8 @@ function runTests() { test(function() { + assert_true(MathMLFeatureDetection.has_mspace()); + var v1 = 5000 * emToPx; var tableMiddle = (getBox("table").bottom + getBox("table").top) / 2; assert_approx_equals(getBox("baseline").bottom - tableMiddle,
diff --git a/third_party/blink/web_tests/external/wpt/mathml/support/feature-detection.js b/third_party/blink/web_tests/external/wpt/mathml/support/feature-detection.js new file mode 100644 index 0000000..5beb78c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/mathml/support/feature-detection.js
@@ -0,0 +1,31 @@ +// This is a helper for MathML feature detection. +// It is indented to be used to prevent false negative test results. + +var MathMLFeatureDetection = { + has_mspace: function() { + if (!this.hasOwnProperty("_has_mspace")) { + document.body.insertAdjacentHTML("beforeend", "<math><mspace></mspace><mspace width='20px'></mspace></math>"); + var math = document.body.lastElementChild; + // The width attribute will add 20px per MathML and none if not supported. + this._has_mspace = + math.lastChild.getBoundingClientRect().width - + math.firstChild.getBoundingClientRect().width > 10; + document.body.removeChild(math); + } + return this._has_mspace; + }, + + has_operator_spacing: function() { + if (!this.hasOwnProperty("_has_operator_spacing")) { + document.body.insertAdjacentHTML("beforeend", "<math><mrow><mn>1</mn><mo lspace='0px' rspace='0px'>+</mo><mn>2</mn><mo lspace='8px' rspace='8px'>+</mo><mn>3</mn></mspace></mrow></math>"); + var math = document.body.lastElementChild; + var mo = math.getElementsByTagName("mo"); + // lspace/rspace will add 16px per MathML and none if not supported. + this._has_operator_spacing = + mo[1].getBoundingClientRect().width - + mo[0].getBoundingClientRect().width > 10; + document.body.removeChild(math); + } + return this._has_operator_spacing; + } +};
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/generic/tools/generate.py b/third_party/blink/web_tests/external/wpt/mixed-content/generic/tools/generate.py index fe4305c4..ed978bc 100755 --- a/third_party/blink/web_tests/external/wpt/mixed-content/generic/tools/generate.py +++ b/third_party/blink/web_tests/external/wpt/mixed-content/generic/tools/generate.py
@@ -3,62 +3,69 @@ import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', 'common', 'security-features', 'tools')) +sys.path.insert( + 0, + os.path.join( + os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', 'common', + 'security-features', 'tools')) import generate class MixedContentConfig(object): - def __init__(self): - self.selection_pattern = '%(subresource)s/' + \ - '%(opt_in_method)s/' + \ - '%(origin)s/' + \ - '%(context_nesting)s/' + \ - '%(redirection)s/' + def __init__(self): + self.selection_pattern = '%(subresource)s/' + \ + '%(delivery_type)s/' + \ + '%(delivery_value)s/' + \ + '%(origin)s/' + \ + 'top-level/' + \ + '%(redirection)s/' - self.test_file_path_pattern = self.selection_pattern + \ - '%(spec_name)s/' + \ - '%(name)s.%(source_scheme)s.html' + self.test_file_path_pattern = self.selection_pattern + \ + '%(spec_name)s/' + \ + '%(name)s.%(source_scheme)s.html' - self.test_description_template = '''opt_in_method: %(opt_in_method)s + self.test_description_template = '''delivery_type: %(delivery_type)s +delivery_value: %(delivery_value)s origin: %(origin)s source_scheme: %(source_scheme)s -context_nesting: %(context_nesting)s +context_nesting: top-level redirection: %(redirection)s subresource: %(subresource)s expectation: %(expectation)s ''' - self.test_page_title_template = 'Mixed-Content: %s' + self.test_page_title_template = 'Mixed-Content: %s' - self.helper_js = '/mixed-content/generic/mixed-content-test-case.js?pipe=sub' + self.helper_js = '/mixed-content/generic/mixed-content-test-case.js?pipe=sub' - # For debug target only. - self.sanity_checker_js = '/mixed-content/generic/sanity-checker.js' - self.spec_json_js = '/mixed-content/spec_json.js' + # For debug target only. + self.sanity_checker_js = '/mixed-content/generic/sanity-checker.js' + self.spec_json_js = '/mixed-content/spec_json.js' - self.test_case_name = 'MixedContentTestCase' + self.test_case_name = 'MixedContentTestCase' - script_directory = os.path.dirname(os.path.abspath(__file__)) - self.spec_directory = os.path.abspath(os.path.join(script_directory, '..', '..')) + script_directory = os.path.dirname(os.path.abspath(__file__)) + self.spec_directory = os.path.abspath( + os.path.join(script_directory, '..', '..')) - def handleDelivery(self, selection, spec): - opt_in_method = selection['opt_in_method'] + def handleDelivery(self, selection, spec): + delivery_type = selection['delivery_type'] + delivery_value = selection['delivery_value'] - meta = '' - headers = [] + meta = '' + headers = [] - # TODO(kristijanburnik): Implement the opt-in-method here. - if opt_in_method == 'meta-csp': - meta = '<meta http-equiv="Content-Security-Policy" ' + \ - 'content="block-all-mixed-content">' - elif opt_in_method == 'http-csp': - headers.append("Content-Security-Policy: block-all-mixed-content") - elif opt_in_method == 'no-opt-in': - pass - else: - raise ValueError("Invalid opt_in_method %s" % opt_in_method) + if delivery_value is not None: + if delivery_type == 'meta': + meta = '<meta http-equiv="Content-Security-Policy" ' + \ + 'content="block-all-mixed-content">' + elif delivery_type == 'http-rp': + headers.append( + "Content-Security-Policy: block-all-mixed-content") + else: + raise ValueError("Invalid delivery_type %s" % delivery_type) - return {"meta": meta, "headers": headers} + return {"meta": meta, "headers": headers} if __name__ == '__main__':
diff --git a/third_party/blink/web_tests/external/wpt/mixed-content/spec.src.json b/third_party/blink/web_tests/external/wpt/mixed-content/spec.src.json index 06d381d..95dc2d3 100644 --- a/third_party/blink/web_tests/external/wpt/mixed-content/spec.src.json +++ b/third_party/blink/web_tests/external/wpt/mixed-content/spec.src.json
@@ -10,28 +10,34 @@ "name": "opt-in-blocks", "expansion": "default", "source_scheme": "https", - "opt_in_method": ["http-csp", "meta-csp"], - "context_nesting": "top-level", + "delivery_type": "*", + "delivery_value": "opt-in", "redirection": "*", "subresource": { "blockable": [], "optionally-blockable": "*" }, - "origin": ["cross-origin-http", "same-host-http"], + "origin": [ + "cross-http", + "same-http" + ], "expectation": "blocked" }, { "name": "no-opt-in-allows", "expansion": "default", "source_scheme": "https", - "opt_in_method": "no-opt-in", - "context_nesting": "top-level", + "delivery_type": "*", + "delivery_value": null, "redirection": "*", "subresource": { "blockable": [], "optionally-blockable": "*" }, - "origin": ["cross-origin-http", "same-host-http"], + "origin": [ + "cross-http", + "same-http" + ], "expectation": "allowed" } ] @@ -46,42 +52,51 @@ "name": "opt-in-blocks", "expansion": "default", "source_scheme": "https", - "opt_in_method": ["http-csp", "meta-csp"], - "context_nesting": "top-level", + "delivery_type": "*", + "delivery_value": "opt-in", "redirection": "*", "subresource": { "blockable": "*", "optionally-blockable": [] }, - "origin": ["cross-origin-http", "same-host-http"], + "origin": [ + "cross-http", + "same-http" + ], "expectation": "blocked" }, { "name": "no-opt-in-blocks", "expansion": "default", "source_scheme": "https", - "opt_in_method": "no-opt-in", - "context_nesting": "top-level", + "delivery_type": "*", + "delivery_value": null, "redirection": "*", "subresource": { "blockable": "*", "optionally-blockable": [] }, - "origin": ["cross-origin-http", "same-host-http"], + "origin": [ + "cross-http", + "same-http" + ], "expectation": "blocked" }, { "name": "ws-downgrade-blocks", "expansion": "default", "source_scheme": "https", - "opt_in_method": ["no-opt-in", "http-csp", "meta-csp"], - "context_nesting": "top-level", + "delivery_type": "*", + "delivery_value": "*", "redirection": "*", "subresource": { "blockable": "websocket-request", "optionally-blockable": [] }, - "origin": ["cross-origin-ws", "same-host-ws"], + "origin": [ + "cross-ws", + "same-ws" + ], "expectation": "blocked" } ] @@ -96,41 +111,65 @@ "name": "allowed", "expansion": "default", "source_scheme": "https", - "opt_in_method": "*", - "context_nesting": "top-level", - "redirection": ["no-redirect", "keep-scheme-redirect"], + "delivery_type": "*", + "delivery_value": "*", + "redirection": [ + "no-redirect", + "keep-scheme" + ], "subresource": { "blockable": "*", "optionally-blockable": "*" }, - "origin": ["same-host-https"], + "origin": [ + "same-https" + ], "expectation": "allowed" }, { "name": "websocket-allowed", "expansion": "default", "source_scheme": "https", - "opt_in_method": "*", - "context_nesting": "top-level", - "redirection": ["no-redirect", "keep-scheme-redirect"], + "delivery_type": "*", + "delivery_value": "*", + "redirection": [ + "no-redirect", + "keep-scheme" + ], "subresource": { "blockable": "websocket-request", "optionally-blockable": [] }, - "origin": ["same-host-wss"], + "origin": [ + "same-wss" + ], "expectation": "allowed" } ] } ], - + "delivery_key": "mixedContent", "excluded_tests": [ { + "name": "Skip-redundant-no-opt-in", + "expansion": "*", + "source_scheme": "*", + "delivery_type": "http-rp", + "delivery_value": null, + "redirection": "*", + "subresource": { + "blockable": "*", + "optionally-blockable": "*" + }, + "origin": "*", + "expectation": "*" + }, + { "name": "Redundant-subresources", "expansion": "*", "source_scheme": "*", - "opt_in_method": "*", - "context_nesting": "*", + "delivery_type": "*", + "delivery_value": "*", "redirection": "*", "subresource": { "blockable": [ @@ -145,8 +184,8 @@ "name": "Skip-origins-not-applicable-to-websockets", "expansion": "*", "source_scheme": "*", - "opt_in_method": "*", - "context_nesting": "*", + "delivery_type": "*", + "delivery_value": "*", "redirection": "*", "subresource": { "blockable": [ @@ -155,37 +194,23 @@ "optionally-blockable": [] }, "origin": [ - "same-host-https", - "same-host-http", - "cross-origin-https", - "cross-origin-http" + "same-https", + "same-http", + "cross-https", + "cross-http" ], "expectation": "*" }, { - "name": "TODO-opt-in-method-img-cross-origin", - "expansion": "*", - "source_scheme": "*", - "opt_in_method": "img-crossorigin", - "context_nesting": "*", - "redirection": "*", - "subresource": { - "blockable": "*", - "optionally-blockable": "*" - }, - "origin": "*", - "expectation": "*" - }, - { "name": "Skip-redundant-for-opt-in-method", "expansion": "*", "source_scheme": "*", - "opt_in_method": [ - "meta-csp", - "img-crossorigin" + "delivery_type": "meta", + "delivery_value": "opt-in", + "redirection": [ + "keep-scheme", + "swap-scheme" ], - "context_nesting": "*", - "redirection": ["keep-scheme-redirect", "swap-scheme-redirect"], "subresource": { "blockable": "*", "optionally-blockable": "*" @@ -194,7 +219,6 @@ "expectation": "*" } ], - "test_expansion_schema": { "expansion": [ "default", @@ -204,30 +228,28 @@ "http", "https" ], - "opt_in_method": [ - "no-opt-in", - "http-csp", - "meta-csp", - "img-crossorigin" + "delivery_type": [ + "http-rp", + "meta" + ], + "delivery_value": [ + null, + "opt-in" ], "redirection": [ "no-redirect", - "keep-scheme-redirect", - "swap-scheme-redirect" - ], - "context_nesting": [ - "top-level", - "sub-level" + "keep-scheme", + "swap-scheme" ], "origin": [ - "same-host-https", - "same-host-http", - "cross-origin-https", - "cross-origin-http", - "same-host-wss", - "same-host-ws", - "cross-origin-wss", - "cross-origin-ws" + "same-https", + "same-http", + "cross-https", + "cross-http", + "same-wss", + "same-ws", + "cross-wss", + "cross-ws" ], "subresource": { "blockable": [
diff --git a/third_party/blink/web_tests/external/wpt/native-file-system/NativeFileSystemWritableFileStream.tentative.https.window.js b/third_party/blink/web_tests/external/wpt/native-file-system/NativeFileSystemWritableFileStream.tentative.https.window.js deleted file mode 100644 index 1dbcb2b..0000000 --- a/third_party/blink/web_tests/external/wpt/native-file-system/NativeFileSystemWritableFileStream.tentative.https.window.js +++ /dev/null
@@ -1,126 +0,0 @@ -// META: script=resources/test-helpers.js -promise_test(async t => cleanupSandboxedFileSystem(), - 'Cleanup to setup test environment'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'empty_blob'); - const stream = await handle.createWritable(); - - await stream.write(0, new Blob([])); - - assert_equals(await getFileContents(handle), ''); - assert_equals(await getFileSize(handle), 0); -}, 'write() with an empty blob to an empty file'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'valid_blob'); - const stream = await handle.createWritable(); - - await stream.write(0, new Blob(['1234567890'])); - - assert_equals(await getFileContents(handle), '1234567890'); - assert_equals(await getFileSize(handle), 10); -}, 'write() a blob to an empty file'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'blob_with_offset'); - const stream = await handle.createWritable(); - - await stream.write(0, new Blob(['1234567890'])); - await stream.write(4, new Blob(['abc'])); - - assert_equals(await getFileContents(handle), '1234abc890'); - assert_equals(await getFileSize(handle), 10); -}, 'write() called with a blob and a valid offset'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'bad_offset'); - const stream = await handle.createWritable(); - - await promise_rejects(t, 'InvalidStateError', stream.write(4, new Blob(['abc']))); - - assert_equals(await getFileContents(handle), ''); - assert_equals(await getFileSize(handle), 0); -}, 'write() called with an invalid offset'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'empty_string'); - const stream = await handle.createWritable(); - - await stream.write(0, ''); - assert_equals(await getFileContents(handle), ''); - assert_equals(await getFileSize(handle), 0); -}, 'write() with an empty string to an empty file'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'valid_utf8_string'); - const stream = await handle.createWritable(); - - await stream.write(0, 'foo🤘'); - assert_equals(await getFileContents(handle), 'foo🤘'); - assert_equals(await getFileSize(handle), 7); -}, 'write() with a valid utf-8 string'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'string_with_unix_line_ending'); - const stream = await handle.createWritable(); - - await stream.write(0, 'foo\n'); - assert_equals(await getFileContents(handle), 'foo\n'); - assert_equals(await getFileSize(handle), 4); -}, 'write() with a string with unix line ending preserved'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'string_with_windows_line_ending'); - const stream = await handle.createWritable(); - - await stream.write(0, 'foo\r\n'); - assert_equals(await getFileContents(handle), 'foo\r\n'); - assert_equals(await getFileSize(handle), 5); -}, 'write() with a string with windows line ending preserved'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'empty_array_buffer'); - const stream = await handle.createWritable(); - - let buf = new ArrayBuffer(0); - await stream.write(0, buf); - assert_equals(await getFileContents(handle), ''); - assert_equals(await getFileSize(handle), 0); -}, 'write() with an empty array buffer to an empty file'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'valid_string_typed_byte_array'); - const stream = await handle.createWritable(); - - let buf = new ArrayBuffer(3); - let intView = new Uint8Array(buf); - intView[0] = 0x66; - intView[1] = 0x6f; - intView[2] = 0x6f; - await stream.write(0, buf); - assert_equals(await getFileContents(handle), 'foo'); - assert_equals(await getFileSize(handle), 3); -}, 'write() with a valid typed array buffer'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'trunc_shrink'); - const stream = await handle.createWritable(); - - await stream.write(0, new Blob(['1234567890'])); - await stream.truncate(5); - - assert_equals(await getFileContents(handle), '12345'); - assert_equals(await getFileSize(handle), 5); -}, 'truncate() to shrink a file'); - -promise_test(async t => { - const handle = await createEmptyFile(t, 'trunc_grow'); - const stream = await handle.createWritable(); - - await stream.write(0, new Blob(['abc'])); - await stream.truncate(5); - - assert_equals(await getFileContents(handle), 'abc\0\0'); - assert_equals(await getFileSize(handle), 5); -}, 'truncate() to grow a file');
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_pointermove_in_pointerlock.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_pointermove_in_pointerlock.html index 9d859f3a..b2251d6 100644 --- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_pointermove_in_pointerlock.html +++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_pointermove_in_pointerlock.html
@@ -34,58 +34,54 @@ var target1 = innerframe.contentDocument.getElementById('target1'); innerframe.contentWindow.name = "innerframe"; + on_event(document, "pointerlockchange", function(event) { + if (document.pointerLockElement == target0) { + on_event(target0, "pointermove", function (event) { + test_pointermove.step(function() { + assert_equals(event.view.name, "outerframe", "View attribute of pointermove should be the target frame."); + }, "View attribute of pointermove should be the target frame."); + document.exitPointerLock(); + + on_event(target1, "click", function(event) { + target1.requestPointerLock(); + }); + + on_event(innerframe.contentDocument, "pointerlockchange", function(event) { + if (innerframe.contentDocument.pointerLockElement == target1) { + on_event(target1, "pointermove", function (event) { + innerframe_pointermoveReceived = true; + test_pointermove.step(function() { + assert_equals(event.view.name, "innerframe", "View attribute of pointermove should be the target frame."); + }, "View attribute of pointermove should be the target frame."); + innerframe.contentDocument.exitPointerLock(); + test_pointermove.done(); + }); + } + }); + }); + } + }); + on_event(target0, "click", function(event) { target0.requestPointerLock(); }); - on_event(target1, "click", function(event) { - target1.requestPointerLock(); - }); + var x = innerframe.getBoundingClientRect().x + target1.getBoundingClientRect().x; + var y = innerframe.getBoundingClientRect().y + target1.getBoundingClientRect().y; + // Inject mouse input + new test_driver.Actions() + .pointerMove(5, 5, {origin: target0}) + .pointerDown() + .pointerUp() + .pointerMove(100, 300, {origin: target0}) + .pointerMove(x+10, y+10) + .pointerDown() + .pointerUp() + .pointerMove(5, 5, {origin: target0}) + .send(); - on_event(target0, "pointermove", function (event) { - if (document.pointerLockElement == target0) { - test_pointermove.step(function() { - assert_equals(event.view.name, "outerframe", "View attribute of pointermove should be the target frame."); - }, "View attribute of pointermove should be the target frame."); - document.exitPointerLock(); - // Click the inner frame target to lock. - clickInTarget("mouse", target1); - } - }); - - on_event(target1, "pointermove", function (event) { - if (innerframe.contentDocument.pointerLockElement == target1) { - test_pointermove.step(function() { - assert_equals(event.view.name, "innerframe", "View attribute of pointermove should be the target frame."); - }, "View attribute of pointermove should be the target frame."); - innerframe.contentDocument.exitPointerLock(); - test_pointermove.done(); - } - }); - - on_event(document, "pointerlockchange", function(event) { - if (document.pointerLockElement == target0) { - // Send moves in main frame target - new test_driver.Actions() - .pointerMove(10, 30, {origin: target0}) - .pointerMove(20, 10, {origin: target0}) - .send(); - } - }); - - on_event(innerframe.contentDocument, "pointerlockchange", function(event) { - if (innerframe.contentDocument.pointerLockElement == target1) { - // Send moves in inner frame target - new test_driver.Actions() - .pointerMove(10, 30, {origin: target1}) - .pointerMove(20, 10, {origin: target1}) - .send(); - } - }); - - // Click the outer frame target to lock. - clickInTarget("mouse", target0); } + </script> <div id="complete-notice"> </div>
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/README.md b/third_party/blink/web_tests/external/wpt/referrer-policy/README.md index 303362d..498f7f2 100644 --- a/third_party/blink/web_tests/external/wpt/referrer-policy/README.md +++ b/third_party/blink/web_tests/external/wpt/referrer-policy/README.md
@@ -30,6 +30,8 @@ The spec can be validated by running ```./generic/tools/spec_validator.py```. This is specially important when you're making changes to ```spec.src.json```. Make sure it's a valid JSON (no comments or trailing commas). The validator should be informative and very specific on any issues. +The ```spec.src.json``` file can be formatted by running ```../common/security-features/tools/format_spec_src_json.py```. + For details about the spec JSON, see **Overview of the spec JSON** below.
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/generate.py b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/generate.py index b3e3340..98374982 100755 --- a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/generate.py +++ b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/generate.py
@@ -3,65 +3,71 @@ import os import sys -sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', 'common', 'security-features', 'tools')) +sys.path.insert( + 0, + os.path.join( + os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', 'common', + 'security-features', 'tools')) import generate + class ReferrerPolicyConfig(object): - def __init__(self): - self.selection_pattern = '%(delivery_method)s/' + \ - '%(origin)s/' + \ - '%(source_protocol)s-%(target_protocol)s/' + \ - '%(subresource)s/' + \ - '%(redirection)s/' + def __init__(self): + self.selection_pattern = '%(delivery_type)s/' + \ + '%(origin)s/' + \ + '%(source_scheme)s/' + \ + '%(subresource)s/' + \ + '%(redirection)s/' - self.test_file_path_pattern = '%(spec_name)s/' + self.selection_pattern + \ - '%(name)s.%(source_protocol)s.html' + self.test_file_path_pattern = '%(spec_name)s/' + self.selection_pattern + \ + '%(name)s.%(source_scheme)s.html' - self.test_description_template = '''The referrer URL is %(referrer_url)s when a -document served over %(source_protocol)s requires an %(target_protocol)s -sub-resource via %(subresource)s using the %(delivery_method)s + self.test_description_template = '''The referrer URL is %(expectation)s when a +document served over %(source_scheme)s requires a +sub-resource via %(subresource)s using the %(delivery_type)s delivery method with %(redirection)s and when the target request is %(origin)s.''' - self.test_page_title_template = 'Referrer-Policy: %s' + self.test_page_title_template = 'Referrer-Policy: %s' - self.helper_js = '/referrer-policy/generic/referrer-policy-test-case.sub.js' + self.helper_js = '/referrer-policy/generic/referrer-policy-test-case.sub.js' - # For debug target only. - self.sanity_checker_js = '/referrer-policy/generic/sanity-checker.js' - self.spec_json_js = '/referrer-policy/spec_json.js' + # For debug target only. + self.sanity_checker_js = '/referrer-policy/generic/sanity-checker.js' + self.spec_json_js = '/referrer-policy/spec_json.js' - self.test_case_name = 'ReferrerPolicyTestCase' + self.test_case_name = 'ReferrerPolicyTestCase' - script_directory = os.path.dirname(os.path.abspath(__file__)) - self.spec_directory = os.path.abspath(os.path.join(script_directory, '..', '..')) + script_directory = os.path.dirname(os.path.abspath(__file__)) + self.spec_directory = os.path.abspath( + os.path.join(script_directory, '..', '..')) - def handleDelivery(self, selection, spec): - delivery_method = selection['delivery_method'] - delivery_value = spec['referrer_policy'] + def handleDelivery(self, selection, spec): + delivery_type = selection['delivery_type'] + delivery_value = selection['delivery_value'] - meta = '' - headers = [] - if delivery_value != None: - if delivery_method == 'meta-referrer': - meta = \ - '<meta name="referrer" content="%s">' % delivery_value - elif delivery_method == 'http-rp': - meta = \ - "<!-- No meta: Referrer policy delivered via HTTP headers. -->" - headers.append('Referrer-Policy: ' + '%s' % delivery_value) - # TODO(kristijanburnik): Limit to WPT origins. - headers.append('Access-Control-Allow-Origin: *') - elif delivery_method == 'attr-referrer': - # attr-referrer is supported by the JS test wrapper. - pass - elif delivery_method == 'rel-noreferrer': - # rel=noreferrer is supported by the JS test wrapper. - pass - else: - raise ValueError('Not implemented delivery_method: ' \ - + delivery_method) - return {"meta": meta, "headers": headers} + meta = '' + headers = [] + if delivery_value != None: + if delivery_type == 'meta': + meta = \ + '<meta name="referrer" content="%s">' % delivery_value + elif delivery_type == 'http-rp': + meta = \ + "<!-- No meta: Referrer policy delivered via HTTP headers. -->" + headers.append('Referrer-Policy: ' + '%s' % delivery_value) + # TODO(kristijanburnik): Limit to WPT origins. + headers.append('Access-Control-Allow-Origin: *') + elif delivery_type == 'attr': + # attr-referrer is supported by the JS test wrapper. + pass + elif delivery_type == 'rel-noref': + # rel=noreferrer is supported by the JS test wrapper. + pass + else: + raise ValueError('Not implemented delivery_type: ' \ + + delivery_type) + return {"meta": meta, "headers": headers} if __name__ == '__main__':
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/spec_validator.py b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/spec_validator.py deleted file mode 100755 index 70656db..0000000 --- a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/tools/spec_validator.py +++ /dev/null
@@ -1,173 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function - -import json, sys -from common_paths import * - -def assert_non_empty_string(obj, field): - assert field in obj, 'Missing field "%s"' % field - assert isinstance(obj[field], basestring), \ - 'Field "%s" must be a string' % field - assert len(obj[field]) > 0, 'Field "%s" must not be empty' % field - - -def assert_non_empty_list(obj, field): - assert isinstance(obj[field], list), \ - '%s must be a list' % field - assert len(obj[field]) > 0, \ - '%s list must not be empty' % field - - -def assert_non_empty_dict(obj, field): - assert isinstance(obj[field], dict), \ - '%s must be a dict' % field - assert len(obj[field]) > 0, \ - '%s dict must not be empty' % field - - -def assert_contains(obj, field): - assert field in obj, 'Must contain field "%s"' % field - - -def assert_value_from(obj, field, items): - assert obj[field] in items, \ - 'Field "%s" must be from: %s' % (field, str(items)) - - -def assert_atom_or_list_items_from(obj, field, items): - if isinstance(obj[field], basestring) or isinstance(obj[field], int): - assert_value_from(obj, field, items) - return - - assert isinstance(obj[field], list), '%s must be a list' % field - for allowed_value in obj[field]: - assert allowed_value != '*', "Wildcard is not supported for lists!" - assert allowed_value in items, \ - 'Field "%s" must be from: %s' % (field, str(items)) - - -def assert_contains_only_fields(obj, expected_fields): - for expected_field in expected_fields: - assert_contains(obj, expected_field) - - for actual_field in obj: - assert actual_field in expected_fields, \ - 'Unexpected field "%s".' % actual_field - - -def assert_value_unique_in(value, used_values): - assert value not in used_values, 'Duplicate value "%s"!' % str(value) - used_values[value] = True - - -def assert_valid_artifact(exp_pattern, artifact_key, schema): - if isinstance(schema, list): - assert_atom_or_list_items_from(exp_pattern, artifact_key, - ["*"] + schema) - return - - for sub_artifact_key, sub_schema in schema.iteritems(): - assert_valid_artifact(exp_pattern[artifact_key], sub_artifact_key, - sub_schema) - -def validate(spec_json, details): - """ Validates the json specification for generating tests. """ - - details['object'] = spec_json - assert_contains_only_fields(spec_json, ["specification", - "referrer_policy_schema", - "test_expansion_schema", - "excluded_tests"]) - assert_non_empty_list(spec_json, "specification") - assert_non_empty_list(spec_json, "referrer_policy_schema") - assert_non_empty_dict(spec_json, "test_expansion_schema") - assert_non_empty_list(spec_json, "excluded_tests") - - specification = spec_json['specification'] - referrer_policy_schema = spec_json['referrer_policy_schema'] - test_expansion_schema = spec_json['test_expansion_schema'] - excluded_tests = spec_json['excluded_tests'] - - valid_test_expansion_fields = ['name'] + test_expansion_schema.keys() - - # Validate each single spec. - for spec in specification: - details['object'] = spec - - # Validate required fields for a single spec. - assert_contains_only_fields(spec, ['name', - 'title', - 'description', - 'referrer_policy', - 'specification_url', - 'test_expansion']) - assert_non_empty_string(spec, 'name') - assert_non_empty_string(spec, 'title') - assert_non_empty_string(spec, 'description') - assert_non_empty_string(spec, 'specification_url') - assert_value_from(spec, 'referrer_policy', referrer_policy_schema) - assert_non_empty_list(spec, 'test_expansion') - - # Validate spec's test expansion. - used_spec_names = {} - - for spec_exp in spec['test_expansion']: - details['object'] = spec_exp - assert_non_empty_string(spec_exp, 'name') - # The name is unique in same expansion group. - assert_value_unique_in((spec_exp['expansion'], spec_exp['name']), - used_spec_names) - assert_contains_only_fields(spec_exp, valid_test_expansion_fields) - - for artifact in test_expansion_schema: - details['test_expansion_field'] = artifact - assert_valid_artifact(spec_exp, artifact, - test_expansion_schema[artifact]) - del details['test_expansion_field'] - - # Validate the test_expansion schema members. - details['object'] = test_expansion_schema - assert_contains_only_fields(test_expansion_schema, ['expansion', - 'delivery_method', - 'redirection', - 'origin', - 'source_protocol', - 'target_protocol', - 'subresource', - 'referrer_url']) - # Validate excluded tests. - details['object'] = excluded_tests - for excluded_test_expansion in excluded_tests: - assert_contains_only_fields(excluded_test_expansion, - valid_test_expansion_fields) - details['object'] = excluded_test_expansion - for artifact in test_expansion_schema: - details['test_expansion_field'] = artifact - assert_valid_artifact( - excluded_test_expansion, - artifact, - test_expansion_schema[artifact]) - del details['test_expansion_field'] - - del details['object'] - - -def assert_valid_spec_json(spec_json): - error_details = {} - try: - validate(spec_json, error_details) - except AssertionError as err: - print('ERROR:', err.message) - print(json.dumps(error_details, indent=4)) - sys.exit(1) - - -def main(): - spec_json = load_spec_json(); - assert_valid_spec_json(spec_json) - print("Spec JSON is valid.") - - -if __name__ == '__main__': - main()
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/spec.src.json b/third_party/blink/web_tests/external/wpt/referrer-policy/spec.src.json index 5f0247b..f69c289 100644 --- a/third_party/blink/web_tests/external/wpt/referrer-policy/spec.src.json +++ b/third_party/blink/web_tests/external/wpt/referrer-policy/spec.src.json
@@ -5,51 +5,62 @@ "title": "Referrer Policy is not explicitly defined", "description": "Check that referrer URL follows no-referrer-when-downgrade policy when no explicit Referrer Policy is set.", "specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policies", - "referrer_policy": null, "test_expansion": [ { "name": "insecure-protocol", "expansion": "default", - "source_protocol": "http", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": null, "redirection": "*", - "origin": "*", + "origin": [ + "same-http", + "cross-http" + ], "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "upgrade-protocol", "expansion": "default", - "source_protocol": "http", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": null, "redirection": "*", - "origin": "*", + "origin": [ + "same-https", + "cross-https" + ], "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "downgrade-protocol", "expansion": "default", - "source_protocol": "https", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": null, "redirection": "*", - "origin": "*", + "origin": [ + "same-http", + "cross-http" + ], "subresource": "*", - "referrer_url": "omitted" + "expectation": "omitted" }, { "name": "secure-protocol", "expansion": "default", - "source_protocol": "https", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": null, "redirection": "*", - "origin": "*", + "origin": [ + "same-https", + "cross-https" + ], "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" } ] }, @@ -58,18 +69,17 @@ "title": "Referrer Policy is set to 'no-referrer'", "description": "Check that sub-resource never gets the referrer URL.", "specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-no-referrer", - "referrer_policy": "no-referrer", "test_expansion": [ { "name": "generic", "expansion": "default", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "no-referrer", "redirection": "*", "origin": "*", "subresource": "*", - "referrer_url": "omitted" + "expectation": "omitted" } ] }, @@ -78,51 +88,62 @@ "title": "Referrer Policy is set to 'no-referrer-when-downgrade'", "description": "Check that non a priori insecure subresource gets the full Referrer URL. A priori insecure subresource gets no referrer information.", "specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-no-referrer-when-downgrade", - "referrer_policy": "no-referrer-when-downgrade", "test_expansion": [ { "name": "insecure-protocol", "expansion": "default", - "source_protocol": "http", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "no-referrer-when-downgrade", "redirection": "*", - "origin": "*", + "origin": [ + "same-http", + "cross-http" + ], "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "upgrade-protocol", "expansion": "default", - "source_protocol": "http", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "no-referrer-when-downgrade", "redirection": "*", - "origin": "*", + "origin": [ + "same-https", + "cross-https" + ], "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "downgrade-protocol", "expansion": "default", - "source_protocol": "https", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "no-referrer-when-downgrade", "redirection": "*", - "origin": "*", + "origin": [ + "same-http", + "cross-http" + ], "subresource": "*", - "referrer_url": "omitted" + "expectation": "omitted" }, { "name": "secure-protocol", "expansion": "default", - "source_protocol": "https", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "no-referrer-when-downgrade", "redirection": "*", - "origin": "*", + "origin": [ + "same-https", + "cross-https" + ], "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" } ] }, @@ -131,18 +152,17 @@ "title": "Referrer Policy is set to 'origin'", "description": "Check that all subresources in all casses get only the origin portion of the referrer URL.", "specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin", - "referrer_policy": "origin", "test_expansion": [ { "name": "generic", "expansion": "default", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "origin", "redirection": "*", "origin": "*", "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" } ] }, @@ -151,51 +171,56 @@ "title": "Referrer Policy is set to 'same-origin'", "description": "Check that cross-origin subresources get no referrer information and same-origin get the stripped referrer URL.", "specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-same-origin", - "referrer_policy": "same-origin", "test_expansion": [ { "name": "same-origin-insecure", "expansion": "default", - "source_protocol": "http", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "same-origin", "redirection": "*", - "origin": "same-origin", + "origin": "same-http", "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "same-origin-secure-default", "expansion": "default", - "source_protocol": "https", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "same-origin", "redirection": "*", - "origin": "same-origin", + "origin": "same-https", "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "same-origin-insecure", "expansion": "override", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], - "redirection": "swap-origin-redirect", - "origin": "same-origin", + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "same-origin", + "redirection": "swap-origin", + "origin": [ + "same-http", + "same-https" + ], "subresource": "*", - "referrer_url": "omitted" + "expectation": "omitted" }, { "name": "cross-origin", "expansion": "default", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "same-origin", "redirection": "*", - "origin": "cross-origin", + "origin": [ + "cross-http", + "cross-https" + ], "subresource": "*", - "referrer_url": "omitted" + "expectation": "omitted" } ] }, @@ -204,73 +229,78 @@ "title": "Referrer Policy is set to 'origin-when-cross-origin'", "description": "Check that cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.", "specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-origin-when-cross-origin", - "referrer_policy": "origin-when-cross-origin", "test_expansion": [ { "name": "same-origin-insecure", "expansion": "default", - "source_protocol": "http", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "origin-when-cross-origin", "redirection": "*", - "origin": "same-origin", + "origin": "same-http", "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "same-origin-secure-default", "expansion": "default", - "source_protocol": "https", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "origin-when-cross-origin", "redirection": "*", - "origin": "same-origin", + "origin": "same-https", "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "same-origin-upgrade", "expansion": "default", - "source_protocol": "http", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "origin-when-cross-origin", "redirection": "*", - "origin": "same-origin", + "origin": "same-https", "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" }, { "name": "same-origin-downgrade", "expansion": "default", - "source_protocol": "https", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "origin-when-cross-origin", "redirection": "*", - "origin": "same-origin", + "origin": "same-http", "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" }, { "name": "same-origin-insecure", "expansion": "override", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], - "redirection": "swap-origin-redirect", - "origin": "same-origin", + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "origin-when-cross-origin", + "redirection": "swap-origin", + "origin": [ + "same-http", + "same-https" + ], "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" }, { "name": "cross-origin", "expansion": "default", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "origin-when-cross-origin", "redirection": "*", - "origin": "cross-origin", + "origin": [ + "cross-http", + "cross-https" + ], "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" } ] }, @@ -279,51 +309,62 @@ "title": "Referrer Policy is set to 'strict-origin'", "description": "Check that non a priori insecure subresource gets only the origin portion of the referrer URL. A priori insecure subresource gets no referrer information.", "specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin", - "referrer_policy": "strict-origin", "test_expansion": [ { "name": "insecure-protocol", "expansion": "default", - "source_protocol": "http", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "strict-origin", "redirection": "*", - "origin": "*", + "origin": [ + "same-http", + "cross-http" + ], "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" }, { "name": "upgrade-protocol", "expansion": "default", - "source_protocol": "http", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "strict-origin", "redirection": "*", - "origin": "*", + "origin": [ + "same-https", + "cross-https" + ], "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" }, { "name": "downgrade-protocol", "expansion": "default", - "source_protocol": "https", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "strict-origin", "redirection": "*", - "origin": "*", + "origin": [ + "same-http", + "cross-http" + ], "subresource": "*", - "referrer_url": "omitted" + "expectation": "omitted" }, { "name": "secure-protocol", "expansion": "default", - "source_protocol": "https", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "strict-origin", "redirection": "*", - "origin": "*", + "origin": [ + "same-https", + "cross-https" + ], "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" } ] }, @@ -332,95 +373,100 @@ "title": "Referrer Policy is set to 'strict-origin-when-cross-origin'", "description": "Check that a priori insecure subresource gets no referrer information. Otherwise, cross-origin subresources get the origin portion of the referrer URL and same-origin get the stripped referrer URL.", "specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-strict-origin-when-cross-origin", - "referrer_policy": "strict-origin-when-cross-origin", "test_expansion": [ { "name": "same-insecure", "expansion": "default", - "source_protocol": "http", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "strict-origin-when-cross-origin", "redirection": "*", - "origin": "same-origin", + "origin": "same-http", "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "same-insecure", "expansion": "override", - "source_protocol": "http", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], - "redirection": "swap-origin-redirect", - "origin": "same-origin", + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "strict-origin-when-cross-origin", + "redirection": "swap-origin", + "origin": "same-http", "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" }, { "name": "cross-insecure", "expansion": "default", - "source_protocol": "http", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "strict-origin-when-cross-origin", "redirection": "*", - "origin": "cross-origin", + "origin": "cross-http", "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" }, { "name": "upgrade-protocol", "expansion": "default", - "source_protocol": "http", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "strict-origin-when-cross-origin", "redirection": "*", - "origin": "*", + "origin": [ + "same-https", + "cross-https" + ], "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" }, { "name": "downgrade-protocol", "expansion": "default", - "source_protocol": "https", - "target_protocol": "http", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "strict-origin-when-cross-origin", "redirection": "*", - "origin": "*", + "origin": [ + "same-http", + "cross-http" + ], "subresource": "*", - "referrer_url": "omitted" + "expectation": "omitted" }, { "name": "same-secure", "expansion": "default", - "source_protocol": "https", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "strict-origin-when-cross-origin", "redirection": "*", - "origin": "same-origin", + "origin": "same-https", "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" }, { "name": "same-secure", "expansion": "override", - "source_protocol": "https", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], - "redirection": "swap-origin-redirect", - "origin": "same-origin", + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "strict-origin-when-cross-origin", + "redirection": "swap-origin", + "origin": "same-https", "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" }, { "name": "cross-secure", "expansion": "default", - "source_protocol": "https", - "target_protocol": "https", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "strict-origin-when-cross-origin", "redirection": "*", - "origin": "cross-origin", + "origin": "cross-https", "subresource": "*", - "referrer_url": "origin" + "expectation": "origin" } ] }, @@ -429,199 +475,185 @@ "title": "Referrer Policy is set to 'unsafe-url'", "description": "Check that all sub-resources get the stripped referrer URL.", "specification_url": "https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-unsafe-url", - "referrer_policy": "unsafe-url", "test_expansion": [ { "name": "generic", "expansion": "default", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": ["http-rp", "meta-referrer", "attr-referrer"], + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "unsafe-url", "redirection": "*", "origin": "*", "subresource": "*", - "referrer_url": "stripped-referrer" + "expectation": "stripped-referrer" } ] } ], - - "excluded_tests":[ + "delivery_key": "referrerPolicy", + "excluded_tests": [ { "name": "cross-origin-workers", "expansion": "*", - "source_protocol": "*", - "target_protocol": "*", + "source_scheme": "*", "redirection": "*", - "delivery_method": "*", - "origin": "cross-origin", + "delivery_type": "*", + "delivery_value": "*", + "origin": [ + "cross-http", + "cross-https" + ], "subresource": [ "worker-request", "module-worker", "shared-worker" ], - "referrer_url": "*" + "expectation": "*" }, { "name": "upgraded-protocol-workers", "expansion": "*", - "source_protocol": "http", - "target_protocol": "https", - "delivery_method": "*", + "source_scheme": "http", + "delivery_type": "*", + "delivery_value": "*", "redirection": "*", - "origin": "*", + "origin": [ + "same-https", + "cross-https" + ], "subresource": [ "worker-request", "module-worker", "shared-worker" ], - "referrer_url": "*" + "expectation": "*" }, { "name": "mixed-content-insecure-subresources", "expansion": "*", - "source_protocol": "https", - "target_protocol": "http", - "delivery_method": "*", + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "*", "redirection": "*", - "origin": "*", + "origin": [ + "same-http", + "cross-http" + ], "subresource": "*", - "referrer_url": "*" - }, - { - "name": "elements-not-supporting-attr-referrer", - "expansion": "*", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": ["attr-referrer"], - "redirection": "*", - "origin": "*", - "subresource": [ - "xhr-request", - "worker-request", - "module-worker", - "shared-worker", - "fetch-request" - ], - "referrer_url": "*" - }, - { - "name": "elements-not-supporting-rel-noreferrer", - "expansion": "*", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": ["rel-noreferrer"], - "redirection": "*", - "origin": "*", - "subresource": [ - "iframe-tag", - "img-tag", - "script-tag", - "xhr-request", - "worker-request", - "module-worker", - "shared-worker", - "fetch-request", - "area-tag" - ], - "referrer_url": "*" + "expectation": "*" }, { "name": "area-tag", "expansion": "*", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": "*", + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "*", "redirection": "*", "origin": "*", "subresource": "area-tag", - "referrer_url": "*" + "expectation": "*" }, { "name": "worker-requests-with-swap-origin-redirect", "expansion": "*", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": "*", - "redirection": "swap-origin-redirect", + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "*", + "redirection": "swap-origin", "origin": "*", "subresource": [ "worker-request", "module-worker", "shared-worker" ], - "referrer_url": "*" + "expectation": "*" }, { "name": "overhead-for-redirection", "expansion": "*", - "source_protocol": "*", - "target_protocol": "*", - "delivery_method": "*", - "redirection": ["keep-origin-redirect", "swap-origin-redirect"], + "source_scheme": "*", + "delivery_type": "*", + "delivery_value": "*", + "redirection": [ + "keep-origin", + "swap-origin" + ], "origin": "*", - "subresource": ["a-tag", "area-tag"], - "referrer_url": "*" + "subresource": [ + "a-tag", + "area-tag" + ], + "expectation": "*" }, { "name": "source-https-unsupported-by-web-platform-tests-runners", "expansion": "*", - "source_protocol": "https", - "target_protocol": "*", - "delivery_method": "*", + "source_scheme": "https", + "delivery_type": "*", + "delivery_value": "*", "redirection": "*", "origin": "*", "subresource": "*", - "referrer_url": "*" + "expectation": "*" + }, + { + "name": "<link rel=noreferrer>'s delivery_value should be no-referrer", + "expansion": "*", + "source_scheme": "*", + "delivery_type": "rel-noref", + "delivery_value": [ + null, + "no-referrer-when-downgrade", + "same-origin", + "origin", + "origin-when-cross-origin", + "strict-origin", + "strict-origin-when-cross-origin", + "unsafe-url" + ], + "redirection": "*", + "origin": "*", + "subresource": "*", + "expectation": "*" } ], - - "referrer_policy_schema": [ - null, - "no-referrer", - "no-referrer-when-downgrade", - "same-origin", - "origin", - "origin-when-cross-origin", - "strict-origin", - "strict-origin-when-cross-origin", - "unsafe-url" - ], - "test_expansion_schema": { "expansion": [ "default", "override" ], - - "delivery_method": [ + "delivery_type": [ + "attr", + "rel-noref", "http-rp", - "meta-referrer", - "attr-referrer", - "rel-noreferrer" + "meta" ], - - "origin": [ + "delivery_value": [ + null, + "no-referrer", + "no-referrer-when-downgrade", "same-origin", - "cross-origin" + "origin", + "origin-when-cross-origin", + "strict-origin", + "strict-origin-when-cross-origin", + "unsafe-url" ], - - "source_protocol": [ + "origin": [ + "same-http", + "same-https", + "cross-http", + "cross-https" + ], + "source_scheme": [ "http", "https" ], - - "target_protocol": [ - "http", - "https" - ], - "redirection": [ "no-redirect", - "keep-origin-redirect", - "swap-origin-redirect" + "keep-origin", + "swap-origin" ], - "subresource": [ "iframe-tag", "img-tag", @@ -634,8 +666,7 @@ "shared-worker", "fetch-request" ], - - "referrer_url": [ + "expectation": [ "omitted", "origin", "stripped-referrer"
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detected-boundingBox-read-only.html b/third_party/blink/web_tests/external/wpt/shape-detection/detected-boundingBox-read-only.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detected-boundingBox-read-only.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detected-boundingBox-read-only.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLCanvasElement.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLCanvasElement.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLCanvasElement.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLCanvasElement.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLImageElement.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLImageElement.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLImageElement.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLImageElement.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-HTMLVideoElement.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageBitmap.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageBitmap.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageBitmap.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageBitmap.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageData-detached.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageData-detached.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageData-detached.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageData-detached.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageData.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageData.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageData.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-ImageData.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-getSupportedFormats.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-getSupportedFormats.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-getSupportedFormats.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-getSupportedFormats.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-on-worker.worker.js b/third_party/blink/web_tests/external/wpt/shape-detection/detection-on-worker.https.worker.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-on-worker.worker.js rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-on-worker.https.worker.js
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-options.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-options.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-options.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-options.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detection-security-test.html b/third_party/blink/web_tests/external/wpt/shape-detection/detection-security-test.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detection-security-test.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detection-security-test.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/detector-same-object.html b/third_party/blink/web_tests/external/wpt/shape-detection/detector-same-object.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/detector-same-object.html rename to third_party/blink/web_tests/external/wpt/shape-detection/detector-same-object.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any-expected.txt b/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.https.any-expected.txt similarity index 87% rename from third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any-expected.txt rename to third_party/blink/web_tests/external/wpt/shape-detection/idlharness.https.any-expected.txt index 3eeafa7..4e09e548 100644 --- a/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.https.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 53 tests; 50 PASS, 3 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 53 tests; 52 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS FaceDetector interface: existence and properties of interface object PASS FaceDetector interface object length @@ -12,9 +12,7 @@ PASS Stringification of faceDetector PASS FaceDetector interface: faceDetector must inherit property "detect(ImageBitmapSource)" with the proper type PASS FaceDetector interface: calling detect(ImageBitmapSource) on faceDetector with too few arguments must throw TypeError -FAIL DetectedFace interface: existence and properties of interface object assert_throws: interface object didn't throw TypeError when called as a constructor function "function() { - new interface_object(); - }" did not throw +PASS DetectedFace interface: existence and properties of interface object PASS DetectedFace interface object length PASS DetectedFace interface object name PASS DetectedFace interface: existence and properties of interface prototype object @@ -39,9 +37,7 @@ PASS BarcodeDetector interface: barcodeDetector must inherit property "getSupportedFormats()" with the proper type PASS BarcodeDetector interface: barcodeDetector must inherit property "detect(ImageBitmapSource)" with the proper type PASS BarcodeDetector interface: calling detect(ImageBitmapSource) on barcodeDetector with too few arguments must throw TypeError -FAIL DetectedBarcode interface: existence and properties of interface object assert_throws: interface object didn't throw TypeError when called as a constructor function "function() { - new interface_object(); - }" did not throw +PASS DetectedBarcode interface: existence and properties of interface object PASS DetectedBarcode interface object length PASS DetectedBarcode interface object name PASS DetectedBarcode interface: existence and properties of interface prototype object
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any.js b/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.https.any.js similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any.js rename to third_party/blink/web_tests/external/wpt/shape-detection/idlharness.https.any.js
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.https.any.worker-expected.txt similarity index 84% rename from third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any.worker-expected.txt rename to third_party/blink/web_tests/external/wpt/shape-detection/idlharness.https.any.worker-expected.txt index 58b8ab3..e27f6fa 100644 --- a/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/shape-detection/idlharness.https.any.worker-expected.txt
@@ -11,8 +11,8 @@ PASS Stringification of faceDetector PASS FaceDetector interface: faceDetector must inherit property "detect(ImageBitmapSource)" with the proper type PASS FaceDetector interface: calling detect(ImageBitmapSource) on faceDetector with too few arguments must throw TypeError -PASS DetectedFace interface: existence and properties of interface object -FAIL DetectedFace must be primary interface of detectedFace assert_own_property: self does not have own property "DetectedFace" expected property "DetectedFace" missing +FAIL DetectedFace interface: existence and properties of interface object assert_false: expected false got true +PASS DetectedFace must be primary interface of detectedFace PASS Stringification of detectedFace FAIL DetectedFace interface: detectedFace must not have property "boundingBox" assert_false: expected false got true FAIL DetectedFace interface: detectedFace must not have property "landmarks" assert_false: expected false got true @@ -29,8 +29,8 @@ PASS BarcodeDetector interface: barcodeDetector must inherit property "getSupportedFormats()" with the proper type PASS BarcodeDetector interface: barcodeDetector must inherit property "detect(ImageBitmapSource)" with the proper type PASS BarcodeDetector interface: calling detect(ImageBitmapSource) on barcodeDetector with too few arguments must throw TypeError -PASS DetectedBarcode interface: existence and properties of interface object -FAIL DetectedBarcode must be primary interface of detectedBarcode assert_own_property: self does not have own property "DetectedBarcode" expected property "DetectedBarcode" missing +FAIL DetectedBarcode interface: existence and properties of interface object assert_false: expected false got true +PASS DetectedBarcode must be primary interface of detectedBarcode PASS Stringification of detectedBarcode FAIL DetectedBarcode interface: detectedBarcode must not have property "boundingBox" assert_false: expected false got true FAIL DetectedBarcode interface: detectedBarcode must not have property "rawValue" assert_false: expected false got true
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html b/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.html rename to third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-cross-origin.sub.https.html
diff --git a/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-empty-input.html b/third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-empty-input.https.html similarity index 100% rename from third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-empty-input.html rename to third_party/blink/web_tests/external/wpt/shape-detection/shapedetection-empty-input.https.html
diff --git a/third_party/blink/web_tests/external/wpt/tools/requirements_flake8.txt b/third_party/blink/web_tests/external/wpt/tools/requirements_flake8.txt index 480aacd4..d73e7c3d 100644 --- a/third_party/blink/web_tests/external/wpt/tools/requirements_flake8.txt +++ b/third_party/blink/web_tests/external/wpt/tools/requirements_flake8.txt
@@ -1,4 +1,4 @@ -flake8==3.7.7 +flake8==3.7.8 pycodestyle==2.5.0 pyflakes==2.1.1 pep8-naming==0.8.2
diff --git a/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt index 8f1d67cd..c1bf4bc0 100644 --- a/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt +++ b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
@@ -1,3 +1,3 @@ -mypy==0.711 +mypy==0.720 mypy-extensions==0.4.1 typed-ast==1.4.0
diff --git a/third_party/blink/web_tests/external/wpt/tools/tox.ini b/third_party/blink/web_tests/external/wpt/tools/tox.ini index ba6dc03..63fb8ed9 100644 --- a/third_party/blink/web_tests/external/wpt/tools/tox.ini +++ b/third_party/blink/web_tests/external/wpt/tools/tox.ini
@@ -13,6 +13,7 @@ passenv = HYPOTHESIS_PROFILE + PY_COLORS [testenv:py27-flake8] deps = -rrequirements_flake8.txt
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py index 6acc5b8e..d5d7e7a2 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py +++ b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
@@ -661,7 +661,7 @@ if __name__ == "__main__": import pdb - from tools import localpaths # noqa: flake8 + from tools import localpaths # noqa: F401 try: main() except Exception:
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/wpt.py b/third_party/blink/web_tests/external/wpt/tools/wpt/wpt.py index 4130e1e..93301dd 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wpt/wpt.py +++ b/third_party/blink/web_tests/external/wpt/tools/wpt/wpt.py
@@ -4,7 +4,7 @@ import os import sys -from tools import localpaths # noqa: flake8 +from tools import localpaths # noqa: F401 from six import iteritems from . import virtualenv
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt index e25eec3..d6c7a4f 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/requirements.txt
@@ -2,7 +2,7 @@ mozinfo==1.1.0 mozlog==4.2.0 mozdebug==0.1.1 -pillow==6.0.0 +pillow==6.1.0 urllib3[secure]==1.25.3 requests==2.22.0 six==1.12.0
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py index 2493f1f..9244092 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/environment.py
@@ -14,7 +14,7 @@ repo_root = os.path.abspath(os.path.join(here, os.pardir, os.pardir, os.pardir)) sys.path.insert(0, repo_root) -from tools import localpaths # noqa: flake8 +from tools import localpaths # noqa: F401 from wptserve.handlers import StringHandler
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/update.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/update.py index a0f4237..0bcaf82 100644 --- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/update.py +++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/update/update.py
@@ -10,7 +10,7 @@ def setup_paths(sync_path): sys.path.insert(0, os.path.abspath(sync_path)) - from tools import localpaths # noqa: flake8 + from tools import localpaths # noqa: F401 class LoadConfig(Step): """Step for loading configuration from the ini file and kwargs."""
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html index 3074895..8dda8b2 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html
@@ -6,20 +6,24 @@ </head> <body> <script> - // CSP insists the "trusted-types: ..." directives are deliverd as headers + // CSP insists the "trusted-types: ..." directives are delivered as headers // (rather than as "<meta http-equiv" tags). This test assumes the following // headers are set in the .headers file: // // Content-Security-Policy: trusted-types one // Content-Security-Policy-Report-Only: trusted-types two; report-uri ... // Content-Security-Policy: plugin-types bla/blubb + // Content-Security-Policy: default-src * 'unsafe-inline' // - // The last rule is there so we can provoke a CSP violation report at will. + // The third rule is there so we can provoke a CSP violation report at will. // The intent is that in order to test that a violation has *not* been thrown // (and without resorting to abominations like timeouts), we force a *another* - // CSP violation (by violating the img-src rule) and when that event is + // CSP violation (by violating the plugin-types rule) and when that event is // processed we can we sure that an earlier event - if it indeed occurred - // must have already been processed. + // + // The last rule allows all scripting except 'unsafe-eval', so we can also + // test reporting of this case. const url = "" + document.location; @@ -72,7 +76,6 @@ }); } - promise_test(t => { let p = Promise.resolve() .then(promise_violation("trusted-types one")) @@ -134,10 +137,89 @@ return p; }, "Trusted Type violation report: assign trusted HTML to html; no report"); + // Test the "sample" field of the event. + // TODO(vogelheim): The current set of tests allows for more variance in the + // sample reports than the current spec draft does. Once the spec has + // been finalized, we should clamp this down to check byte-for-byte + // against the values mandated by the spec. + + function expect_sample(s) { return e => { + assert_true(e.sample.includes(s), + `expected "${e.sample}" to include "${s}".`); + return e; + } } + + promise_test(t => { + let p = Promise.resolve() + .then(promise_violation("trusted-types two")) + .then(expect_sample("Element.innerHTML")) + .then(expect_sample("abc")); + expect_throws(_ => { document.getElementById("div").innerHTML = "abc" }); + return p; + }, "Trusted Type violation report: sample for .innerHTML assignment"); + + promise_test(t => { + let p = Promise.resolve() + .then(promise_violation("trusted-types two")) + .then(expect_sample("HTMLAnchorElement.href")); + expect_throws(_ => { document.getElementById("anchor").href = "" }); + return p; + }, "Trusted Type violation report: sample for .href assignment"); + + promise_test(t => { + let p = Promise.resolve() + .then(promise_violation("trusted-types two")) + .then(expect_sample("HTMLElement.innerText")) + .then(expect_sample("2+2;")); + expect_throws(_ => document.getElementById("script").innerText = "2+2;"); + return p; + }, "Trusted Type violation report: sample for script innerText assignment"); + + promise_test(t => { + let p = Promise.resolve() + .then(promise_violation("trusted-types one")) + .then(expect_sample("eval")) + .then(expect_sample("2+2")) + .then(promise_flush()); + expect_throws(_ => eval("2+2")); + flush(); + return p; + }, "Trusted Type violation report: sample for eval"); + + promise_test(t => { + // We expect the sample string to always contain the name, and at least the + // start of the value, but it should not be excessively long. + let p = Promise.resolve() + .then(promise_violation("trusted-types two")) + .then(expect_sample("HTMLElement.innerText")) + .then(expect_sample("abbb")) + .then(e => assert_less_than(e.sample.length, 150)); + const value = "a" + "b".repeat(50000); + expect_throws(_ => document.getElementById("script").innerText = value); + return p; + }, "Trusted Type violation report: large values should be handled sanely."); + + // Test reporting for Custom Elements (where supported). The report should + // refer to the DOM elements being modified, so that Custom Elements cannot + // "mask" the underlying DOM mechanism (for reporting). + if (customElements) { + class CustomLink extends HTMLAnchorElement {}; + customElements.define("custom-link", CustomLink, { extends: "a" }); + + promise_test(t => { + let p = Promise.resolve() + .then(promise_violation("trusted-types one")) + .then(expect_sample("HTMLAnchorElement.href")) + .then(expect_sample("abc")); + expect_throws(_ => document.getElementById("customlink").href = "abc"); + return p; + }, "Trusted Type violation report: sample for custom element assignment"); + } </script> <!-- Some elements for the tests to act on. --> <a id="anchor" href="">anchor</a> <div id="div"></div> - + <script id="script"></script> + <a id="customlink" is="custom-link" href="a"></a> </body>
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html.headers b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html.headers index 8093b84..947a151c 100644 --- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html.headers +++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-reporting.tentative.https.html.headers
@@ -1,4 +1,5 @@ Content-Security-Policy: trusted-types one Content-Security-Policy-Report-Only: trusted-types two; report-uri /content-security-policy/resources/dummy-report.php Content-Security-Policy: plugin-types bla/blubb +Content-Security-Policy: default-src * 'unsafe-inline'
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing-expected.txt b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing-expected.txt deleted file mode 100644 index 511d86a..0000000 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing-expected.txt +++ /dev/null
@@ -1,4 +0,0 @@ -This is a testharness.js-based test. -FAIL MediaStreamAudioSourceNode captures the right track. assert_true: Other track seem to be routed to the AudioContext? expected true got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html index 43e5ac8..2e04ab6a 100644 --- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html +++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-mediastreamaudiosourcenode-interface/mediastreamaudiosourcenode-routing.html
@@ -57,6 +57,8 @@ const twoTrackSource = ac.createMediaStreamSource(twoTrackMediaStream); const analyser = ac.createAnalyser(); + // Don't do smoothing so that the frequency data changes quickly + analyser.smoothingTimeConstant = 0; twoTrackSource.connect(analyser);
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html new file mode 100644 index 0000000..4dcce451 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html
@@ -0,0 +1,29 @@ +<!doctype html> +<meta charset=utf-8> +<title></title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script src="RTCPeerConnection-helper.js"></script> +<script> +"use strict"; + +promise_test(async t => { + const pc1 = new RTCPeerConnection(); + const pc2 = new RTCPeerConnection(); + t.add_cleanup(() => pc1.close()); + t.add_cleanup(() => pc2.close()); + + pc1.addTransceiver("audio"); + + await pc1.setLocalDescription(await pc1.createOffer()); + pc1.restartIce(); + await pc2.setRemoteDescription(pc1.localDescription); + await pc2.setLocalDescription(await pc2.createAnswer()); + await pc1.setRemoteDescription(pc2.localDescription); + // When the setRemoteDescription() promise above is resolved a task should be + // queued to fire the onnegotiationneeded event. Because of this, we should + // have time to hook up the event listener *after* awaiting the SRD promise. + await new Promise(r => pc1.onnegotiationneeded = r); +}, "Negotiation needed when returning to stable does not fire too early"); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce.https-expected.txt index 0ec35085..2c0c15c 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce.https-expected.txt
@@ -1,16 +1,16 @@ This is a testharness.js-based test. -FAIL restartIce() does not trigger negotiation ahead of initial negotiation promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() has no effect on initial negotiation promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() fires negotiationneeded after initial negotiation promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() causes fresh ufrags promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() works in have-local-offer promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() works in initial have-local-offer promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() works in have-remote-offer promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() does nothing in initial have-remote-offer promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() survives remote offer promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() is satisfied by remote ICE restart promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() trumps {iceRestart: false} promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() survives rollback promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" -FAIL restartIce() survives remote offer containing partial restart promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" +FAIL restartIce() does not trigger negotiation ahead of initial negotiation assert_equals: No negotiationneeded event expected (undefined) undefined but got (object) object "[object Event]" +PASS restartIce() has no effect on initial negotiation +PASS restartIce() fires negotiationneeded after initial negotiation +PASS restartIce() causes fresh ufrags +PASS restartIce() works in have-local-offer +PASS restartIce() works in initial have-local-offer +PASS restartIce() works in have-remote-offer +PASS restartIce() does nothing in initial have-remote-offer +PASS restartIce() survives remote offer +PASS restartIce() is satisfied by remote ICE restart +PASS restartIce() trumps {iceRestart: false} +FAIL restartIce() survives rollback promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType." +FAIL restartIce() survives remote offer containing partial restart assert_false: Restarted 2 expected false got true Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce.https.html index 6b66975f..c069736f 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce.https.html +++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-restartIce.https.html
@@ -39,6 +39,19 @@ assert_equals(event, undefined, "No negotiationneeded event"); } +// In Chromium, assert_equals() produces test expectations with the values +// compared. Because ufrags are different on each run, this would make Chromium +// test expectations different on each run on tests that failed when comparing +// ufrags. To work around this problem, assert_ufrags_equals() and +// assert_ufrags_not_equals() should be preferred over assert_equals() and +// assert_not_equals(). +function assert_ufrags_equals(x, y, description) { + assert_true(x === y, description); +} +function assert_ufrags_not_equals(x, y, description) { + assert_false(x === y, description); +} + promise_test(async t => { const pc1 = new RTCPeerConnection(); const pc2 = new RTCPeerConnection(); @@ -90,21 +103,21 @@ const [oldUfrag1] = getUfrags(pc1.localDescription); const [oldUfrag2] = getUfrags(pc2.localDescription); await doSignalingHandshakeEndOnFirst(pc1, pc2); - assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "control 1"); - assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "control 2"); + assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "control 1"); + assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "control 2"); pc1.restartIce(); await new Promise(r => pc1.onnegotiationneeded = r); await doSignalingHandshakeEndOnFirst(pc1, pc2); const [newUfrag1] = getUfrags(pc1.localDescription); const [newUfrag2] = getUfrags(pc2.localDescription); - assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); - assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); await assertNoNegotiationNeeded(t, pc1); await doSignalingHandshakeEndOnFirst(pc1, pc2); - assert_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1"); - assert_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2"); + assert_ufrags_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1"); + assert_ufrags_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2"); }, "restartIce() causes fresh ufrags"); promise_test(async t => { @@ -124,15 +137,25 @@ pc1.restartIce(); await pc2.setRemoteDescription(pc1.localDescription); await pc2.setLocalDescription(await pc2.createAnswer()); + // Several tests in this file initializes the onnegotiationneeded listener + // before the setLocalDescription() or setRemoteDescription() that we expect + // to trigger negotiation needed. This allows Chrome to exercise these tests + // without timing out due to a bug that causes onnegotiationneeded to fire too + // early. + // TODO(https://crbug.com/985797): Once Chrome does not fire ONN too early, + // simply do "await new Promise(...)" instead of + // "await negotiationNeededPromise" here and in other tests in this file. + const negotiationNeededPromise = + new Promise(r => pc1.onnegotiationneeded = r); await pc1.setRemoteDescription(pc2.localDescription); - assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1"); - assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2"); - await new Promise(r => pc1.onnegotiationneeded = r); + assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1"); + assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2"); + await negotiationNeededPromise; await doSignalingHandshakeEndOnFirst(pc1, pc2); const [newUfrag1] = getUfrags(pc1.localDescription); const [newUfrag2] = getUfrags(pc2.localDescription); - assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); - assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); await assertNoNegotiationNeeded(t, pc1); }, "restartIce() works in have-local-offer"); @@ -148,15 +171,17 @@ pc1.restartIce(); await pc2.setRemoteDescription(pc1.localDescription); await pc2.setLocalDescription(await pc2.createAnswer()); + const negotiationNeededPromise = + new Promise(r => pc1.onnegotiationneeded = r); await pc1.setRemoteDescription(pc2.localDescription); const [oldUfrag1] = getUfrags(pc1.localDescription); const [oldUfrag2] = getUfrags(pc2.localDescription); - await new Promise(r => pc1.onnegotiationneeded = r); + await negotiationNeededPromise; await doSignalingHandshakeEndOnFirst(pc1, pc2); const [newUfrag1] = getUfrags(pc1.localDescription); const [newUfrag2] = getUfrags(pc2.localDescription); - assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); - assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); await assertNoNegotiationNeeded(t, pc1); }, "restartIce() works in initial have-local-offer"); @@ -177,15 +202,17 @@ await pc1.setRemoteDescription(pc2.localDescription); pc1.restartIce(); await pc2.setRemoteDescription(await pc1.createAnswer()); + const negotiationNeededPromise = + new Promise(r => pc1.onnegotiationneeded = r); await pc1.setLocalDescription(pc2.remoteDescription); // End on pc1. No race - assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1"); - assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2"); - await new Promise(r => pc1.onnegotiationneeded = r); + assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1"); + assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2"); + await negotiationNeededPromise; await doSignalingHandshakeEndOnFirst(pc1, pc2); const [newUfrag1] = getUfrags(pc1.localDescription); const [newUfrag2] = getUfrags(pc2.localDescription); - assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); - assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); await assertNoNegotiationNeeded(t, pc1); }, "restartIce() works in have-remote-offer"); @@ -219,15 +246,17 @@ pc1.restartIce(); await new Promise(r => pc1.onnegotiationneeded = r); + const negotiationNeededPromise = + new Promise(r => pc1.onnegotiationneeded = r); await doSignalingHandshakeEndOnSecond(pc2, pc1); - assert_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "nothing yet 1"); - assert_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "nothing yet 2"); - await new Promise(r => pc1.onnegotiationneeded = r); + assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "nothing yet 1"); + assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "nothing yet 2"); + await negotiationNeededPromise; await doSignalingHandshakeEndOnFirst(pc1, pc2); const [newUfrag1] = getUfrags(pc1.localDescription); const [newUfrag2] = getUfrags(pc2.localDescription); - assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); - assert_not_equals(newUfrag2, oldUfrag2, "ufrag 2 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); + assert_ufrags_not_equals(newUfrag2, oldUfrag2, "ufrag 2 changed"); await assertNoNegotiationNeeded(t, pc1); }, "restartIce() survives remote offer"); @@ -250,13 +279,13 @@ await doSignalingHandshakeEndOnSecond(pc2, pc1); const [newUfrag1] = getUfrags(pc1.localDescription); const [newUfrag2] = getUfrags(pc2.localDescription); - assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); - assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); await assertNoNegotiationNeeded(t, pc1); await doSignalingHandshakeEndOnFirst(pc1, pc2); - assert_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1"); - assert_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2"); + assert_ufrags_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1"); + assert_ufrags_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2"); await assertNoNegotiationNeeded(t, pc1); }, "restartIce() is satisfied by remote ICE restart"); @@ -281,8 +310,8 @@ await pc1.setRemoteDescription(pc2.localDescription); const [newUfrag1] = getUfrags(pc1.localDescription); const [newUfrag2] = getUfrags(pc2.localDescription); - assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); - assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); await assertNoNegotiationNeeded(t, pc1); }, "restartIce() trumps {iceRestart: false}"); @@ -302,13 +331,15 @@ pc1.restartIce(); await new Promise(r => pc1.onnegotiationneeded = r); await pc1.setLocalDescription(await pc1.createOffer()); + const negotiationNeededPromise = + new Promise(r => pc1.onnegotiationneeded = r); await pc1.setLocalDescription({type: "rollback"}); - await new Promise(r => pc1.onnegotiationneeded = r); + await negotiationNeededPromise; await doSignalingHandshakeEndOnFirst(pc1, pc2); const [newUfrag1] = getUfrags(pc1.localDescription); const [newUfrag2] = getUfrags(pc2.localDescription); - assert_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); - assert_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed"); + assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed"); await assertNoNegotiationNeeded(t, pc1); }, "restartIce() survives rollback"); @@ -340,21 +371,23 @@ sdp = sdp.replace(getPwds({sdp})[0], oldPwds2[0]); const newUfrags2 = getUfrags({sdp}); const newPwds2 = getPwds({sdp}); - assert_equals(newUfrags2[0], oldUfrags2[0], "control ufrag match"); - assert_equals(newPwds2[0], oldPwds2[0], "control pwd match"); - assert_not_equals(newUfrags2[1], oldUfrags2[1], "control ufrag non-match"); - assert_not_equals(newPwds2[1], oldPwds2[1], "control pwd non-match"); + assert_ufrags_equals(newUfrags2[0], oldUfrags2[0], "control ufrag match"); + assert_ufrags_equals(newPwds2[0], oldPwds2[0], "control pwd match"); + assert_ufrags_not_equals(newUfrags2[1], oldUfrags2[1], "control ufrag non-match"); + assert_ufrags_not_equals(newPwds2[1], oldPwds2[1], "control pwd non-match"); await pc1.setRemoteDescription({type, sdp}); } + const negotiationNeededPromise = + new Promise(r => pc1.onnegotiationneeded = r); await pc1.setLocalDescription(await pc1.createAnswer()); const newUfrags1 = getUfrags(pc1.localDescription); - assert_equals(newUfrags1[0], oldUfrags1[0], "Unchanged 1"); - assert_not_equals(newUfrags1[1], oldUfrags1[1], "Restarted 2"); - await new Promise(r => pc1.onnegotiationneeded = r); + assert_ufrags_equals(newUfrags1[0], oldUfrags1[0], "Unchanged 1"); + assert_ufrags_not_equals(newUfrags1[1], oldUfrags1[1], "Restarted 2"); + await negotiationNeededPromise; await pc1.setLocalDescription(await pc1.createOffer()); const newestUfrags1 = getUfrags(pc1.localDescription); - assert_not_equals(newestUfrags1[0], oldUfrag1[0], "Restarted 1"); - assert_not_equals(newestUfrags1[1], oldUfrag1[1], "Restarted 2"); + assert_ufrags_not_equals(newestUfrags1[0], oldUfrags1[0], "Restarted 1"); + assert_ufrags_not_equals(newestUfrags1[1], oldUfrags1[1], "Restarted 2"); await assertNoNegotiationNeeded(t, pc1); }, "restartIce() survives remote offer containing partial restart");
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt index 1f26f0d..2671b88 100644 --- a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt +++ b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 508 tests; 468 PASS, 40 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 508 tests; 470 PASS, 38 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS Test driver for asyncInitCertificate PASS Test driver for asyncInitTransports @@ -33,7 +33,7 @@ PASS RTCPeerConnection interface: attribute iceConnectionState PASS RTCPeerConnection interface: attribute connectionState FAIL RTCPeerConnection interface: attribute canTrickleIceCandidates assert_true: The prototype object must have a property "canTrickleIceCandidates" expected true got false -FAIL RTCPeerConnection interface: operation restartIce() assert_own_property: interface prototype object missing non-static operation expected property "restartIce" missing +PASS RTCPeerConnection interface: operation restartIce() FAIL RTCPeerConnection interface: operation getDefaultIceServers() assert_own_property: interface object missing static operation expected property "getDefaultIceServers" missing PASS RTCPeerConnection interface: operation getConfiguration() PASS RTCPeerConnection interface: operation setConfiguration(RTCConfiguration) @@ -86,7 +86,7 @@ PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "iceConnectionState" with the proper type PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "connectionState" with the proper type FAIL RTCPeerConnection interface: new RTCPeerConnection() must inherit property "canTrickleIceCandidates" with the proper type assert_inherits: property "canTrickleIceCandidates" not found in prototype chain -FAIL RTCPeerConnection interface: new RTCPeerConnection() must inherit property "restartIce()" with the proper type assert_inherits: property "restartIce" not found in prototype chain +PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "restartIce()" with the proper type PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "getDefaultIceServers()" with the proper type PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "getConfiguration()" with the proper type PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "setConfiguration(RTCConfiguration)" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_util.js b/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_util.js index d75e5c7..022aca8c 100644 --- a/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_util.js +++ b/third_party/blink/web_tests/external/wpt/webxr/resources/webxr_util.js
@@ -123,7 +123,7 @@ callback(window.XRCoordinateSystemEvent, 'XRCoordinateSystemEvent'); } -// Code for loading test api in chromium. +// Code for loading test API in Chromium. let loadChromiumResources = Promise.resolve().then(() => { if (!('MojoInterfaceInterceptor' in self)) { // Do nothing on non-Chromium-based browsers or when the Mojo bindings are @@ -131,26 +131,38 @@ return; } + let chromiumResources = [ + '/gen/layout_test_data/mojo/public/js/mojo_bindings.js', + '/gen/mojo/public/mojom/base/time.mojom.js', + '/gen/gpu/ipc/common/mailbox_holder.mojom.js', + '/gen/gpu/ipc/common/sync_token.mojom.js', + '/gen/ui/display/mojom/display.mojom.js', + '/gen/ui/gfx/geometry/mojo/geometry.mojom.js', + '/gen/ui/gfx/mojo/gpu_fence_handle.mojom.js', + '/gen/ui/gfx/mojo/transform.mojom.js', + '/gen/device/vr/public/mojom/vr_service.mojom.js', + '/resources/chromium/webxr-test.js', + '/resources/testdriver.js', + '/resources/testdriver-vendor.js', + ]; + + // This infrastructure is also used by Chromium-specific internal tests that + // may need additional resources (e.g. internal API extensions), this allows + // those tests to rely on this infrastructure while ensuring that no tests + // make it into public WPTs that rely on APIs outside of the webxr test API. + if (typeof(additionalChromiumResources) !== 'undefined') { + chromiumResources = chromiumResources.concat(additionalChromiumResources); + } + let chain = Promise.resolve(); - ['/gen/layout_test_data/mojo/public/js/mojo_bindings.js', - '/gen/mojo/public/mojom/base/time.mojom.js', - '/gen/gpu/ipc/common/mailbox_holder.mojom.js', - '/gen/gpu/ipc/common/sync_token.mojom.js', - '/gen/ui/display/mojom/display.mojom.js', - '/gen/ui/gfx/geometry/mojo/geometry.mojom.js', - '/gen/ui/gfx/mojo/gpu_fence_handle.mojom.js', - '/gen/ui/gfx/mojo/transform.mojom.js', - '/gen/device/vr/public/mojom/vr_service.mojom.js', - '/resources/chromium/webxr-test.js', '/resources/testdriver.js', - '/resources/testdriver-vendor.js', - ].forEach(path => { - let script = document.createElement('script'); - script.src = path; - script.async = false; - chain = chain.then(() => new Promise(resolve => { - script.onload = () => resolve(); - })); - document.head.appendChild(script); + chromiumResources.forEach(path => { + let script = document.createElement('script'); + script.src = path; + script.async = false; + chain = chain.then(() => new Promise(resolve => { + script.onload = () => resolve(); + })); + document.head.appendChild(script); }); return chain;
diff --git a/third_party/blink/web_tests/fast/shapedetection/shapedetection-creation.html b/third_party/blink/web_tests/fast/shapedetection/shapedetection-creation.html index a8894fb..641c6761 100644 --- a/third_party/blink/web_tests/fast/shapedetection/shapedetection-creation.html +++ b/third_party/blink/web_tests/fast/shapedetection/shapedetection-creation.html
@@ -3,12 +3,6 @@ <script src=../../resources/testharnessreport.js></script> <script> -// This test verifies that DetectedText can be created -test(function() { - var detectedText = new DetectedText(); - assert_true(detectedText instanceof DetectedText); -}, 'DetectedText instance can be created.'); - // This test verifies that TextDetector can be created test(function() { var textDetector = new TextDetector();
diff --git a/third_party/blink/web_tests/http/tests/content_index/content-index.html b/third_party/blink/web_tests/http/tests/content_index/content-index.html index 7816dc4..2649c0c 100644 --- a/third_party/blink/web_tests/http/tests/content_index/content-index.html +++ b/third_party/blink/web_tests/http/tests/content_index/content-index.html
@@ -111,4 +111,36 @@ }, 'index.delete works on invalid ID.'); +contentIndexTest(async (t, index) => { + // Register an entry. + await index.add(createDescription({id: 'my-id'})); + + // Simulate a user deleting it. + testRunner.simulateWebContentIndexDelete('my-id'); + + const swMessage = await waitForMessageFromServiceWorker(); + assert_equals(swMessage, 'my-id'); + + // Make sure it is actually deleted. + const descriptions = await index.getDescriptions(); + assert_equals(descriptions.length, 0); + +}, 'Fire contentdelete event on user intiated content deletion.'); + +contentIndexTest(async (t, index) => { + // Register an entry. + await index.add(createDescription({id: 'register-again'})); + + // Simulate a user deleting it. + testRunner.simulateWebContentIndexDelete('register-again'); + + const swMessage = await waitForMessageFromServiceWorker(); + assert_equals(swMessage, 'Failed to add description due to I/O error.'); + + // Make sure it is actually deleted and no new content was added. + const descriptions = await index.getDescriptions(); + assert_equals(descriptions.length, 0); + +}, 'Content cannot be registered while contentdelete event is firing.'); + </script>
diff --git a/third_party/blink/web_tests/http/tests/content_index/resources.js b/third_party/blink/web_tests/http/tests/content_index/resources.js index 500b0e06..5e1777d9 100644 --- a/third_party/blink/web_tests/http/tests/content_index/resources.js +++ b/third_party/blink/web_tests/http/tests/content_index/resources.js
@@ -4,8 +4,8 @@ 'use strict'; -const swUrl = '/resources/empty-worker.js'; -const scope = '/resources/'; +const swUrl = 'resources/sw.js'; +const scope = 'resources/'; async function expectTypeErrorWithMessage(promise, message) { try { @@ -34,3 +34,14 @@ return func(t, registration.index); }, description); } + +async function waitForMessageFromServiceWorker() { + return await new Promise(resolve => { + const listener = event => { + navigator.serviceWorker.removeEventListener('message', listener); + resolve(event.data); + }; + + navigator.serviceWorker.addEventListener('message', listener); + }); +}
diff --git a/third_party/blink/web_tests/http/tests/content_index/resources/sw.js b/third_party/blink/web_tests/http/tests/content_index/resources/sw.js new file mode 100644 index 0000000..66d939bb3 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/content_index/resources/sw.js
@@ -0,0 +1,33 @@ +// 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. + +async function postMessageToWindow(msg) { + for (const client of await clients.matchAll({includeUncontrolled: true})) + client.postMessage(msg); +} + +async function reregisterContent() { + try { + await self.registration.index.add({ + id: 'new id', + title: 'same title', + description: 'same description', + category: 'article', + iconUrl: '/resources/square.png', + launchUrl: 'resources/', + }); + await postMessageToWindow('Successfully registered'); + } catch (e) { + await postMessageToWindow(e.message); + } +} + +self.addEventListener('contentdelete', event => { + if (event.id === 'register-again') { + event.waitUntil(reregisterContent()); + return; + } + + event.waitUntil(postMessageToWindow(event.id)); +});
diff --git a/third_party/blink/web_tests/http/tests/cookie-store/delete-on-localhost.html b/third_party/blink/web_tests/http/tests/cookie-store/delete-on-localhost.html new file mode 100644 index 0000000..f60fd92 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/cookie-store/delete-on-localhost.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- NOTE: On http://localhost, the Cookie Store API is intended to behave the +same way as document.cookie. --> +<title>Cookie Store API: Delete a cookie on http://localhost</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +promise_test(async t => { + await cookieStore.set('cookie-name', 'cookie-value', { secure: false }); + t.add_cleanup(async () => { await cookieStore.delete('cookie-name'); }); + + await cookieStore.delete('cookie-name'); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie, null); +}, 'cookieStore.delete(name) deletes an insecure cookie with the given name'); + +promise_test(async t => { + await cookieStore.set('cookie-name', 'cookie-value', { secure: false }); + t.add_cleanup(async () => { await cookieStore.delete('cookie-name'); }); + + await cookieStore.delete({ name: 'cookie-name' }); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie, null); +}, `cookieStore.delete(options) deletes an insecure cookie with the given name + option`); + +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/cookie-store/set-on-localhost.html b/third_party/blink/web_tests/http/tests/cookie-store/set-on-localhost.html new file mode 100644 index 0000000..d8fffd9 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/cookie-store/set-on-localhost.html
@@ -0,0 +1,68 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<!-- NOTE: On http://localhost, the Cookie Store API is intended to behave the +same way as document.cookie. --> +<title>Cookie Store API: Set a cookie on http://localhost</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> + +promise_test(async t => { + await cookieStore.delete('cookie-name'); + + await cookieStore.set('cookie-name', 'cookie-value'); + t.add_cleanup(async () => { await cookieStore.delete('cookie-name'); }); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie.value, 'cookie-value'); + assert_equals(cookie.secure, false); +}, 'cookieStore.set(name, value) sets an insecure cookie'); + +promise_test(async t => { + await cookieStore.delete('cookie-name'); + + await cookieStore.set({ name: 'cookie-name', value: 'cookie-value' }); + t.add_cleanup(async () => { await cookieStore.delete('cookie-name'); }); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie.value, 'cookie-value'); + assert_equals(cookie.secure, false); +}, 'cookieStore.set(options) with no "secure" option sets an insecure cookie'); + +promise_test(async t => { + await cookieStore.delete('cookie-name'); + + await cookieStore.set({ + name: 'cookie-name', value: 'cookie-value', secure: false + }); + t.add_cleanup(async () => { await cookieStore.delete('cookie-name'); }); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie.value, 'cookie-value'); + assert_equals(cookie.secure, false); +}, 'cookieStore.set(options) with "secure: false" sets an insecure cookie'); + +promise_test(async t => { + await promise_rejects(t, new TypeError(), + cookieStore.set({ + name: 'cookie-name', value: 'cookie-value', secure: true + })); +}, 'cookieStore.set(options) with "secure: true" throws an exception'); + +promise_test(async t => { + await cookieStore.delete('cookie-name'); + + await cookieStore.set('cookie-name', 'cookie-value', { secure: false }); + t.add_cleanup(async () => { await cookieStore.delete('cookie-name'); }); + const cookie = await cookieStore.get('cookie-name'); + assert_equals(cookie.value, 'cookie-value'); + assert_equals(cookie.secure, false); +}, `cookieStore.set(name, value, options) with "secure: false" sets an insecure + cookie`); + +promise_test(async t => { + await cookieStore.delete('cookie-name'); + + await promise_rejects(t, new TypeError(), + cookieStore.set('cookie-name', 'cookie-value', { secure: true })); +}, `cookieStore.set(name, value, options) with "secure: true" throws an + exception`); + +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run-expected.txt b/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run-expected.txt index 9aef32f..459cca2 100644 --- a/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run-expected.txt
@@ -301,7 +301,7 @@ bypass: notApplicable canonical: notApplicable color-contrast: notApplicable -content-width: pass +content-width: flaky critical-request-chains: notApplicable custom-controls-labels: manual custom-controls-roles: manual
diff --git a/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run.js b/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run.js index 16c06e2..165f135 100644 --- a/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run.js +++ b/third_party/blink/web_tests/http/tests/devtools/audits/audits-successful-run.js
@@ -32,6 +32,8 @@ 'uses-responsive-images', 'uses-text-compression', 'uses-webp-images', + // content shell issues + 'content-width' // crbug.com/987722 ]; TestRunner.addResult('Tests that audits panel works.\n');
diff --git a/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-javascript-expected.txt b/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-javascript-expected.txt index 222485f..dcfa09d0 100644 --- a/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-javascript-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-javascript-expected.txt
@@ -1,5 +1,15 @@ Tests that JavaScriptSourceSyntaxHighlighter detects the tokens. +1_23.45_67: cm-js-number +0xDEAD_c0de: cm-js-number +0o123_456: cm-js-number +0b1011_1101: cm-js-number +123_456: cm-js-number +.123_456e0_1: cm-js-number +1E+12_34: cm-js-number +123_456n: cm-js-number +window._abc: cm-js-variable, *, cm-js-property +window._for: cm-js-variable, *, cm-js-property return'foo';: cm-js-keyword, cm-js-string, * /\//g: cm-js-string-2 //ig';: cm-js-comment
diff --git a/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-javascript.js b/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-javascript.js index a508bf4d..cc2b29a 100644 --- a/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-javascript.js +++ b/third_party/blink/web_tests/http/tests/devtools/syntax-highlight-javascript.js
@@ -9,6 +9,16 @@ return TestRunner.dumpSyntaxHighlight(str, 'text/javascript'); } + dumpSyntaxHighlightJS('1_23.45_67'); + dumpSyntaxHighlightJS('0xDEAD_c0de'); + dumpSyntaxHighlightJS('0o123_456'); + dumpSyntaxHighlightJS('0b1011_1101'); + dumpSyntaxHighlightJS('123_456'); + dumpSyntaxHighlightJS('.123_456e0_1'); + dumpSyntaxHighlightJS('1E+12_34'); + dumpSyntaxHighlightJS('123_456n'); + dumpSyntaxHighlightJS('window._abc'); + dumpSyntaxHighlightJS('window._for'); dumpSyntaxHighlightJS('return\'foo\';'); dumpSyntaxHighlightJS('/\\\//g'); dumpSyntaxHighlightJS('//ig\';');
diff --git a/third_party/blink/web_tests/http/tests/misc/object-image-error-with-onload.html b/third_party/blink/web_tests/http/tests/misc/object-image-error-with-onload.html index c02914ab..cf8082b 100644 --- a/third_party/blink/web_tests/http/tests/misc/object-image-error-with-onload.html +++ b/third_party/blink/web_tests/http/tests/misc/object-image-error-with-onload.html
@@ -1,15 +1,22 @@ <html> -<script> - if (window.testRunner) { - testRunner.dumpAsText() - } -</script> <body> <p> Test for <i><a href="https://bugs.webkit.org/show_bug.cgi?id=19891">Bug https://bugs.webkit.org/show_bug.cgi?id=19891</a></i> Broken HTML object elements cause de-reference of pointer to freed memory </p> -<object data="this.object.does.not.exist.gif" codetype="image/gif" height="10"></object> +<object id=target codetype="image/gif" height="10"></object> Pass if there is no crash or ASSERT. + +<script> +const target = document.getElementById("target"); +if (window.testRunner) { + testRunner.dumpAsText(); + testRunner.waitUntilDone(); + target.onload = () => testRunner.notifyDone(); +} +// Ensure to install an onload handler before setting data to avoid +// cases where the event is fired before the handler is in place. +target.data = "this.object.does.not.exist.gif"; +</script> </body> </html>
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt index 2595679..75c4cd4f 100644 --- a/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt +++ b/third_party/blink/web_tests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -379,6 +379,24 @@ method constructor method contains method item +interface DetectedBarcode + attribute @@toStringTag + getter boundingBox + getter cornerPoints + getter format + getter rawValue + method constructor +interface DetectedFace + attribute @@toStringTag + getter boundingBox + getter landmarks + method constructor +interface DetectedText + attribute @@toStringTag + getter boundingBox + getter cornerPoints + getter rawValue + method constructor interface ErrorEvent : Event attribute @@toStringTag getter colno
diff --git a/third_party/blink/web_tests/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt b/third_party/blink/web_tests/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt new file mode 100644 index 0000000..4b8c234 --- /dev/null +++ b/third_party/blink/web_tests/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt
@@ -0,0 +1,34 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "drawsContent": false, + "backgroundColor": "#FFFFFF" + }, + { + "name": "Scrolling Layer", + "bounds": [785, 600], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [785, 656], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "VerticalScrollbar", + "rect": [353, 8, 15, 640], + "reason": "scroll control" + } + ] + }, + { + "name": "LayoutNGBlockFlow (sticky positioned) DIV id='sticky'", + "position": [8, 8], + "bounds": [345, 20] + } + ] +} +
diff --git a/third_party/blink/web_tests/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html b/third_party/blink/web_tests/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html new file mode 100644 index 0000000..0b8b7b24 --- /dev/null +++ b/third_party/blink/web_tests/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky.html
@@ -0,0 +1,58 @@ +<!DOCTYPE HTML> +<div id="parent1"> + <mat id="scroller"> + <div id="sticky">This should stay sticky</div> + <mat id="spacer"></mat> + </mat> +</div> + +<style> +#parent1 { + height: 640px; + width: 360px; + perspective: 10px; +} +#scroller { + display: block; + height: 640px; + width: 360px; + overflow: hidden auto; +} +#sticky { + position: sticky; + top: 0px; +} +#spacer { + display: block; + height: 2000px; +} +</style> + + +<script src="../../resources/text-based-repaint.js"></script> +<script> +function repaintTest() { + var scroller = document.getElementById("scroller"); + // See crbug/983209: keyboard or mouse wheel (not just setting scroll + // offset) was required to see this bug. + scrollerMidX = scroller.offsetLeft + scroller.offsetWidth / 2; + scrollerMidY = scroller.offsetTop + scroller.offsetHeight / 2; + const pointerActions = [{ + source: "touch", + actions: [ + { name: "pointerDown", x: scrollerMidX, y: scrollerMidY }, + { name: "pointerMove", x: scrollerMidX, y: scrollerMidY - 50 }, + { name: 'pause', duration: 100}, + { name: "pointerUp" }, + ], + }]; + if (window.chrome && chrome.gpuBenchmarking) { + chrome.gpuBenchmarking.pointerActionSequence(pointerActions, finishRepaintTest); + } else { + sticky.innerHTML = "This test requires gpuBenchmarking"; + finishRepaintTest(); + } +} +window.testIsAsync = true; +onload = runRepaintTest; +</script>
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt new file mode 100644 index 0000000..f9942e2 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt
@@ -0,0 +1,34 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "drawsContent": false, + "backgroundColor": "#FFFFFF" + }, + { + "name": "Scrolling Layer", + "bounds": [785, 600], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [785, 656], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "VerticalScrollbar", + "rect": [353, 8, 15, 640], + "reason": "scroll control" + } + ] + }, + { + "name": "LayoutNGBlockFlow (sticky positioned) DIV id='sticky'", + "position": [8, 8], + "bounds": [345, 18] + } + ] +} +
diff --git a/third_party/blink/web_tests/platform/mac/virtual/compositor_threaded_scrollbar_scrolling/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt b/third_party/blink/web_tests/platform/mac/virtual/compositor_threaded_scrollbar_scrolling/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt new file mode 100644 index 0000000..e45f5fa --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/compositor_threaded_scrollbar_scrolling/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt
@@ -0,0 +1,75 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "drawsContent": false, + "backgroundColor": "#FFFFFF" + }, + { + "name": "Scrolling Layer", + "bounds": [785, 600], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [785, 656], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutNGBlockFlow MAT id='scroller'", + "position": [8, 8], + "bounds": [360, 640] + }, + { + "name": "Scrolling Layer", + "position": [8, 8], + "bounds": [345, 640], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "position": [8, 8], + "bounds": [345, 2018], + "transform": 1 + }, + { + "name": "Overflow Controls Host Layer", + "position": [8, 8], + "bounds": [360, 640], + "drawsContent": false + }, + { + "name": "Vertical Scrollbar Layer", + "position": [353, 8], + "bounds": [15, 640], + "drawsContent": false, + "paintInvalidations": [ + { + "object": "Vertical Scrollbar Layer", + "rect": [0, 0, 15, 640], + "reason": "full layer" + } + ] + }, + { + "name": "LayoutNGBlockFlow (sticky positioned) DIV id='sticky'", + "position": [8, -27], + "bounds": [345, 18] + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, -35, 0, 1] + ], + "flattenInheritedTransform": false + } + ] +} +
diff --git a/third_party/blink/web_tests/svg/animations/resources/svglength-additive-by-5.svg b/third_party/blink/web_tests/svg/animations/resources/svglength-additive-by-5.svg deleted file mode 100644 index 365a2f8d..0000000 --- a/third_party/blink/web_tests/svg/animations/resources/svglength-additive-by-5.svg +++ /dev/null
@@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd"> -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> - -<!-- an1: Change width from 10 to 50 in 4s --> -<!-- an2: Change width from 10 to 100 in 4s starting at 5s --> -<rect width="10" height="100" fill="green"> - <animate id="an1" attributeType="XML" attributeName="width" fill="remove" by="40" begin="0s" dur="4s"/> - <animate id="an2" attributeType="XML" attributeName="width" additive="sum" fill="freeze" by="90" begin="5s" dur="4s"/> -</rect> - -</svg>
diff --git a/third_party/blink/web_tests/svg/animations/script-tests/svglength-additive-by-5.js b/third_party/blink/web_tests/svg/animations/script-tests/svglength-additive-by-5.js deleted file mode 100644 index f54b32fc..0000000 --- a/third_party/blink/web_tests/svg/animations/script-tests/svglength-additive-by-5.js +++ /dev/null
@@ -1,53 +0,0 @@ -description("This tests by-animations adding to previous underlying values"); -embedSVGTestCase("resources/svglength-additive-by-5.svg"); - -// Setup animation test -function sample1() { - shouldBeCloseEnough("rect.width.animVal.value", "10"); - shouldBe("rect.width.baseVal.value", "10"); -} - -function sample2() { - shouldBeCloseEnough("rect.width.animVal.value", "30"); - shouldBe("rect.width.baseVal.value", "10"); -} - -function sample3() { - shouldBeCloseEnough("rect.width.animVal.value", "50"); - shouldBe("rect.width.baseVal.value", "10"); -} - -function sample4() { - shouldBeCloseEnough("rect.width.animVal.value", "10"); - shouldBe("rect.width.baseVal.value", "10"); -} - -function sample5() { - shouldBeCloseEnough("rect.width.animVal.value", "55"); - shouldBe("rect.width.baseVal.value", "10"); -} - -function sample6() { - shouldBeCloseEnough("rect.width.animVal.value", "100"); - shouldBe("rect.width.baseVal.value", "10"); -} - -function executeTest() { - rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0]; - - const expectedValues = [ - // [animationId, time, sampleCallback] - ["an1", 0.0, sample1], - ["an1", 2.0, sample2], - ["an1", 3.999, sample3], - ["an1", 4.001, sample4], - ["an1", 7.0, sample5], - ["an1", 9.0, sample6], - ["an1", 60.0, sample6] - ]; - - runAnimationTest(expectedValues); -} - -window.animationStartsImmediately = true; -var successfullyParsed = true;
diff --git a/third_party/blink/web_tests/svg/animations/svglength-additive-by-5-expected.txt b/third_party/blink/web_tests/svg/animations/svglength-additive-by-5-expected.txt deleted file mode 100644 index 3bfde665..0000000 --- a/third_party/blink/web_tests/svg/animations/svglength-additive-by-5-expected.txt +++ /dev/null
@@ -1,24 +0,0 @@ -SVG 1.1 dynamic animation tests - -This tests by-animations adding to previous underlying values - -On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". - -PASS rect.width.animVal.value is 10 -PASS rect.width.baseVal.value is 10 -PASS rect.width.animVal.value is 30 -PASS rect.width.baseVal.value is 10 -PASS rect.width.animVal.value is 50 -PASS rect.width.baseVal.value is 10 -PASS rect.width.animVal.value is 10 -PASS rect.width.baseVal.value is 10 -PASS rect.width.animVal.value is 55 -PASS rect.width.baseVal.value is 10 -PASS rect.width.animVal.value is 100 -PASS rect.width.baseVal.value is 10 -PASS rect.width.animVal.value is 100 -PASS rect.width.baseVal.value is 10 -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/blink/web_tests/svg/animations/svglength-additive-by-5.html b/third_party/blink/web_tests/svg/animations/svglength-additive-by-5.html index a65814d..b155c45 100644 --- a/third_party/blink/web_tests/svg/animations/svglength-additive-by-5.html +++ b/third_party/blink/web_tests/svg/animations/svglength-additive-by-5.html
@@ -1,14 +1,65 @@ <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <html> -<head> -<script src="../../resources/js-test.js"></script> -<script src="resources/SVGTestCase.js"></script> -<script src="resources/SVGAnimationTestCase.js"></script> -</head> -<body onload="runSMILTest()"> -<h1>SVG 1.1 dynamic animation tests</h1> -<p id="description"></p> -<div id="console"></div> -<script src="script-tests/svglength-additive-by-5.js"></script> -</body> +<title>Test by-animations adding to previous underlying values</title> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="resources/SVGAnimationTestCase-testharness.js"></script> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> +<!-- an1: Change width from 10 to 50 in 4s --> +<!-- an2: Change width from 10 to 100 in 4s starting at 5s --> +<rect width="10" height="100" fill="green"> + <animate id="an1" attributeType="XML" attributeName="width" fill="remove" by="40" begin="0s" dur="4s"/> + <animate id="an2" attributeType="XML" attributeName="width" additive="sum" fill="freeze" by="90" begin="5s" dur="4s"/> +</rect> +</svg> +<script> +var rootSVGElement = document.querySelector("svg"); +var rect = rootSVGElement.ownerDocument.getElementsByTagName("rect")[0]; +var epsilon = 0.15; +// Setup animation test +function sample1() { + assert_approx_equals(rect.width.animVal.value, 10, epsilon, "1-1"); + assert_equals(rect.width.baseVal.value, 10, "1-2"); +} + +function sample2() { + assert_approx_equals(rect.width.animVal.value, 30, epsilon, "2-1"); + assert_equals(rect.width.baseVal.value, 10, "2-2"); +} + +function sample3() { + assert_approx_equals(rect.width.animVal.value, 50, epsilon, "3-1"); + assert_equals(rect.width.baseVal.value, 10, "3-2"); +} + +function sample4() { + assert_approx_equals(rect.width.animVal.value, 10, epsilon, "4-1"); + assert_equals(rect.width.baseVal.value, 10, "4-2"); +} + +function sample5() { + assert_approx_equals(rect.width.animVal.value, 55, epsilon, "5-1"); + assert_equals(rect.width.baseVal.value, 10, "5-2"); +} + +function sample6() { + console.log(rootSVGElement.getCurrentTime() + " - 6"); + assert_approx_equals(rect.width.animVal.value, 100, epsilon, "6-1"); + assert_equals(rect.width.baseVal.value, 10, "6-2"); +} + +smil_async_test(t => { + const expectedValues = [ + // [animationId, time, sampleCallback] + ["an1", 0.0, sample1], + ["an1", 2.0, sample2], + ["an1", 3.999, sample3], + ["an1", 4.001, sample4], + ["an1", 7.0, sample5], + ["an1", 9.0, sample6], + ["an1", 60.0, sample6] + ]; + runAnimationTest(t, expectedValues); +}); +</script> </html>
diff --git a/third_party/blink/web_tests/virtual/cache-storage-parallel/external/wpt/service-workers/README.txt b/third_party/blink/web_tests/virtual/cache-storage-parallel/external/wpt/service-workers/README.txt new file mode 100644 index 0000000..8e43317 --- /dev/null +++ b/third_party/blink/web_tests/virtual/cache-storage-parallel/external/wpt/service-workers/README.txt
@@ -0,0 +1,4 @@ +This suite runs the ServiceWorker and CacheStorage tests with the +CacheStorageParallelOps feature enabled and set to 64 maximum shared +operations. This makes cache_storage execute read operations in +parallel.
diff --git a/third_party/blink/web_tests/virtual/compositor_threaded_scrollbar_scrolling/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt b/third_party/blink/web_tests/virtual/compositor_threaded_scrollbar_scrolling/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt new file mode 100644 index 0000000..10168a5 --- /dev/null +++ b/third_party/blink/web_tests/virtual/compositor_threaded_scrollbar_scrolling/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt
@@ -0,0 +1,75 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "drawsContent": false, + "backgroundColor": "#FFFFFF" + }, + { + "name": "Scrolling Layer", + "bounds": [785, 600], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [785, 656], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF" + }, + { + "name": "LayoutNGBlockFlow MAT id='scroller'", + "position": [8, 8], + "bounds": [360, 640] + }, + { + "name": "Scrolling Layer", + "position": [8, 8], + "bounds": [345, 640], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "position": [8, 8], + "bounds": [345, 2020], + "transform": 1 + }, + { + "name": "Overflow Controls Host Layer", + "position": [8, 8], + "bounds": [360, 640], + "drawsContent": false + }, + { + "name": "Vertical Scrollbar Layer", + "position": [353, 8], + "bounds": [15, 640], + "drawsContent": false, + "paintInvalidations": [ + { + "object": "Vertical Scrollbar Layer", + "rect": [0, 0, 15, 640], + "reason": "full layer" + } + ] + }, + { + "name": "LayoutNGBlockFlow (sticky positioned) DIV id='sticky'", + "position": [8, -27], + "bounds": [345, 20] + } + ], + "transforms": [ + { + "id": 1, + "transform": [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, -35, 0, 1] + ], + "flattenInheritedTransform": false + } + ] +} +
diff --git a/third_party/blink/web_tests/virtual/disable-blink-gen-property-trees/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt b/third_party/blink/web_tests/virtual/disable-blink-gen-property-trees/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt new file mode 100644 index 0000000..caab7be --- /dev/null +++ b/third_party/blink/web_tests/virtual/disable-blink-gen-property-trees/paint/invalidation/scroll/sticky/invalidate-after-composited-scroll-with-sticky-expected.txt
@@ -0,0 +1,40 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "drawsContent": false, + "backgroundColor": "#FFFFFF" + }, + { + "name": "Scrolling Layer", + "bounds": [785, 600], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [785, 656], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "VerticalScrollbar", + "rect": [353, 8, 15, 640], + "reason": "scroll control" + } + ] + }, + { + "name": "Ancestor Clipping Layer", + "position": [8, 8], + "bounds": [345, 640], + "drawsContent": false + }, + { + "name": "LayoutNGBlockFlow (sticky positioned) DIV id='sticky'", + "position": [8, 8], + "bounds": [345, 20] + } + ] +} +
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt index cd80f071..4954018 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -59,6 +59,7 @@ property dir property dispatchEvent property draggable + property elementTiming property enterKeyHint property firstChild property firstElementChild @@ -1165,6 +1166,7 @@ property createShadowRoot property dataset property dispatchEvent + property elementTiming property firstChild property firstElementChild property focus
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt index 62b0c9a..480db6b 100644 --- a/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1608,6 +1608,7 @@ getter clientLeft getter clientTop getter clientWidth + getter elementTiming getter firstElementChild getter id getter innerHTML @@ -1689,6 +1690,7 @@ method webkitRequestFullscreen setter classList setter className + setter elementTiming setter id setter innerHTML setter onbeforecopy @@ -3785,6 +3787,23 @@ getter target method constructor setter target +interface LargestContentfulPaint : PerformanceEntry + attribute @@toStringTag + getter element + getter id + getter loadTime + getter renderTime + getter size + getter url + method constructor + method toJSON +interface LayoutShift : PerformanceEntry + attribute @@toStringTag + getter hadRecentInput + getter lastInputTime + getter value + method constructor + method toJSON interface LinearAccelerationSensor : Accelerometer attribute @@toStringTag method constructor @@ -5108,6 +5127,7 @@ method getTransceivers method removeStream method removeTrack + method restartIce method setConfiguration method setLocalDescription method setRemoteDescription @@ -8723,6 +8743,7 @@ method getTransceivers method removeStream method removeTrack + method restartIce method setConfiguration method setLocalDescription method setRemoteDescription
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https-expected.txt new file mode 100644 index 0000000..c759bcb1 --- /dev/null +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https-expected.txt
@@ -0,0 +1,4 @@ +This is a testharness.js-based test. +FAIL Negotiation needed when returning to stable does not fire too early promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'." +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-restartIce.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-restartIce.https-expected.txt index 4f8c807f..b44cc1f 100644 --- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-restartIce.https-expected.txt +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-restartIce.https-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -FAIL restartIce() does not trigger negotiation ahead of initial negotiation promise_test: Unhandled rejection with value: object "TypeError: pc1.restartIce is not a function" +FAIL restartIce() does not trigger negotiation ahead of initial negotiation assert_equals: No negotiationneeded event expected (undefined) undefined but got (object) object "[object Event]" FAIL restartIce() has no effect on initial negotiation promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'." FAIL restartIce() fires negotiationneeded after initial negotiation promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'." FAIL restartIce() causes fresh ufrags promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'."
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt index 52843dc..55ead67 100644 --- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt +++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 508 tests; 399 PASS, 109 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 508 tests; 401 PASS, 107 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS idl_test setup PASS Test driver for asyncInitCertificate FAIL Test driver for asyncInitTransports assert_unreached: Failed to run asyncInitTransports: Error: assert_true: Expect pc.sctp to be instance of RTCSctpTransport expected true got false Reached unreachable code @@ -33,7 +33,7 @@ PASS RTCPeerConnection interface: attribute iceConnectionState PASS RTCPeerConnection interface: attribute connectionState FAIL RTCPeerConnection interface: attribute canTrickleIceCandidates assert_true: The prototype object must have a property "canTrickleIceCandidates" expected true got false -FAIL RTCPeerConnection interface: operation restartIce() assert_own_property: interface prototype object missing non-static operation expected property "restartIce" missing +PASS RTCPeerConnection interface: operation restartIce() FAIL RTCPeerConnection interface: operation getDefaultIceServers() assert_own_property: interface object missing static operation expected property "getDefaultIceServers" missing PASS RTCPeerConnection interface: operation getConfiguration() PASS RTCPeerConnection interface: operation setConfiguration(RTCConfiguration) @@ -86,7 +86,7 @@ PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "iceConnectionState" with the proper type PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "connectionState" with the proper type FAIL RTCPeerConnection interface: new RTCPeerConnection() must inherit property "canTrickleIceCandidates" with the proper type assert_inherits: property "canTrickleIceCandidates" not found in prototype chain -FAIL RTCPeerConnection interface: new RTCPeerConnection() must inherit property "restartIce()" with the proper type assert_inherits: property "restartIce" not found in prototype chain +PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "restartIce()" with the proper type PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "getDefaultIceServers()" with the proper type PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "getConfiguration()" with the proper type PASS RTCPeerConnection interface: new RTCPeerConnection() must inherit property "setConfiguration(RTCConfiguration)" with the proper type
diff --git a/third_party/blink/web_tests/vr/requestAnimationFrame_submitFrame_combinations.html b/third_party/blink/web_tests/vr/requestAnimationFrame_submitFrame_combinations.html index 912f14a..75b1c03 100644 --- a/third_party/blink/web_tests/vr/requestAnimationFrame_submitFrame_combinations.html +++ b/third_party/blink/web_tests/vr/requestAnimationFrame_submitFrame_combinations.html
@@ -5,7 +5,7 @@ <script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> <script> let legacy_vr_test = true; </script> <script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> +<script src="../wpt_internal/webxr/resources/xr-internal-device-mocking.js"></script> <script src="resources/vr-test-utils.js "></script> <canvas id="webgl-canvas"></canvas>
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt index b7b764be..3d94e252 100644 --- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -107,6 +107,7 @@ property dispatchEvent property displayLock property draggable + property elementTiming property enterKeyHint property firstChild property firstElementChild @@ -1294,6 +1295,7 @@ property dataset property dispatchEvent property displayLock + property elementTiming property firstChild property firstElementChild property focus
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt index 1a3665a..19883b5 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -341,6 +341,24 @@ [Worker] attribute PERSISTENT [Worker] attribute TEMPORARY [Worker] method constructor +[Worker] interface DetectedBarcode +[Worker] attribute @@toStringTag +[Worker] getter boundingBox +[Worker] getter cornerPoints +[Worker] getter format +[Worker] getter rawValue +[Worker] method constructor +[Worker] interface DetectedFace +[Worker] attribute @@toStringTag +[Worker] getter boundingBox +[Worker] getter landmarks +[Worker] method constructor +[Worker] interface DetectedText +[Worker] attribute @@toStringTag +[Worker] getter boundingBox +[Worker] getter cornerPoints +[Worker] getter rawValue +[Worker] method constructor [Worker] interface ErrorEvent : Event [Worker] attribute @@toStringTag [Worker] getter colno
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt index 1554f97..025c14d 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -1502,20 +1502,17 @@ getter format getter rawValue method constructor - method toJSON interface DetectedFace attribute @@toStringTag getter boundingBox getter landmarks method constructor - method toJSON interface DetectedText attribute @@toStringTag getter boundingBox getter cornerPoints getter rawValue method constructor - method toJSON interface DeviceMotionEvent : Event attribute @@toStringTag getter acceleration @@ -1993,6 +1990,7 @@ getter computedName getter computedRole getter displayLock + getter elementTiming getter firstElementChild getter id getter innerHTML @@ -2121,6 +2119,7 @@ setter ariaValueText setter classList setter className + setter elementTiming setter id setter innerHTML setter invisible @@ -5929,6 +5928,7 @@ method getTransceivers method removeStream method removeTrack + method restartIce method setConfiguration method setLocalDescription method setRemoteDescription @@ -10884,6 +10884,7 @@ method getTransceivers method removeStream method removeTrack + method restartIce method setConfiguration method setLocalDescription method setRemoteDescription
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt index 134ab1e9..cd3b593 100644 --- a/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt +++ b/third_party/blink/web_tests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -336,6 +336,24 @@ [Worker] method constructor [Worker] method contains [Worker] method item +[Worker] interface DetectedBarcode +[Worker] attribute @@toStringTag +[Worker] getter boundingBox +[Worker] getter cornerPoints +[Worker] getter format +[Worker] getter rawValue +[Worker] method constructor +[Worker] interface DetectedFace +[Worker] attribute @@toStringTag +[Worker] getter boundingBox +[Worker] getter landmarks +[Worker] method constructor +[Worker] interface DetectedText +[Worker] attribute @@toStringTag +[Worker] getter boundingBox +[Worker] getter cornerPoints +[Worker] getter rawValue +[Worker] method constructor [Worker] interface ErrorEvent : Event [Worker] attribute @@toStringTag [Worker] getter colno
diff --git a/third_party/blink/web_tests/wpt_internal/README b/third_party/blink/web_tests/wpt_internal/README index fe2ef6e8..9537fc8a 100644 --- a/third_party/blink/web_tests/wpt_internal/README +++ b/third_party/blink/web_tests/wpt_internal/README
@@ -2,6 +2,10 @@ features (except `wpt lint`) are enabled in this directory, including wptserve. This directory is mapped to wpt_internal/ on wptserve. +When including additional scripts from tests within this folder, the "root" +folder is "external/wpt" and paths should be relative to that. (E.g. "/resources +/testharness.js" will reference external/wpt/resources/testharness.js). + (*) "Internal" in the sense that tests are not synchronized with the WPT upstream (https://github.com/web-platform-tests/wpt) or other browser vendors.
diff --git a/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-positioned-element.html b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-positioned-element.html new file mode 100644 index 0000000..d8c8542 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/display-lock/lock-after-append/acquire-on-positioned-element.html
@@ -0,0 +1,44 @@ +<!doctype HTML> +<html class="reftest-wait"> +<meta charset="utf8"> +<title>Display Locking: acquire, commit</title> +<link rel="author" title="Vladimir Levin" href="mailto:vmpstr@chromium.org"> +<link rel="help" href="https://github.com/WICG/display-locking"> +<link rel="match" href="pass-ref.html"> +<script src="/common/reftest-wait.js"></script> + +<style> +#container { + contain: style layout; + width: 150px; + height: 150px; + + position: absolute; + top: 0px; + left: 0px; +} +</style> + +<div id="log"></div> +<div id="container"></div> + +<script> +function finishTest(status_string) { + if (document.getElementById("log").innerHTML === "") + document.getElementById("log").innerHTML = status_string; + takeScreenshot(); +} + +function runTest() { + const container = document.getElementById("container"); + container.displayLock.acquire({ timeout: Infinity }).then(() => { + const child = document.createElement("div"); + document.body.appendChild(child); + + finishTest("PASS"); + }); +} + +window.onload = runTest; +</script> +</html>
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/README.md b/third_party/blink/web_tests/wpt_internal/webxr/README.md new file mode 100644 index 0000000..80fdd20 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webxr/README.md
@@ -0,0 +1,19 @@ +# WebXR Internal Tests +In keeping with the requirements for the wpt\_internal tests, these tests +validate behavior that is not yet in a stable version of the spec (e.g. AR), +test Chrome specific constants, or test things specific to the blink/mojom +implementations. + +In order to reference xr-internal-device-mocking.js (or other additional files +that may be required for an internal test), the additionalChromiumResources +variable/array should be set before including webxr\_util.js, as webxr\_util.js +begins loading resources immediately. + +To port a test from wpt\_internal to external/wpt, the "/webxr/resources/..." +paths will need to be converted to "resources/..." paths, and any reliance on +internal APIs (i.e. any usage of additionalChromiumResources) should be removed. +Those should be the only changes required other than those required by wpt lint. + +For more details, please reference the wpt_internal [README] [WPT Readme]. + +[WPT Readme]: https://chromium.googlesource.com/chromium/src/+/HEAD/third_party/blink/web_tests/wpt_internal/README
diff --git a/third_party/blink/web_tests/xr/ar_hittest.html b/third_party/blink/web_tests/wpt_internal/webxr/ar_hittest.https.html similarity index 68% rename from third_party/blink/web_tests/xr/ar_hittest.html rename to third_party/blink/web_tests/wpt_internal/webxr/ar_hittest.https.html index 8225619..75dac3ac 100644 --- a/third_party/blink/web_tests/xr/ar_hittest.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/ar_hittest.https.html
@@ -1,15 +1,10 @@ <!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_asserts.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script>let additionalChromiumResources = ["resources/xr-internal-device-mocking.js"];</script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> +<script src="/webxr/resources/webxr_test_asserts.js"></script> <canvas /> <script>
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/events_deviceconnect.https.html b/third_party/blink/web_tests/wpt_internal/webxr/events_deviceconnect.https.html new file mode 100644 index 0000000..861a067 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webxr/events_deviceconnect.https.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> +<canvas /> +<script> +xr_promise_test("Test devicechange fires when devices are connected.", + (t) => { + let eventWatcher = new EventWatcher(t, navigator.xr, ["devicechange"]); + + // The event should fire when a listener is added (which EventWatcher does) + // even if the devices are not explicity queried with navigator.xr.requestDevice(). + // Note: This behaviour is chrome specific, the spec does not explicitly + // state when devicechange events should occur. + + let promise = eventWatcher.wait_for(["devicechange"]); + + // Timeout here is required because addEventListener sends a call to mojo to + // register the listener on the backend, which doesn't go through until the + // javascript pauses. + t.step_timeout(() => { + navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE); + }, 100); + + return promise; + +}); + +</script>
diff --git a/third_party/blink/web_tests/xr/navigator_xr_blocked_by_getVRDisplays.html b/third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_blocked_by_getVRDisplays.https.html similarity index 73% rename from third_party/blink/web_tests/xr/navigator_xr_blocked_by_getVRDisplays.html rename to third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_blocked_by_getVRDisplays.https.html index c64754f..4f0ee6c7 100644 --- a/third_party/blink/web_tests/xr/navigator_xr_blocked_by_getVRDisplays.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_blocked_by_getVRDisplays.https.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> <script> // This behavior is not in the webxr spec, so this is an internal-only test. promise_test((t) => navigator.getVRDisplays().then(() => {
diff --git a/third_party/blink/web_tests/xr/navigator_xr_blocks_getVRDisplays.html b/third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_blocks_getVRDisplays.https.html similarity index 76% rename from third_party/blink/web_tests/xr/navigator_xr_blocks_getVRDisplays.html rename to third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_blocks_getVRDisplays.https.html index 14fe210..1c712a8b 100644 --- a/third_party/blink/web_tests/xr/navigator_xr_blocks_getVRDisplays.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_blocks_getVRDisplays.https.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> <script> // This behavior is not in the webxr spec, so this is an internal-only test. promise_test((t) => navigator.xr.requestSession('immersive-vr').catch(() => {
diff --git a/third_party/blink/web_tests/xr/navigator_xr_detached.html b/third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_detached.https.html similarity index 85% rename from third_party/blink/web_tests/xr/navigator_xr_detached.html rename to third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_detached.https.html index dd8fc5e..78a78438 100644 --- a/third_party/blink/web_tests/xr/navigator_xr_detached.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_detached.https.html
@@ -2,8 +2,8 @@ <html> <head> <title>Detached use of navigator.xr</title> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> </head> <body> <iframe sandbox="allow-same-origin" id="subframe"></iframe>
diff --git a/third_party/blink/web_tests/xr/navigator_xr_early_detached.html b/third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_early_detached.https.html similarity index 84% rename from third_party/blink/web_tests/xr/navigator_xr_early_detached.html rename to third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_early_detached.https.html index 2d60c9c3..d4ecb91d 100644 --- a/third_party/blink/web_tests/xr/navigator_xr_early_detached.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/navigator_xr_early_detached.https.html
@@ -2,8 +2,8 @@ <html> <head> <title>Detached use of navigator.xr()</title> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> </head> <body> <iframe sandbox="allow-same-origin" id="subframe"></iframe>
diff --git a/third_party/blink/web_tests/xr/render_state_vertical_fov_inline.html b/third_party/blink/web_tests/wpt_internal/webxr/render_state_vertical_fov_inline.https.html similarity index 78% rename from third_party/blink/web_tests/xr/render_state_vertical_fov_inline.html rename to third_party/blink/web_tests/wpt_internal/webxr/render_state_vertical_fov_inline.https.html index 79e9097..08d2d9c 100644 --- a/third_party/blink/web_tests/xr/render_state_vertical_fov_inline.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/render_state_vertical_fov_inline.https.html
@@ -1,14 +1,8 @@ <!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> <canvas /> <script>
diff --git a/third_party/blink/web_tests/xr/resources/xr-internal-device-mocking.js b/third_party/blink/web_tests/wpt_internal/webxr/resources/xr-internal-device-mocking.js similarity index 100% rename from third_party/blink/web_tests/xr/resources/xr-internal-device-mocking.js rename to third_party/blink/web_tests/wpt_internal/webxr/resources/xr-internal-device-mocking.js
diff --git a/third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html b/third_party/blink/web_tests/wpt_internal/webxr/xrBoundedReferenceSpace_updates.https.html similarity index 81% rename from third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html rename to third_party/blink/web_tests/wpt_internal/webxr/xrBoundedReferenceSpace_updates.https.html index d65ab5bc..8660345 100644 --- a/third_party/blink/web_tests/xr/xrBoundedReferenceSpace_updates.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/xrBoundedReferenceSpace_updates.https.html
@@ -1,15 +1,10 @@ <!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_asserts.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script>let additionalChromiumResources = ["resources/xr-internal-device-mocking.js"];</script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> +<script src="/webxr/resources/webxr_test_asserts.js"></script> <canvas /> <script>
diff --git a/third_party/blink/web_tests/xr/xrFrame_getPose.html b/third_party/blink/web_tests/wpt_internal/webxr/xrFrame_getPose.https.html similarity index 64% rename from third_party/blink/web_tests/xr/xrFrame_getPose.html rename to third_party/blink/web_tests/wpt_internal/webxr/xrFrame_getPose.https.html index 7d2f8c3e..fef47a2 100644 --- a/third_party/blink/web_tests/xr/xrFrame_getPose.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/xrFrame_getPose.https.html
@@ -1,14 +1,8 @@ <!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> <canvas /> <script>
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/xrSession_dataProviderDisconnect_immersive.https.html b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_dataProviderDisconnect_immersive.https.html new file mode 100644 index 0000000..5c3acf7 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_dataProviderDisconnect_immersive.https.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script>let additionalChromiumResources = ["resources/xr-internal-device-mocking.js"];</script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> +<canvas /> + +<script> +// This test manipulates mojo directly to simulate some behavior, and as such is +// chromium specific. +let testName = "Immersive session ends if data provider disconnects."; +let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE; + +let testFunction = function(session, fakeDeviceController, t) { + return new Promise((resolve) => { + session.addEventListener('end', () => resolve()); + + // Request an animation frame to ensure that everything has time to get + // initialized/connected and avoid a race-condition failure with the data + // binding not being able to get closed. + session.requestAnimationFrame(() => { + fakeDeviceController.closeDataProvider(); + session.requestAnimationFrame(() => {}); + }); + }); +} + +xr_session_promise_test( + testName, testFunction, fakeDeviceInitParams, 'immersive-vr'); + +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/xrSession_dataProviderDisconnect_inline.https.html b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_dataProviderDisconnect_inline.https.html new file mode 100644 index 0000000..88c26d0 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_dataProviderDisconnect_inline.https.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script>let additionalChromiumResources = ["resources/xr-internal-device-mocking.js"];</script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> +<canvas /> + +<script> +// This test manipulates mojo directly to simulate some behavior, and as such is +// chromium specific. +let testName = "Inline session ends if magic window data provider disconnects."; +let fakeDeviceInitParams = VALID_NON_IMMERSIVE_DEVICE; + +let testFunction = function(session, fakeDeviceController, t) { + return new Promise((resolve) => { + session.addEventListener('end', () => resolve()); + + // Request an animation frame to ensure that everything has time to get + // initialized/connected and avoid a race-condition failure with the data + // binding not being able to get closed. + session.requestAnimationFrame(() => { + fakeDeviceController.closeDataProvider(); + session.requestAnimationFrame(() => {}); + }); + }); +} + +xr_session_promise_test( + testName, testFunction, fakeDeviceInitParams, 'inline'); + +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/xrSession_deviceDisconnect.https.html b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_deviceDisconnect.https.html new file mode 100644 index 0000000..a24332e --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_deviceDisconnect.https.html
@@ -0,0 +1,159 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script>let additionalChromiumResources = ["resources/xr-internal-device-mocking.js"];</script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> +<canvas /> + +<script> + +// This test manipulates mojo directly to simulate some behavior, and as such is +// chromium specific. +let testName = "Outstanding promises resolve appropriately if device disconencts"; + +let testFunction = function(t) { + // Expose the ability to get get the VRService and close the device on that VRService. + ChromeXRTest.prototype.getService = function() { + return this.mockVRService_; + } + + MockVRService.prototype.closeDevice = function() { + this.deviceBinding_.close(); + this.devicePtr_ = null; + } + + // Override the default implementations of requestSession and supportsSession + // from XRDevice so that we can choose to either return an answer immediately or + // return a promise that will never resolve to guarantee we have an outstanding + // promise on device disconnect. + MockVRService.prototype.requestSession = function(sessionOptions, was_activation) { + return new Promise((resolve,reject) => { }); + } + + let immediatelyResolveSupportsSession = true; + MockVRService.prototype.supportsSession = function(sessionOptions) { + if (immediatelyResolveSupportsSession) { + return Promise.resolve({ supportsSession: true }); + } + + return new Promise((resolve, reject) => { }); + } + + // Override the default requestDevice implementation so that we can fail if it's + // called when we don't expect it to be called (typically this would be because + // we aren't planning to force another device closure and would leave any + // outstanding promises unresolved, and thus cause the test to timeout), and so + // that we can store the device binding so that we can force it to be closed. + let failIfRequestDeviceCalled = false; + MockVRService.prototype.requestDevice = function() { + if (failIfRequestDeviceCalled) { + assert_unreached("requestDevice shouldn't be called at this time"); + } + + if (!this.devicePtr_) { + this.devicePtr_ = new device.mojom.XRDevicePtr(); + this.deviceBinding_ = new mojo.Binding( + device.mojom.XRDevice, this, mojo.makeRequest(this.devicePtr_)); + } + + return Promise.resolve({device: this.devicePtr_}); + } + + // Convenience methods to turn a resolve/reject into an appropraite string + // which Promise.All can check to tell us which methods failed. + // If we just let the promises assert, then Promise.all would only fail on the + // first assert. + let successMessage = "PASS"; + let failMessageStart = "FAIL: " + function WrapResolve(promise, name, errorMsg) { + return promise.then(() => { + return successMessage; + }, () => { + return failMessageStart + name + ": " + errorMsg; + }); + } + + function WrapReject(promise, name, errorMsg, errorType) { + return promise.then(() => { + return failMessageStart + name + ": " + errorMsg; + }, (err) => { + if (err.name === errorType) { + return successMessage; + } + + return failMessageStart + name + ": expected: " + errorType + " but got: " + err.name; + }); + } + + let validateDeviceDisconnectPromise = function() { + // Ensure that the state is properly set-up for our helper functions so that + // we can be called multiple times. + failIfRequestDeviceCalled = false; + immediatelyResolveSupportsSession = true; + + // Make a supports session call so that we can ensure that the underlying code + // has gotten a devicePtr set up. Note that inline, since it's always + // guaranteed doesn't ensure that the device is set up, where-as a call to see + // if we support immersive does require a device + return navigator.xr.supportsSession('immersive-vr').then(() => { + + // Cause supportsSession to stop returning and make future calls "hang"/ + immediatelyResolveSupportsSession = false; + + // We don't expect a new device to be requested, and if it is we aren't + // going to close it during this test, so any of our mocked calls will cause + // a timeout. + failIfRequestDeviceCalled = true; + let promises = []; + + // Note that inline session requests still call out through the device. + promises.push(WrapResolve(navigator.xr.requestSession('inline'), "Request Inline", + "Inline should always be available")); + promises.push(WrapReject(navigator.xr.requestSession('immersive-vr'), "Request Immersive", + "Immersive should be rejected once device is disconnected", "NotSupportedError")); + promises.push(WrapReject(navigator.xr.supportsSession('immersive-vr'), "Supports Immersive", + "Immersive should not be supported once device is disconnected", "NotSupportedError")); + + // Force the device disconnect, which should cause the promises to resolve. + navigator.xr.test.getService().closeDevice(); + + // Call this after we close the device, because we don't expect this to rely + // on (or request) the presence of a device. + promises.push(WrapResolve(navigator.xr.supportsSession('inline'), "Supports Inline", + "Inline support should be available without calling to a device")); + + return Promise.all(promises).then((results) => { + let error_messages = []; + for (let i = 0; i < results.length; i++) { + if (results[i] !== successMessage) { + error_messages.push(results[i]); + } + } + + if (error_messages.length !== 0) { + assert_unreached(error_messages); + } + }) + }); + } + + return new Promise((resolve) => { + // Give a user activation so that immersive requets don't get a security error. + navigator.xr.test.simulateUserActivation(() => { resolve(); }); + }) + .then(() => { + return validateDeviceDisconnectPromise() + }) + .then(() => { + + // Validate that even after disconnecting and resolving the promises, + // we can still request a new device, and that it will resolve any promises + // on it's disconnect. + return validateDeviceDisconnectPromise(); + }); +} + +xr_promise_test(testName, testFunction); + +</script>
diff --git a/third_party/blink/web_tests/xr/xrSession_environmentBlendMode.html b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_environmentBlendMode.https.html similarity index 68% rename from third_party/blink/web_tests/xr/xrSession_environmentBlendMode.html rename to third_party/blink/web_tests/wpt_internal/webxr/xrSession_environmentBlendMode.https.html index d58c3ce..170931b 100644 --- a/third_party/blink/web_tests/xr/xrSession_environmentBlendMode.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_environmentBlendMode.https.html
@@ -1,13 +1,8 @@ <!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> <canvas /> <script>
diff --git a/third_party/blink/web_tests/wpt_internal/webxr/xrSession_environmentProviderDisconnect.https.html b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_environmentProviderDisconnect.https.html new file mode 100644 index 0000000..3092c068 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/webxr/xrSession_environmentProviderDisconnect.https.html
@@ -0,0 +1,64 @@ +<!DOCTYPE html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script>let additionalChromiumResources = ["resources/xr-internal-device-mocking.js"];</script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> +<canvas /> + +<script> +// This test manipulates mojo directly to simulate some behavior, and as such is +// chromium specific. +let testName = "Outstanding promises get rejected if environmentProvider disconencts"; + +let fakeDeviceInitParams = { supportsImmersive: true, + views: VALID_VIEWS, + supportsEnvironmentIntegration: true }; + +let refSpace = undefined; + +let ray = new XRRay({x : 0.0, y : 0.0, z : 0.0}, {x : 1.0, y : 0.0, z: 0.0}); + +let testFunction = function(session, fakeDeviceController, t) { + // Override the xr-internal-device-mock for requestHitTest so that we can + // also return a promise that never resolves or rejects. + // This is so that we can simulate a disconnect while the mojo call is still + // outstanding. + let immediatelyResolveHitTest = true; + MockRuntime.prototype.requestHitTest = function(Ray) { + if (immediatelyResolveHitTest) { + var hit = new device.mojom.XRHitResult(); + hit.hitMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + hit_results = {results: [hit]}; + return Promise.resolve(hit_results); + } + + return new Promise((resolve,reject) => { }); + } + + return session.requestReferenceSpace('local') + .then((referenceSpace) => { + refSpace = referenceSpace; + + // Request a first hit test to ensure that all of the mojo connections are + // up and running. + return session.requestHitTest(ray, refSpace); + }) + .then(() => { + immediatelyResolveHitTest = false; + let hitTestPromise = session.requestHitTest(ray, refSpace); + fakeDeviceController.closeEnvironmentIntegrationProvider(); + return hitTestPromise; + }) + .then(() => { + assert_unreached("HitTestPromise should not resolve"); + }, + (err) => { + assert_equals(err.name, "InvalidStateError"); + }); +}; + +xr_session_promise_test( + testName, testFunction, fakeDeviceInitParams, 'immersive-ar'); + +</script>
diff --git a/third_party/blink/web_tests/xr/xrWebGLLayer_dirty_framebuffer.html b/third_party/blink/web_tests/wpt_internal/webxr/xrWebGLLayer_dirty_framebuffer.https.html similarity index 73% rename from third_party/blink/web_tests/xr/xrWebGLLayer_dirty_framebuffer.html rename to third_party/blink/web_tests/wpt_internal/webxr/xrWebGLLayer_dirty_framebuffer.https.html index 58e646fe..3c898c02 100644 --- a/third_party/blink/web_tests/xr/xrWebGLLayer_dirty_framebuffer.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/xrWebGLLayer_dirty_framebuffer.https.html
@@ -1,14 +1,9 @@ <!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script>let additionalChromiumResources = ["resources/xr-internal-device-mocking.js"];</script> +<script src="/webxr/resources/webxr_util.js"></script> +<script src="/webxr/resources/webxr_test_constants.js"></script> <canvas /> <script> @@ -50,7 +45,7 @@ gl.clear(gl.COLOR_BUFFER_BIT); // After the function returns ensure the frame was submitted. - window.setTimeout(() => { + t.step_timeout(() => { assert_equals(fakeDeviceController.getSubmitFrameCount(), 1); assert_equals(fakeDeviceController.getMissingFrameCount(), 2); // Finished test.
diff --git a/third_party/blink/web_tests/xr/xr_view_projection_detached.html b/third_party/blink/web_tests/wpt_internal/webxr/xr_view_projection_detached.https.html similarity index 69% rename from third_party/blink/web_tests/xr/xr_view_projection_detached.html rename to third_party/blink/web_tests/wpt_internal/webxr/xr_view_projection_detached.https.html index 9c6922b..02993cc3 100644 --- a/third_party/blink/web_tests/xr/xr_view_projection_detached.html +++ b/third_party/blink/web_tests/wpt_internal/webxr/xr_view_projection_detached.https.html
@@ -1,13 +1,6 @@ <!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> <canvas /> <script>
diff --git a/third_party/blink/web_tests/xr/README.md b/third_party/blink/web_tests/xr/README.md deleted file mode 100644 index 702300d2..0000000 --- a/third_party/blink/web_tests/xr/README.md +++ /dev/null
@@ -1,23 +0,0 @@ -# XR - -This directory contains tests that cannot be external/wpt/webxr tests due to one -one of the following reasons: - -1) The behavior they test is chrome-specific in some way -(e.g. intentionally non-compliant, specific decisions allowed by the spec, non-specced interactions, etc.) - -2) They test behavior and interactions with or exposed by the mojom layer that are not suitable to be shared. - -3) They rely on test methods that are not present in the webxr-test-api - -4) They test behavior that is not yet in the core spec. - -In the case of number 4 a crbug should be filed to update and move the test to be external once the spec has been updated. - -## XR/Resources -The resources folder contains the xr device mocking extensions that enable some internal tests. -Due to pathing limitations, the xr_session_promise_test implementation is also cloned into xr-test-utils - -Where possible, ensure that any updates to xr-test-utils can be mirrored into external/wpt/webxr/webxr_utils. -Any helper methods should also generally be added to the external resources, to ease the transition of temporarily-internal tests to be external. -
diff --git a/third_party/blink/web_tests/xr/events_deviceconnect.html b/third_party/blink/web_tests/xr/events_deviceconnect.html deleted file mode 100644 index 69b5960..0000000 --- a/third_party/blink/web_tests/xr/events_deviceconnect.html +++ /dev/null
@@ -1,34 +0,0 @@ -<!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> -<canvas /> -<script> -promise_test((t) => { - let eventWatcher = new EventWatcher(t, navigator.xr, ["devicechange"]); - - // The event should fire when a listener is added (which EventWatcher does) - // even if the devices are not explicity queried with navigator.xr.requestDevice(). - // Note: This behaviour is chrome specific, the spec does not explicitly - // state when devicechange events should occur. - - let promise = eventWatcher.wait_for(["devicechange"]); - - // Timeout here is required because addEventListener sends a call to mojo to - // register the listener on the backend, which doesn't go through until the - // javascript pauses. - setTimeout(() => { - navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE); - }, 0); - - return promise; - -}, "Test devicechange fires when devices are connected."); - -</script>
diff --git a/third_party/blink/web_tests/xr/resources/xr-test-utils.js b/third_party/blink/web_tests/xr/resources/xr-test-utils.js deleted file mode 100644 index 46026e7..0000000 --- a/third_party/blink/web_tests/xr/resources/xr-test-utils.js +++ /dev/null
@@ -1,77 +0,0 @@ -// func: A function that takes a session and optionally a test object and -// performs tests. If func returns a promise, test will only pass if the promise -// resolves. -function xr_session_promise_test( - name, func, deviceOptions, sessionMode, sessionInit, properties) { - let testSession = null; - let sessionObjects = {}; - - const webglCanvas = document.getElementsByTagName('canvas')[0]; - // We can't use assert_true here because it causes the wpt testharness to treat - // this as a test page and not as a test. - if (!webglCanvas) { - promise_test(async (t) => { - Promise.reject('xr_session_promise_test requires a canvas on the page!'); - }, name, properties); - } - let gl = webglCanvas.getContext('webgl', {alpha: false, antialias: false}); - sessionObjects.gl = gl; - promise_test((t) => { - let fakeDeviceController; - - // Ensure that any pending sessions are ended and devices are - // disconnected when done. This needs to use a cleanup function to - // ensure proper sequencing. If this were done in a .then() for the - // success case, a test that expected failure would already be marked - // done at the time that runs, and the shutdown would interfere with - // the next test which may have started already. - t.add_cleanup(async() => { - if (testSession) { - // TODO(bajones): Throwing an error when a session is - // already ended is not defined by the spec. This - // should be defined or removed. - await testSession.end().catch(() => {}); - } - - await navigator.xr.test.disconnectAllDevices(); - }); - - return navigator.xr.test.simulateDeviceConnection(deviceOptions) - .then((controller) => { - fakeDeviceController = controller; - if (gl) { - return gl.makeXRCompatible().then( - () => Promise.resolve()); - } else { - return Promise.resolve(); - } - }) - .then(() => new Promise((resolve, reject) => { - // Perform the session request in a user gesture. - navigator.xr.test.simulateUserActivation(() => { - navigator.xr.requestSession(sessionMode, sessionInit || {}) - .then((session) => { - testSession = session; - session.mode = sessionMode; - let glLayer = new XRWebGLLayer(session, gl, { - compositionDisabled: session.mode == 'inline' - }); - sessionObjects.glLayer = glLayer; - // Session must have a baseLayer or frame requests - // will be ignored. - session.updateRenderState({ - baseLayer: glLayer - }); - resolve(func(session, fakeDeviceController, t, sessionObjects)); - }) - .catch((err) => { - reject('Session with params ' + - JSON.stringify(sessionMode) + - ' was rejected on device ' + - JSON.stringify(fakeDeviceInit) + - ' with error: ' + err); - }); - }); - })); - }, name, properties); -}
diff --git a/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_immersive.html b/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_immersive.html deleted file mode 100644 index 67e1a1e..0000000 --- a/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_immersive.html +++ /dev/null
@@ -1,38 +0,0 @@ -<!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> -<script src="../xr/resources/test-constants.js"></script> -<canvas /> - -<script> -// This test manipulates mojo directly to simulate some behavior, and as such is -// chromium specific. -let testName = "Immersive session ends if data provider disconnects."; -let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE; - -let testFunction = function(session, fakeDeviceController, t) { - return new Promise((resolve) => { - session.addEventListener('end', () => resolve()); - - // Request an animation frame to ensure that everything has time to get - // initialized/connected and avoid a race-condition failure with the data - // binding not being able to get closed. - session.requestAnimationFrame(() => { - fakeDeviceController.closeDataProvider(); - session.requestAnimationFrame(() => {}); - }); - }); -} - -xr_session_promise_test( - testName, testFunction, fakeDeviceInitParams, 'immersive-vr'); - -</script>
diff --git a/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_inline.html b/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_inline.html deleted file mode 100644 index 92d0b384..0000000 --- a/third_party/blink/web_tests/xr/xrSession_dataProviderDisconnect_inline.html +++ /dev/null
@@ -1,38 +0,0 @@ -<!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> -<script src="../xr/resources/test-constants.js"></script> -<canvas /> - -<script> -// This test manipulates mojo directly to simulate some behavior, and as such is -// chromium specific. -let testName = "Inline session ends if magic window data provider disconnects."; -let fakeDeviceInitParams = VALID_NON_IMMERSIVE_DEVICE; - -let testFunction = function(session, fakeDeviceController, t) { - return new Promise((resolve) => { - session.addEventListener('end', () => resolve()); - - // Request an animation frame to ensure that everything has time to get - // initialized/connected and avoid a race-condition failure with the data - // binding not being able to get closed. - session.requestAnimationFrame(() => { - fakeDeviceController.closeDataProvider(); - session.requestAnimationFrame(() => {}); - }); - }); -} - -xr_session_promise_test( - testName, testFunction, fakeDeviceInitParams, 'inline'); - -</script>
diff --git a/third_party/blink/web_tests/xr/xrSession_deviceDisconnect.html b/third_party/blink/web_tests/xr/xrSession_deviceDisconnect.html deleted file mode 100644 index bdd4b38..0000000 --- a/third_party/blink/web_tests/xr/xrSession_deviceDisconnect.html +++ /dev/null
@@ -1,164 +0,0 @@ -<!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> -<script src="../xr/resources/test-constants.js"></script> -<canvas /> - -<script> - -// This test manipulates mojo directly to simulate some behavior, and as such is -// chromium specific. -let testName = "Outstanding promises resolve appropriately if device disconencts"; - -// Expose the ability to get get the VRService and close the device on that VRService. -ChromeXRTest.prototype.getService = function() { - return this.mockVRService_; -} - -MockVRService.prototype.closeDevice = function() { - this.deviceBinding_.close(); - this.devicePtr_ = null; -} - -// Override the default implementations of requestSession and supportsSession -// from XRDevice so that we can choose to either return an answer immediately or -// return a promise that will never resolve to guarantee we have an outstanding -// promise on device disconnect. -MockVRService.prototype.requestSession = function(sessionOptions, was_activation) { - return new Promise((resolve,reject) => { }); -} - -let immediatelyResolveSupportsSession = true; -MockVRService.prototype.supportsSession = function(sessionOptions) { - if (immediatelyResolveSupportsSession) { - return Promise.resolve({ supportsSession: true }); - } - - return new Promise((resolve, reject) => { }); -} - -// Override the default requestDevice implementation so that we can fail if it's -// called when we don't expect it to be called (typically this would be because -// we aren't planning to force another device closure and would leave any -// outstanding promises unresolved, and thus cause the test to timeout), and so -// that we can store the device binding so that we can force it to be closed. -let failIfRequestDeviceCalled = false; -MockVRService.prototype.requestDevice = function() { - if (failIfRequestDeviceCalled) { - assert_unreached("requestDevice shouldn't be called at this time"); - } - - if (!this.devicePtr_) { - this.devicePtr_ = new device.mojom.XRDevicePtr(); - this.deviceBinding_ = new mojo.Binding( - device.mojom.XRDevice, this, mojo.makeRequest(this.devicePtr_)); - } - - return Promise.resolve({device: this.devicePtr_}); -} - -// Convenience methods to turn a resolve/reject into an appropraite string -// which Promise.All can check to tell us which methods failed. -// If we just let the promises assert, then Promise.all would only fail on the -// first assert. -let successMessage = "PASS"; -let failMessageStart = "FAIL: " -function WrapResolve(promise, name, errorMsg) { - return promise.then(() => { - return successMessage; - }, () => { - return failMessageStart + name + ": " + errorMsg; - }); -} - -function WrapReject(promise, name, errorMsg, errorType) { - return promise.then(() => { - return failMessageStart + name + ": " + errorMsg; - }, (err) => { - if (err.name === errorType) { - return successMessage; - } - - return failMessageStart + name + ": expected: " + errorType + " but got: " + err.name; - }); -} - -let validateDeviceDisconnectPromise = function() { - // Ensure that the state is properly set-up for our helper functions so that - // we can be called multiple times. - failIfRequestDeviceCalled = false; - immediatelyResolveSupportsSession = true; - - // Make a supports session call so that we can ensure that the underlying code - // has gotten a devicePtr set up. Note that inline, since it's always - // guaranteed doesn't ensure that the device is set up, where-as a call to see - // if we support immersive does require a device - return navigator.xr.supportsSession('immersive-vr').then(() => { - - // Cause supportsSession to stop returning and make future calls "hang"/ - immediatelyResolveSupportsSession = false; - - // We don't expect a new device to be requested, and if it is we aren't - // going to close it during this test, so any of our mocked calls will cause - // a timeout. - failIfRequestDeviceCalled = true; - let promises = []; - - // Note that inline session requests still call out through the device. - promises.push(WrapResolve(navigator.xr.requestSession('inline'), "Request Inline", - "Inline should always be available")); - promises.push(WrapReject(navigator.xr.requestSession('immersive-vr'), "Request Immersive", - "Immersive should be rejected once device is disconnected", "NotSupportedError")); - promises.push(WrapReject(navigator.xr.supportsSession('immersive-vr'), "Supports Immersive", - "Immersive should not be supported once device is disconnected", "NotSupportedError")); - - // Force the device disconnect, which should cause the promises to resolve. - navigator.xr.test.getService().closeDevice(); - - // Call this after we close the device, because we don't expect this to rely - // on (or request) the presence of a device. - promises.push(WrapResolve(navigator.xr.supportsSession('inline'), "Supports Inline", - "Inline support should be available without calling to a device")); - - return Promise.all(promises).then((results) => { - let error_messages = []; - for (let i = 0; i < results.length; i++) { - if (results[i] !== successMessage) { - error_messages.push(results[i]); - } - } - - if (error_messages.length !== 0) { - assert_unreached(error_messages); - } - }) - }); -} - -let testFunction = function(t) { - return new Promise((resolve) => { - // Give a user activation so that immersive requets don't get a security error. - navigator.xr.test.simulateUserActivation(() => { resolve(); }); - }) - .then(() => { - return validateDeviceDisconnectPromise() - }) - .then(() => { - - // Validate that even after disconnecting and resolving the promises, - // we can still request a new device, and that it will resolve any promises - // on it's disconnect. - return validateDeviceDisconnectPromise(); - }); -} - -promise_test(testFunction, testName); - -</script>
diff --git a/third_party/blink/web_tests/xr/xrSession_environmentProviderDisconnect.html b/third_party/blink/web_tests/xr/xrSession_environmentProviderDisconnect.html deleted file mode 100644 index ae9ca72..0000000 --- a/third_party/blink/web_tests/xr/xrSession_environmentProviderDisconnect.html +++ /dev/null
@@ -1,70 +0,0 @@ -<!DOCTYPE html> -<script src="../resources/testharness.js"></script> -<script src="../resources/testharnessreport.js"></script> -<script src="../resources/testdriver.js"></script> -<script src="../resources/testdriver-vendor.js"></script> -<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script> -<script src="file:///gen/device/vr/public/mojom/vr_service.mojom.js"></script> -<script src="../external/wpt/resources/chromium/webxr-test.js"></script> -<script src="../external/wpt/webxr/resources/webxr_test_constants.js"></script> -<script src="../xr/resources/xr-internal-device-mocking.js"></script> -<script src="../xr/resources/xr-test-utils.js"></script> -<script src="../xr/resources/test-constants.js"></script> -<canvas /> - -<script> -// This test manipulates mojo directly to simulate some behavior, and as such is -// chromium specific. -let testName = "Outstanding promises get rejected if environmentProvider disconencts"; - -let fakeDeviceInitParams = { supportsImmersive: true, - views: VALID_VIEWS, - supportsEnvironmentIntegration: true }; - -let refSpace = undefined; - -let ray = new XRRay({x : 0.0, y : 0.0, z : 0.0}, {x : 1.0, y : 0.0, z: 0.0}); - -// Override the xr-internal-device-mock for requestHitTest so that we can -// also return a promise that never resolves or rejects. -// This is so that we can simulate a disconnect while the mojo call is still -// outstanding. -let immediatelyResolveHitTest = true; -MockRuntime.prototype.requestHitTest = function(Ray) { - if (immediatelyResolveHitTest) { - var hit = new device.mojom.XRHitResult(); - hit.hitMatrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; - hit_results = {results: [hit]}; - return Promise.resolve(hit_results); - } - - return new Promise((resolve,reject) => { }); -} - -let testFunction = function(session, fakeDeviceController, t) { - return session.requestReferenceSpace('local') - .then((referenceSpace) => { - refSpace = referenceSpace; - - // Request a first hit test to ensure that all of the mojo connections are - // up and running. - return session.requestHitTest(ray, refSpace); - }) - .then(() => { - immediatelyResolveHitTest = false; - let hitTestPromise = session.requestHitTest(ray, refSpace); - fakeDeviceController.closeEnvironmentIntegrationProvider(); - return hitTestPromise; - }) - .then(() => { - assert_unreached("HitTestPromise should not resolve"); - }, - (err) => { - assert_equals(err.name, "InvalidStateError"); - }); -}; - -xr_session_promise_test( - testName, testFunction, fakeDeviceInitParams, 'immersive-ar'); - -</script>
diff --git a/third_party/libcxx-pretty-printers/README.chromium b/third_party/libcxx-pretty-printers/README.chromium index 332511d..30c2d47 100644 --- a/third_party/libcxx-pretty-printers/README.chromium +++ b/third_party/libcxx-pretty-printers/README.chromium
@@ -1,6 +1,6 @@ Name: libcxx-pretty-printers URL: https://github.com/koutheir/libcxx-pretty-printers -Version: 5c40997ea6850a11321907b4651954bcfa6a21c7 +Version: 9eb1bc3070a6560e388803af657b60015cfb440c License: GPL v3 License File: LICENSE Security Critical: no
diff --git a/third_party/libcxx-pretty-printers/printers.py b/third_party/libcxx-pretty-printers/printers.py index 7f06a759d..5d68550 100644 --- a/third_party/libcxx-pretty-printers/printers.py +++ b/third_party/libcxx-pretty-printers/printers.py
@@ -148,7 +148,7 @@ len = sl['__size_'] ptr = sl['__data_'] - return ''.join(chr(ptr[i]) for i in range(len)) + return u''.join(unichr(ptr[i]) for i in range(len)) def display_hint(self): return 'string'
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium index 4088419..2cf027d 100644 --- a/third_party/libvpx/README.chromium +++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@ License File: source/libvpx/LICENSE Security Critical: yes -Date: Monday July 15 2019 +Date: Tuesday July 23 2019 Branch: master -Commit: bb407a27b2e32f89f0e9eeee2bcd0aa9d5cfea3f +Commit: 18d309c12734d2f06d54ad1716e512153a13ab9d Description: Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h index abd9cbd..9c314978 100644 --- a/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/ios/arm-neon/vpx_dsp_rtcd.h
@@ -1347,6 +1347,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_neon +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h index abd9cbd..9c314978 100644 --- a/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/ios/arm64/vpx_dsp_rtcd.h
@@ -1347,6 +1347,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_neon +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h index 0f5ae3e..95df12a 100644 --- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_dsp_rtcd.h
@@ -1741,6 +1741,13 @@ int ref_stride, uint32_t* sad_array); +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_dsp_rtcd.h index 24f335a..71eb333 100644 --- a/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm-neon-highbd/vpx_dsp_rtcd.h
@@ -4047,6 +4047,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_neon +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h index abd9cbd..9c314978 100644 --- a/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_dsp_rtcd.h
@@ -1347,6 +1347,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_neon +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h index dc7b59b..792d50f 100644 --- a/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm/vpx_dsp_rtcd.h
@@ -870,6 +870,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_c +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/arm64-highbd/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm64-highbd/vpx_dsp_rtcd.h index 24f335a..71eb333 100644 --- a/third_party/libvpx/source/config/linux/arm64-highbd/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm64-highbd/vpx_dsp_rtcd.h
@@ -4047,6 +4047,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_neon +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h index abd9cbd..9c314978 100644 --- a/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/arm64/vpx_dsp_rtcd.h
@@ -1347,6 +1347,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_neon +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h index 7e5eb2cf..8ba4d880 100644 --- a/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
@@ -3155,6 +3155,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_c +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h index 472c624d..096e3a86 100644 --- a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
@@ -5856,6 +5856,22 @@ int ref_stride, uint32_t* sad_array); +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +void vpx_sad32x32x8_avx2(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +RTCD_EXTERN void (*vpx_sad32x32x8)(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr, @@ -7843,6 +7859,9 @@ vpx_sad32x32x4d = vpx_sad32x32x4d_sse2; if (flags & HAS_AVX2) vpx_sad32x32x4d = vpx_sad32x32x4d_avx2; + vpx_sad32x32x8 = vpx_sad32x32x8_c; + if (flags & HAS_AVX2) + vpx_sad32x32x8 = vpx_sad32x32x8_avx2; vpx_sad32x64 = vpx_sad32x64_sse2; if (flags & HAS_AVX2) vpx_sad32x64 = vpx_sad32x64_avx2;
diff --git a/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h index b406c88..63a0f75 100644 --- a/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/mips64el/vpx_dsp_rtcd.h
@@ -870,6 +870,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_c +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h index b406c88..63a0f75 100644 --- a/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/mipsel/vpx_dsp_rtcd.h
@@ -870,6 +870,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_c +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h index 7021eaa..ed632331 100644 --- a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
@@ -5933,6 +5933,22 @@ int ref_stride, uint32_t* sad_array); +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +void vpx_sad32x32x8_avx2(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +RTCD_EXTERN void (*vpx_sad32x32x8)(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr, @@ -7923,6 +7939,9 @@ vpx_sad32x32x4d = vpx_sad32x32x4d_sse2; if (flags & HAS_AVX2) vpx_sad32x32x4d = vpx_sad32x32x4d_avx2; + vpx_sad32x32x8 = vpx_sad32x32x8_c; + if (flags & HAS_AVX2) + vpx_sad32x32x8 = vpx_sad32x32x8_avx2; vpx_sad32x64 = vpx_sad32x64_sse2; if (flags & HAS_AVX2) vpx_sad32x64 = vpx_sad32x64_avx2;
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h index 472c624d..096e3a86 100644 --- a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
@@ -5856,6 +5856,22 @@ int ref_stride, uint32_t* sad_array); +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +void vpx_sad32x32x8_avx2(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +RTCD_EXTERN void (*vpx_sad32x32x8)(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr, @@ -7843,6 +7859,9 @@ vpx_sad32x32x4d = vpx_sad32x32x4d_sse2; if (flags & HAS_AVX2) vpx_sad32x32x4d = vpx_sad32x32x4d_avx2; + vpx_sad32x32x8 = vpx_sad32x32x8_c; + if (flags & HAS_AVX2) + vpx_sad32x32x8 = vpx_sad32x32x8_avx2; vpx_sad32x64 = vpx_sad32x64_sse2; if (flags & HAS_AVX2) vpx_sad32x64 = vpx_sad32x64_avx2;
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h index 7021eaa..ed632331 100644 --- a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
@@ -5933,6 +5933,22 @@ int ref_stride, uint32_t* sad_array); +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +void vpx_sad32x32x8_avx2(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +RTCD_EXTERN void (*vpx_sad32x32x8)(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr, @@ -7923,6 +7939,9 @@ vpx_sad32x32x4d = vpx_sad32x32x4d_sse2; if (flags & HAS_AVX2) vpx_sad32x32x4d = vpx_sad32x32x4d_avx2; + vpx_sad32x32x8 = vpx_sad32x32x8_c; + if (flags & HAS_AVX2) + vpx_sad32x32x8 = vpx_sad32x32x8_avx2; vpx_sad32x64 = vpx_sad32x64_sse2; if (flags & HAS_AVX2) vpx_sad32x64 = vpx_sad32x64_avx2;
diff --git a/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h index 7e5eb2cf..8ba4d880 100644 --- a/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
@@ -3155,6 +3155,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_c +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h index 225da6e..e481f5e 100644 --- a/third_party/libvpx/source/config/vpx_version.h +++ b/third_party/libvpx/source/config/vpx_version.h
@@ -1,8 +1,8 @@ // This file is generated. Do not edit. #define VERSION_MAJOR 1 #define VERSION_MINOR 8 -#define VERSION_PATCH 0 -#define VERSION_EXTRA "601-gbb407a27b2" +#define VERSION_PATCH 1 +#define VERSION_EXTRA "53-g18d309c127" #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH)) -#define VERSION_STRING_NOSP "v1.8.0-601-gbb407a27b2" -#define VERSION_STRING " v1.8.0-601-gbb407a27b2" +#define VERSION_STRING_NOSP "v1.8.1-53-g18d309c127" +#define VERSION_STRING " v1.8.1-53-g18d309c127"
diff --git a/third_party/libvpx/source/config/win/arm64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/arm64/vpx_dsp_rtcd.h index 24f335a..71eb333 100644 --- a/third_party/libvpx/source/config/win/arm64/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/win/arm64/vpx_dsp_rtcd.h
@@ -4047,6 +4047,13 @@ uint32_t* sad_array); #define vpx_sad32x32x4d vpx_sad32x32x4d_neon +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +#define vpx_sad32x32x8 vpx_sad32x32x8_c + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr,
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h index 472c624d..096e3a86 100644 --- a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
@@ -5856,6 +5856,22 @@ int ref_stride, uint32_t* sad_array); +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +void vpx_sad32x32x8_avx2(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +RTCD_EXTERN void (*vpx_sad32x32x8)(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr, @@ -7843,6 +7859,9 @@ vpx_sad32x32x4d = vpx_sad32x32x4d_sse2; if (flags & HAS_AVX2) vpx_sad32x32x4d = vpx_sad32x32x4d_avx2; + vpx_sad32x32x8 = vpx_sad32x32x8_c; + if (flags & HAS_AVX2) + vpx_sad32x32x8 = vpx_sad32x32x8_avx2; vpx_sad32x64 = vpx_sad32x64_sse2; if (flags & HAS_AVX2) vpx_sad32x64 = vpx_sad32x64_avx2;
diff --git a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h index 7021eaa..ed632331 100644 --- a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h +++ b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
@@ -5933,6 +5933,22 @@ int ref_stride, uint32_t* sad_array); +void vpx_sad32x32x8_c(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +void vpx_sad32x32x8_avx2(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); +RTCD_EXTERN void (*vpx_sad32x32x8)(const uint8_t* src_ptr, + int src_stride, + const uint8_t* ref_ptr, + int ref_stride, + uint32_t* sad_array); + unsigned int vpx_sad32x64_c(const uint8_t* src_ptr, int src_stride, const uint8_t* ref_ptr, @@ -7923,6 +7939,9 @@ vpx_sad32x32x4d = vpx_sad32x32x4d_sse2; if (flags & HAS_AVX2) vpx_sad32x32x4d = vpx_sad32x32x4d_avx2; + vpx_sad32x32x8 = vpx_sad32x32x8_c; + if (flags & HAS_AVX2) + vpx_sad32x32x8 = vpx_sad32x32x8_avx2; vpx_sad32x64 = vpx_sad32x64_sse2; if (flags & HAS_AVX2) vpx_sad32x64 = vpx_sad32x64_avx2;
diff --git a/third_party/netty4/OWNERS b/third_party/netty4/OWNERS index fb59c70..d314095 100644 --- a/third_party/netty4/OWNERS +++ b/third_party/netty4/OWNERS
@@ -1 +1,3 @@ file://net/OWNERS +# COMPONENT: Internals>Network>Library +# TEAM: net-dev@chromium.org
diff --git a/third_party/tcmalloc/chromium/src/base/basictypes.h b/third_party/tcmalloc/chromium/src/base/basictypes.h index 24a6a8a6..3bf59f4e 100644 --- a/third_party/tcmalloc/chromium/src/base/basictypes.h +++ b/third_party/tcmalloc/chromium/src/base/basictypes.h
@@ -200,7 +200,8 @@ # define ATTRIBUTE_UNUSED #endif -#if defined(HAVE___ATTRIBUTE__) && defined(HAVE_TLS) +#if defined(HAVE___ATTRIBUTE__) && defined(HAVE_TLS) && \ + !(defined(__GNUC__) && !defined(__clang__) && defined(__arm__)) #define ATTR_INITIAL_EXEC __attribute__ ((tls_model ("initial-exec"))) #else #define ATTR_INITIAL_EXEC
diff --git a/third_party/tcmalloc/chromium/src/heap-checker.cc b/third_party/tcmalloc/chromium/src/heap-checker.cc index 8e71f582..918194f2 100755 --- a/third_party/tcmalloc/chromium/src/heap-checker.cc +++ b/third_party/tcmalloc/chromium/src/heap-checker.cc
@@ -445,7 +445,8 @@ // the cost you can't dlopen this library. But dlopen on heap-checker // doesn't work anyway -- it must run before main -- so this is a good // trade-off. -# ifdef HAVE___ATTRIBUTE__ +# if defined(HAVE___ATTRIBUTE__) && \ + !(defined(__GNUC__) && !defined(__clang__) && defined(__arm__)) __attribute__ ((tls_model ("initial-exec"))) # endif ;
diff --git a/third_party/tcmalloc/gperftools-2.0/chromium/src/heap-checker.cc b/third_party/tcmalloc/gperftools-2.0/chromium/src/heap-checker.cc index 1400c8e..3da27ff 100644 --- a/third_party/tcmalloc/gperftools-2.0/chromium/src/heap-checker.cc +++ b/third_party/tcmalloc/gperftools-2.0/chromium/src/heap-checker.cc
@@ -448,7 +448,8 @@ // the cost you can't dlopen this library. But dlopen on heap-checker // doesn't work anyway -- it must run before main -- so this is a good // trade-off. -# ifdef HAVE___ATTRIBUTE__ +#if defined(HAVE___ATTRIBUTE__) && \ + !(defined(__GNUC__) && !defined(__clang__) && defined(__arm__)) __attribute__ ((tls_model ("initial-exec"))) # endif ;
diff --git a/third_party/tcmalloc/gperftools-2.0/chromium/src/thread_cache.h b/third_party/tcmalloc/gperftools-2.0/chromium/src/thread_cache.h index ba2f873..0397842 100644 --- a/third_party/tcmalloc/gperftools-2.0/chromium/src/thread_cache.h +++ b/third_party/tcmalloc/gperftools-2.0/chromium/src/thread_cache.h
@@ -272,7 +272,7 @@ // gcc has a problem with this tls model on arm. // See https://bugs.chromium.org/p/chromium/issues/detail?id=650137 #if defined(HAVE___ATTRIBUTE__) && !defined(PGO_GENERATE) && \ - !(!defined(__clang__) && defined(OS_CHROMEOS) && defined(__arm__)) + !(defined(__GNUC__) && !defined(__clang__) && defined(__arm__)) __attribute__ ((tls_model ("initial-exec"))) # endif ;
diff --git a/third_party/webxr_test_pages/webxr-samples/room-scale.html b/third_party/webxr_test_pages/webxr-samples/room-scale.html index f06dae7..b44e365 100644 --- a/third_party/webxr_test_pages/webxr-samples/room-scale.html +++ b/third_party/webxr_test_pages/webxr-samples/room-scale.html
@@ -69,8 +69,7 @@ // XR globals. let xrButton = null; - let xrImmersiveRefSpace = null; - let xrNonImmersiveRefSpace = null; + let refSpaces = {}; // WebGL scene globals. let gl = null; @@ -127,13 +126,22 @@ onResize(); renderer = new Renderer(gl); - scene.setRenderer(renderer); } + function updateBoundsRenderer(refSpace) { + if (!boundsRenderer) { + boundsRenderer = new BoundsRenderer(refSpace); + scene.addNode(boundsRenderer); + } else { + boundsRenderer.boundedRefSpace = refSpace; + } + } + function onSessionStarted(session) { if (!session.mode) session.mode = 'inline'; + session.ended = false; session.addEventListener('end', onSessionEnded); initGL(); @@ -147,13 +155,8 @@ // Attempt to get a 'bounded' reference space, which will align the // user's physical floor with Y=0 and provide boundaries that indicate // where the user can safely walk. - session.requestReferenceSpace({ type: 'bounded' }).then((refSpace) => { - if (!boundsRenderer) { - boundsRenderer = new BoundsRenderer(refSpace); - scene.addNode(boundsRenderer); - } else { - boundsRenderer.boundedRefSpace = refSpace; - } + session.requestReferenceSpace('bounded-floor').then((refSpace) => { + updateBoundsRenderer(refSpace); return refSpace; }).catch(() => { // If a bounded reference space isn't supported, fall back to a @@ -185,16 +188,31 @@ } }); }).then((refSpace) => { - if (session.mode.startsWith('immersive')) { - xrImmersiveRefSpace = refSpace; - } else { - xrNonImmersiveRefSpace = refSpace; - } - + refSpaces[session.mode] = refSpace; session.requestAnimationFrame(onXRFrame); + if (session.mode.startsWith('immersive') && !boundsRenderer) { + pollBounds(session); + } }); } + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + function pollBounds(session) { + if (session.mode.startsWith('immersive') && !session.ended) { + session.requestReferenceSpace('bounded-floor').then((space) => { + updateBoundsRenderer(space); + refSpaces[session.mode] = space; + console.log(space.boundsGeometry); + }).catch(() => { + console.log("Failed to get bounded reference space. Trying again in 1 second."); + sleep(1000).then(() => pollBounds(session)); + }); + } + } + function onEndSession(session) { session.end(); } @@ -203,14 +221,12 @@ if (event.session.mode.startsWith('immersive')) { xrButton.setSession(null); } + event.session.ended = true; } function onXRFrame(t, frame) { let session = frame.session; - let refSpace = session.mode.startsWith('immersive') ? - xrImmersiveRefSpace : - xrNonImmersiveRefSpace; - let pose = frame.getViewerPose(refSpace); + let pose = frame.getViewerPose(refSpaces[session.mode]); scene.startFrame();
diff --git a/third_party/win_build_output/mc/chrome/credential_provider/eventlog/gcp_eventlog_messages.h b/third_party/win_build_output/mc/chrome/credential_provider/eventlog/gcp_eventlog_messages.h index 6a45791..7f1f35b 100644 --- a/third_party/win_build_output/mc/chrome/credential_provider/eventlog/gcp_eventlog_messages.h +++ b/third_party/win_build_output/mc/chrome/credential_provider/eventlog/gcp_eventlog_messages.h
@@ -47,13 +47,13 @@ // -// MessageId: GCP_CATEGORY +// MessageId: GCPW_CATEGORY // // MessageText: // -// GCP Events +// GCPW Events // -#define GCP_CATEGORY ((WORD)0x00000001L) +#define GCPW_CATEGORY ((WORD)0x00000001L) // // MessageId: MSG_LOG_MESSAGE
diff --git a/third_party/zlib/patches/0000-build.patch b/third_party/zlib/patches/0000-build.patch index c27111d..b7c5996 100644 --- a/third_party/zlib/patches/0000-build.patch +++ b/third_party/zlib/patches/0000-build.patch
@@ -149,9 +149,17 @@ #ifndef ZCONF_H #define ZCONF_H ++/* ++ * This library is also built as a part of AOSP, which does not need to include ++ * chromeconf.h. This config does not want chromeconf.h, so it can set this ++ * macro to opt out. While this works today, there's no guarantee that building ++ * zlib outside of Chromium keeps working in the future. ++ */ ++#if !defined(CHROMIUM_ZLIB_NO_CHROMECONF) +/* This include does prefixing as below, but with an updated set of names. Also + * sets up export macros in component builds. */ +#include "chromeconf.h" ++#endif + /* * If you *really* need a unique prefix for all types and library functions,
diff --git a/third_party/zlib/zconf.h b/third_party/zlib/zconf.h index 1664387..2d1d03f 100644 --- a/third_party/zlib/zconf.h +++ b/third_party/zlib/zconf.h
@@ -10,9 +10,11 @@ /* * This library is also built as a part of AOSP, which does not need to include - * chromeconf.h. In that case, neither of these macros will be defined. + * chromeconf.h. This config does not want chromeconf.h, so it can set this + * macro to opt out. While this works today, there's no guarantee that building + * zlib outside of Chromium keeps working in the future. */ -#if defined(CHROMIUM_BUILD) || defined(GOOGLE_CHROME_BUILD) +#if !defined(CHROMIUM_ZLIB_NO_CHROMECONF) /* This include does prefixing as below, but with an updated set of names. Also * sets up export macros in component builds. */ #include "chromeconf.h"
diff --git a/tools/OWNERS b/tools/OWNERS index d771315..2f045af 100644 --- a/tools/OWNERS +++ b/tools/OWNERS
@@ -54,3 +54,6 @@ per-file sort-headers.py=satorux@chromium.org per-file sort-sources.py=satorux@chromium.org per-file yes_no.py=satorux@chromium.org + +per-file download_cros_provided_profile.py=gbiv@chromium.org +per-file download_cros_provided_profile.py=tcwang@chromium.org
diff --git a/tools/cfi/blacklist.txt b/tools/cfi/blacklist.txt index c2199d1..1adb46f5 100644 --- a/tools/cfi/blacklist.txt +++ b/tools/cfi/blacklist.txt
@@ -159,8 +159,6 @@ src:*ui/gl/gl_bindings_autogen_* src:*components/os_crypt/* -src:*chrome/browser/password_manager/native_backend_gnome_x.cc -src:*chrome/browser/password_manager/native_backend_libsecret* src:*content/browser/accessibility/browser_accessibility_auralinux.cc src:*ui/accessibility/platform/ax_platform_node_auralinux.cc
diff --git a/tools/chrome_proxy/webdriver/fallback.py b/tools/chrome_proxy/webdriver/fallback.py index c50d266..cf61ae51 100644 --- a/tools/chrome_proxy/webdriver/fallback.py +++ b/tools/chrome_proxy/webdriver/fallback.py
@@ -35,8 +35,8 @@ # Verify that DataReductionProxy.ProbeURL histogram has one entry in # FAILED_PROXY_DISABLED, which is bucket=1. histogram = test_driver.GetBrowserHistogram('DataReductionProxy.ProbeURL') - self.assertEqual(histogram['count'], 1) - self.assertEqual(histogram['buckets'][0]['low'], 1) + self.assertGreaterEqual(histogram['count'], 1) + self.assertGreaterEqual(histogram['buckets'][0]['low'], 1) for response in responses: self.assertHasProxyHeaders(response) # TODO(rajendrant): Fix the correct protocol received.
diff --git a/tools/download_cros_provided_profile.py b/tools/download_cros_provided_profile.py new file mode 100755 index 0000000..45755d2 --- /dev/null +++ b/tools/download_cros_provided_profile.py
@@ -0,0 +1,155 @@ +#!/usr/bin/python +# Copyright 2018 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""This script is used to update our local profiles (AFDO or orderfiles) + +This uses profiles of Chrome, or orderfiles for linking, provided by our +friends from Chrome OS. Though the profiles are available externally, +the bucket they sit in is otherwise unreadable by non-Googlers. Gsutil +usage with this bucket is therefore quite awkward: you can't do anything +but `cp` certain files with an external account, and you can't even do +that if you're not yet authenticated. + +No authentication is necessary if you pull these profiles directly over +https. +""" + +import argparse +import contextlib +import os +import subprocess +import sys +import urllib2 + +GS_HTTP_URL = 'https://storage.googleapis.com' + + +def ReadUpToDateProfileName(newest_profile_name_path): + with open(newest_profile_name_path) as f: + return f.read().strip() + + +def ReadLocalProfileName(local_profile_name_path): + try: + with open(local_profile_name_path) as f: + return f.read().strip() + except IOError: + # Assume it either didn't exist, or we couldn't read it. In either case, we + # should probably grab a new profile (and, in doing so, make this file sane + # again) + return None + + +def WriteLocalProfileName(name, local_profile_name_path): + with open(local_profile_name_path, 'w') as f: + f.write(name) + + +def CheckCallOrExit(cmd): + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = proc.communicate() + exit_code = proc.wait() + if not exit_code: + return + + complaint_lines = [ + '## %s failed with exit code %d' % (cmd[0], exit_code), + '## Full command: %s' % cmd, + '## Stdout:\n' + stdout, + '## Stderr:\n' + stderr, + ] + print >>sys.stderr, '\n'.join(complaint_lines) + sys.exit(1) + + +def RetrieveProfile(desired_profile_name, out_path, gs_url_base): + # vpython is > python 2.7.9, so we can expect urllib to validate HTTPS certs + # properly. + ext = os.path.splitext(desired_profile_name)[1] + compressed_path = out_path + ext + gs_prefix = 'gs://' + if not desired_profile_name.startswith(gs_prefix): + gs_url = os.path.join(GS_HTTP_URL, gs_url_base, desired_profile_name) + else: + gs_url = os.path.join(GS_HTTP_URL, desired_profile_name[len(gs_prefix):]) + + with contextlib.closing(urllib2.urlopen(gs_url)) as u: + with open(compressed_path, 'wb') as f: + while True: + buf = u.read(4096) + if not buf: + break + f.write(buf) + + if ext == '.bz2': + # NOTE: we can't use Python's bzip module, since it doesn't support + # multi-stream bzip files. It will silently succeed and give us a garbage + # profile. + # bzip2 removes the compressed file on success. + CheckCallOrExit(['bzip2', '-d', compressed_path]) + elif ext == '.xz': + # ...And we can't use the `lzma` module, since it was introduced in python3. + # xz removes the compressed file on success. + CheckCallOrExit(['xz', '-d', compressed_path]) + else: + # Wait until after downloading the file to check the file extension, so the + # user has something usable locally if the file extension is unrecognized. + raise ValueError( + 'Only bz2 and xz extensions are supported; "%s" is not' % ext) + + +def main(): + parser = argparse.ArgumentParser( + 'Downloads profile/orderfile provided by Chrome OS') + + parser.add_argument( + '--newest_state', + required=True, + help='Path to the file with name of the newest profile. ' + 'We use this file to track the name of the newest profile ' + 'we should pull' + ) + parser.add_argument( + '--local_state', + required=True, + help='Path of the file storing name of the local profile. ' + 'We use this file to track the most recent profile we\'ve ' + 'successfully pulled.' + ) + parser.add_argument( + '--gs_url_base', + required=True, + help='The base GS URL to search for the profile.' + ) + parser.add_argument( + '--output_name', + required=True, + help='Output name of the downloaded and uncompressed profile.' + ) + parser.add_argument( + '-f', '--force', + action='store_true', + help='Fetch a profile even if the local one is current' + ) + args = parser.parse_args() + + up_to_date_profile = ReadUpToDateProfileName(args.newest_state) + if not args.force: + local_profile_name = ReadLocalProfileName(args.local_state) + # In a perfect world, the local profile should always exist if we + # successfully read local_profile_name. If it's gone, though, the user + # probably removed it as a way to get us to download it again. + if local_profile_name == up_to_date_profile \ + and os.path.exists(args.output_name): + return 0 + + new_tmpfile = args.output_name + '.new' + RetrieveProfile(up_to_date_profile, new_tmpfile, args.gs_url_base) + os.rename(new_tmpfile, args.output_name) + WriteLocalProfileName(up_to_date_profile, args.local_state) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/gdb/gdb_chrome.py b/tools/gdb/gdb_chrome.py index 78c5610..116a83b7 100644 --- a/tools/gdb/gdb_chrome.py +++ b/tools/gdb/gdb_chrome.py
@@ -162,9 +162,14 @@ typename = 'base::WeakPtr' def ptr(self): - if bool( - gdb.parse_and_eval( - '(*(%s*)(%s)).ref_.IsValid()' % (self.val.type, self.val.address))): + # Check that the pointer is valid. The invalidated flag is stored at + # val.ref_.flag_.ptr_->invalidated_.flag_.__a_.__a_value. This is a gdb + # implementation of base::WeakReference::IsValid(). This is necessary + # because calling gdb.parse_and_eval('(*(%s*)(%s)).ref_.IsValid()' % + # (self.val.type, self.val.address))) does not work in all cases. + ptr = self.val['ref_']['flag_']['ptr_'] + if (ptr and + not ptr.dereference()['invalidated_']['flag_']['__a_']['__a_value']): return self.val['ptr_'] return gdb.Value(0).cast(self.val['ptr_'].type)
diff --git a/tools/mb/mb.py b/tools/mb/mb.py index a5120181..ba3af5a 100755 --- a/tools/mb/mb.py +++ b/tools/mb/mb.py
@@ -1296,7 +1296,10 @@ # If we're testing a CrOS simplechrome build, assume we need to prepare a # DUT for testing. So prepend the command to run with the test wrapper. if is_simplechrome: - cmdline = [os.path.join('bin', 'cros_test_wrapper')] + cmdline = [ + os.path.join('bin', 'cros_test_wrapper'), + '--logs-dir=${ISOLATED_OUTDIR}', + ] cmdline += [ '../../testing/test_env.py', '../../' + self.ToSrcRelPath(isolate_map[target]['script'])
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 0be04c7..40bbfa2 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -4007,16 +4007,19 @@ </action> <action name="ChromeColors_MenuCancel"> + <obsolete>Deprecated as of 7/2019.</obsolete> <owner>gayane@chromium.org</owner> <description>Applied changes where canceled from Colors menu.</description> </action> <action name="ChromeColors_MenuDone"> + <obsolete>Deprecated as of 7/2019.</obsolete> <owner>gayane@chromium.org</owner> <description>Applied changes where confirmed from Colors menu.</description> </action> <action name="ChromeColors_TabClosed"> + <obsolete>Deprecated as of 7/2019.</obsolete> <owner>gayane@chromium.org</owner> <description>Tab with open Colors menu was closed.</description> </action>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 2681efd4..996ee16 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -2168,6 +2168,91 @@ <int value="8" label="kLaunchTypeUnspecified"/> </enum> +<enum name="AppListNonAppImpressionCategory"> + <int value="0" label="APPS"/> + <int value="1" label="SEARCH_RESULTS"/> + <int value="2" label="START"/> + <int value="3" label="CUSTOM_LAUNCHER_PAGE_DEPRECATED"/> +</enum> + +<enum name="AppListNonAppImpressionDeviceMode"> + <int value="0" label="UNKNOWN"/> + <int value="1" label="FILE"/> + <int value="2" label="HISTORY"/> + <int value="3" label="NAV_SUGGEST"/> + <int value="4" label="SEARCH"/> + <int value="5" label="BOOKMARK"/> + <int value="6" label="DOCUMENT"/> + <int value="7" label="OMNIBOX_DEPRECATED"/> + <int value="8" label="OMNIBOX_GENERIC"/> +</enum> + +<enum name="AppListNonAppImpressionFileExtension"> + <int value="0" label=".3ga"/> + <int value="1" label=".3gp"/> + <int value="2" label=".aac"/> + <int value="3" label=".alac"/> + <int value="4" label=".asf"/> + <int value="5" label=".avi"/> + <int value="6" label=".bmp"/> + <int value="7" label=".csv"/> + <int value="8" label=".doc"/> + <int value="9" label=".docx"/> + <int value="10" label=".flac"/> + <int value="11" label=".gif"/> + <int value="12" label=".jpeg"/> + <int value="13" label=".jpg"/> + <int value="14" label=".log"/> + <int value="15" label=".m3u"/> + <int value="16" label=".m3u8"/> + <int value="17" label=".m4a"/> + <int value="18" label=".m4v"/> + <int value="19" label=".mid"/> + <int value="20" label=".mkv"/> + <int value="21" label=".mov"/> + <int value="22" label=".mp3"/> + <int value="23" label=".mp4"/> + <int value="24" label=".mpg"/> + <int value="25" label=".odf"/> + <int value="26" label=".odp"/> + <int value="27" label=".ods"/> + <int value="28" label=".odt"/> + <int value="29" label=".oga"/> + <int value="30" label=".ogg"/> + <int value="31" label=".ogv"/> + <int value="32" label=".pdf"/> + <int value="33" label=".png"/> + <int value="34" label=".ppt"/> + <int value="35" label=".pptx"/> + <int value="36" label=".ra"/> + <int value="37" label=".ram"/> + <int value="38" label=".rar"/> + <int value="39" label=".rm"/> + <int value="40" label=".rtf"/> + <int value="41" label=".wav"/> + <int value="42" label=".webm"/> + <int value="43" label=".webp"/> + <int value="44" label=".wma"/> + <int value="45" label=".wmv"/> + <int value="46" label=".xls"/> + <int value="47" label=".xlsx"/> + <int value="48" label=".crdownload"/> + <int value="49" label=".crx"/> + <int value="50" label=".dmg"/> + <int value="51" label=".exe"/> + <int value="52" label=".html"/> + <int value="53" label=".htm"/> + <int value="54" label=".jar"/> + <int value="55" label=".ps"/> + <int value="56" label=".torrent"/> + <int value="57" label=".txt"/> + <int value="58" label=".zip"/> + <int value="59" label=".mhtml"/> + <int value="60" label=".gdoc"/> + <int value="61" label=".gsheet"/> + <int value="62" label=".gslides"/> +</enum> + <enum name="AppListOmniboxResult"> <int value="0" label="QUERY_SUGGESTION"/> <int value="1" label="ZERO_STATE_SUGEESTION"/> @@ -5630,6 +5715,11 @@ <int value="1" label="Checked"/> </enum> +<enum name="BooleanChromeColorsChangesConfirmed"> + <int value="0" label="Reverted"/> + <int value="1" label="Confirmed"/> +</enum> + <enum name="BooleanCleared"> <int value="0" label="Not cleared"/> <int value="1" label="Cleared"/> @@ -7426,6 +7516,12 @@ <int value="19" label="RASPBERRY"/> </enum> +<enum name="ChromeColorsRevertReason"> + <int value="0" label="User action"/> + <int value="1" label="Search provider change"/> + <int value="2" label="Tab closed"/> +</enum> + <enum name="ChromeDownloadCountType"> <int value="0" label="Initiated by Navigation (Obsolete)"/> <int value="1" label="Initiated by Context Menu (Obsolete)"/> @@ -20048,6 +20144,8 @@ <int value="1360" label="ACTION_SETBADGEBACKGROUNDCOLOR"/> <int value="1361" label="AUTOTESTPRIVATE_SETARCAPPWINDOWSTATE"/> <int value="1362" label="ACCESSIBILITY_PRIVATE_OPENSETTINGSSUBPAGE"/> + <int value="1363" label="ACTION_ENABLE"/> + <int value="1364" label="ACTION_DISABLE"/> </enum> <enum name="ExtensionIconState"> @@ -23693,7 +23791,7 @@ <int value="2649" label="OpenerNavigationDownloadCrossOrigin"/> <int value="2650" label="V8RegExpMatchIsTrueishOnNonJSRegExp"/> <int value="2651" label="V8RegExpMatchIsFalseishOnJSRegExp"/> - <int value="2652" label="DownloadInAdFrameWithUserGesture"/> + <int value="2652" label="OBSOLETE_DownloadInAdFrameWithUserGesture"/> <int value="2653" label="DownloadInAdFrameWithoutUserGesture"/> <int value="2654" label="NavigatorAppVersion"/> <int value="2655" label="NavigatorDoNotTrack"/> @@ -24013,9 +24111,7 @@ <int value="2946" label="WebkitMarginAfterCollapseSeparate"/> <int value="2947" label="WebkitMarginAfterCollapseSeparateMaybeDoesSomething"/> - <int value="2948" label="CredentialManagerCreateWithUVM"/> <int value="2949" label="CredentialManagerGetWithUVM"/> - <int value="2950" label="CredentialManagerCreateSuccessWithUVM"/> <int value="2951" label="CredentialManagerGetSuccessWithUVM"/> <int value="2952" label="DiscardInputEventToMovingIframe"/> <int value="2953" label="SignedExchangeSubresourcePrefetch"/> @@ -24040,6 +24136,10 @@ <int value="2971" label="V8PointerEvent_GetPredictedEvents_Method"/> <int value="2972" label="ScrollSnapOnViewportBreaks"/> <int value="2973" label="ScrollPaddingOnViewportBreaks"/> + <int value="2974" label="DownloadInAdFrame"/> + <int value="2975" label="DownloadInSandbox"/> + <int value="2976" label="DownloadWithoutUserGesture"/> + <int value="2977" label="AutoplayDynamicDelegation"/> </enum> <enum name="FeaturePolicyAllowlistType"> @@ -24159,6 +24259,10 @@ <int value="2" label="Fetch failure"/> </enum> +<!-- Keep elements in sync with components/feed/core/feed_logging_metrics.cc and + third_party/feed/src/src/main/java/com/google/android/libraries/feed/api/host/logging/InternalFeedError.java + --> + <enum name="FeedInternalError"> <int value="0" label="SWITCH_TO_EPHEMERAL"/> <int value="1" label="NO_URL_FOR_OPEN"/> @@ -32304,6 +32408,52 @@ label="Del Fail -MaxPathCheck Fail - MoveFileEx Fail - CopyDelDir Fail"/> </enum> +<enum name="KerberosConfigErrorCode"> + <int value="0" label="Valid"/> + <int value="1" label="Section nested in group"/> + <int value="2" label="Section syntax"/> + <int value="3" label="Expected opening curly brace"/> + <int value="4" label="Extra curly brace"/> + <int value="5" label="Relation syntax"/> + <int value="6" label="Key not supported"/> + <int value="7" label="Section not supported"/> + <int value="8" label="Krb5 failed to parse"/> +</enum> + +<enum name="KerberosErrorType"> + <int value="0" label="Success"/> + <int value="1" label="Unspecified error"/> + <int value="2" label="Unspecified D-Bus error"/> + <int value="3" label="General network problem"/> + <int value="4" label="Unspecified KRB5 error."/> + <int value="5" label="Bad principal"/> + <int value="6" label="Bad password"/> + <int value="7" label="Password expired"/> + <int value="8" label="Password rejected while trying to change it"/> + <int value="9" label="Kerberos credentials cache not found"/> + <int value="10" label="Kerberos ticket expired while renewing credentials"/> + <int value="11" + label="Key Distribution Center does not support enforced encryption + types"/> + <int value="12" label="Failed to contact Key Distribution Center"/> + <int value="13" label="Parsing D-Bus request message failed"/> + <int value="14" label="Local IO operation failed"/> + <int value="15" label="Account with given principal name does not exist"/> + <int value="16" + label="Adding account failed; account with given principal name already + exists"/> + <int value="17" label="Asynchronous operation in progress"/> + <int value="18" label="Badly formatted principal name"/> + <int value="19" label="Badly formatted Kerberos configuration"/> + <int value="20" label="Failed to run untrusted code in container"/> + <int value="21" label="Kerberos feature disabled"/> +</enum> + +<enum name="KerberosUserType"> + <int value="0" label="Managed"/> + <int value="1" label="Unmanaged"/> +</enum> + <enum name="KeyboardControlEvent"> <int value="0" label="Keyboard was shown."/> <int value="1" label="Keyboard was automatically hidden."/> @@ -33756,6 +33906,7 @@ <int value="-2118893353" label="WebRtcRemoteEventLog:enabled"/> <int value="-2117621241" label="ExperimentalProductivityFeatures:enabled"/> <int value="-2117201726" label="disable-gpu-rasterization"/> + <int value="-2117169027" label="UpdateHoverAtBeginFrame:enabled"/> <int value="-2114831248" label="disable-new-ntp"/> <int value="-2113783491" label="ArcFilePickerExperiment:enabled"/> <int value="-2113705745" @@ -34469,6 +34620,8 @@ <int value="-1201183153" label="enable-centered-app-list"/> <int value="-1199159971" label="ContextualSuggestionsIPHReverseScroll:enabled"/> + <int value="-1198304634" + label="ProcessSharingWithDefaultSiteInstances:disabled"/> <int value="-1197245070" label="CookieDeprecationMessages:disabled"/> <int value="-1197035323" label="ZeroSuggestRedirectToChrome:disabled"/> <int value="-1195194959" label="XGEOVisibleNetworks:disabled"/> @@ -34530,6 +34683,7 @@ <int value="-1112782121" label="AndroidSigninPromos:disabled"/> <int value="-1107762575" label="enable-data-reduction-proxy-config-client"/> <int value="-1107103335" label="FsNosymfollow:enabled"/> + <int value="-1105637876" label="FilteringScrollPrediction:enabled"/> <int value="-1103099187" label="NotificationStackingBarRedesign:disabled"/> <int value="-1102212525" label="enable-tcp-fastopen"/> <int value="-1099618411" label="UpdatedCellularActivationUi:enabled"/> @@ -34657,6 +34811,8 @@ <int value="-932474660" label="VirtualDesks:enabled"/> <int value="-932261921" label="enable-defer-all-script-without-optimization-hints"/> + <int value="-932164609" + label="ProcessSharingWithDefaultSiteInstances:enabled"/> <int value="-929944930" label="AutofillRationalizeRepeatedServerPredictions:disabled"/> <int value="-928138978" label="IPH_DemoMode:disabled"/> @@ -35130,6 +35286,7 @@ <int value="-250822813" label="PwaImprovedSplashScreen:enabled"/> <int value="-250721831" label="AndroidAutofillAccessibility:disabled"/> <int value="-250543540" label="DeferAllScript:enabled"/> + <int value="-249415830" label="FilteringScrollPrediction:disabled"/> <int value="-248223420" label="AutofillKeyboardAccessory:disabled"/> <int value="-243323793" label="OmniboxOnDeviceHeadProvider:enabled"/> <int value="-241353344" label="MidiManagerWinrt:disabled"/> @@ -36727,6 +36884,7 @@ <int value="2071229145" label="BloatedRendererDetection:enabled"/> <int value="2071340353" label="progress-bar-completion"/> <int value="2071461362" label="disable-credit-card-scan"/> + <int value="2072057275" label="UpdateHoverAtBeginFrame:disabled"/> <int value="2072231406" label="SingleProcessMash:disabled"/> <int value="2073113207" label="SensorContentSetting:disabled"/> <int value="2075207488" label="AutomaticPasswordGeneration:disabled"/> @@ -39623,6 +39781,7 @@ <int value="13" label="Chrome Search Extension"/> <int value="14" label="Chrome Content Extension"/> <int value="15" label="Chrome Share Extension"/> + <int value="16" label="Chrome"/> </enum> <enum name="MobileSessionShutdownType"> @@ -40231,7 +40390,9 @@ <int value="5" label="Opener x-origin"/> <int value="7" label="Sandbox no gesture"/> <int value="8" label="Ad frame no gesture"/> - <int value="9" label="Ad frame gesture"/> + <int value="10" label="Ad frame"/> + <int value="11" label="Sandbox"/> + <int value="12" label="No gesture"/> </enum> <enum name="NavigationInterceptResult"> @@ -53362,12 +53523,20 @@ </int> </enum> +<enum name="SharingClickToCallDialogType"> + <int value="0" label="Dialog with devices and maybe apps"/> + <int value="1" label="Dialog without devices but with an app"/> + <int value="2" label="Educational dialog without devices or apps"/> + <int value="3" label="Error dialog"/> +</enum> + <enum name="SharingDeviceRegistrationResult"> <int value="0" label="Operation is successful"/> <int value="1" label="Failed with Sync not ready"/> <int value="2" label="Failed with encryption related error"/> <int value="3" label="Failed with FCM transient error"/> <int value="4" label="Failed with FCM fatal error"/> + <int value="5" label="Device has not been registered"/> </enum> <enum name="SharingMessageType"> @@ -58442,6 +58611,15 @@ label="CROS Cr50 0.2.2 aka 0.4.4 Flags 0x10(pre-pvt)"/> </enum> +<enum name="TracingFinalizationDisallowedReason"> + <int value="0" label="Incognito profile launched"/> + <int value="1" label="Default profile not loaded"/> + <int value="2" label="Crash metrics not loaded"/> + <int value="3" label="Last session crashed"/> + <int value="4" label="Metrics reporting disabled"/> + <int value="5" label="Recently uploaded another trace"/> +</enum> + <enum name="TrackedPreference"> <int value="0" label="kShowHomeButton"/> <int value="1" label="kHomePageIsNewTabPage"/> @@ -62912,6 +63090,361 @@ <int value="1" label="Cannot open last used profile"/> </enum> +<enum name="WindowsPatchLevel"> +<!-- These can be generated by visiting https://bit.ly/2JQr6rB --> + + <int value="0" label="Invalid Patch Level"/> + <int value="498163541" label="Windows 7 Service Pack 1 (Build 7601.24405)"/> + <int value="602947584" label="Windows 8 (Build 9200.16384)"/> + <int value="629164923" label="Windows 8.1 (Build 9600.19323)"/> + <int value="671090283" label="Windows 10 1507 (Build 10240.1643)"/> + <int value="671090292" label="Windows 10 1507 (Build 10240.1652)"/> + <int value="671090299" label="Windows 10 1507 (Build 10240.1659)"/> + <int value="671090359" label="Windows 10 1507 (Build 10240.1719)"/> + <int value="671090417" label="Windows 10 1507 (Build 10240.1777)"/> + <int value="671105045" label="Windows 10 1507 (Build 10240.16405)"/> + <int value="671105053" label="Windows 10 1507 (Build 10240.16413)"/> + <int value="671105073" label="Windows 10 1507 (Build 10240.16433)"/> + <int value="671105085" label="Windows 10 1507 (Build 10240.16445)"/> + <int value="671105103" label="Windows 10 1507 (Build 10240.16463)"/> + <int value="671105127" label="Windows 10 1507 (Build 10240.16487)"/> + <int value="671105189" label="Windows 10 1507 (Build 10240.16549)"/> + <int value="671105206" label="Windows 10 1507 (Build 10240.16566)"/> + <int value="671105241" label="Windows 10 1507 (Build 10240.16601)"/> + <int value="671105284" label="Windows 10 1507 (Build 10240.16644)"/> + <int value="671105323" label="Windows 10 1507 (Build 10240.16683)"/> + <int value="671105365" label="Windows 10 1507 (Build 10240.16725)"/> + <int value="671105411" label="Windows 10 1507 (Build 10240.16771)"/> + <int value="671105494" label="Windows 10 1507 (Build 10240.16854)"/> + <int value="671105582" label="Windows 10 1507 (Build 10240.16942)"/> + <int value="671105664" label="Windows 10 1507 (Build 10240.17024)"/> + <int value="671105711" label="Windows 10 1507 (Build 10240.17071)"/> + <int value="671105753" label="Windows 10 1507 (Build 10240.17113)"/> + <int value="671105786" label="Windows 10 1507 (Build 10240.17146)"/> + <int value="671105842" label="Windows 10 1507 (Build 10240.17202)"/> + <int value="671105876" label="Windows 10 1507 (Build 10240.17236)"/> + <int value="671105959" label="Windows 10 1507 (Build 10240.17319)"/> + <int value="671105994" label="Windows 10 1507 (Build 10240.17354)"/> + <int value="671106034" label="Windows 10 1507 (Build 10240.17394)"/> + <int value="671106083" label="Windows 10 1507 (Build 10240.17443)"/> + <int value="671106086" label="Windows 10 1507 (Build 10240.17446)"/> + <int value="671106128" label="Windows 10 1507 (Build 10240.17488)"/> + <int value="671106173" label="Windows 10 1507 (Build 10240.17533)"/> + <int value="671106249" label="Windows 10 1507 (Build 10240.17609)"/> + <int value="671106283" label="Windows 10 1507 (Build 10240.17643)"/> + <int value="671106313" label="Windows 10 1507 (Build 10240.17673)"/> + <int value="671106349" label="Windows 10 1507 (Build 10240.17709)"/> + <int value="671106378" label="Windows 10 1507 (Build 10240.17738)"/> + <int value="671106381" label="Windows 10 1507 (Build 10240.17741)"/> + <int value="671106437" label="Windows 10 1507 (Build 10240.17797)"/> + <int value="671106471" label="Windows 10 1507 (Build 10240.17831)"/> + <int value="671106501" label="Windows 10 1507 (Build 10240.17861)"/> + <int value="671106529" label="Windows 10 1507 (Build 10240.17889)"/> + <int value="671106554" label="Windows 10 1507 (Build 10240.17914)"/> + <int value="671106558" label="Windows 10 1507 (Build 10240.17918)"/> + <int value="671106586" label="Windows 10 1507 (Build 10240.17946)"/> + <int value="671106616" label="Windows 10 1507 (Build 10240.17976)"/> + <int value="671106645" label="Windows 10 1507 (Build 10240.18005)"/> + <int value="671106676" label="Windows 10 1507 (Build 10240.18036)"/> + <int value="671106703" label="Windows 10 1507 (Build 10240.18063)"/> + <int value="671106704" label="Windows 10 1507 (Build 10240.18064)"/> + <int value="671106734" label="Windows 10 1507 (Build 10240.18094)"/> + <int value="671106772" label="Windows 10 1507 (Build 10240.18132)"/> + <int value="671106775" label="Windows 10 1507 (Build 10240.18135)"/> + <int value="671106798" label="Windows 10 1507 (Build 10240.18158)"/> + <int value="671106826" label="Windows 10 1507 (Build 10240.18186)"/> + <int value="671106827" label="Windows 10 1507 (Build 10240.18187)"/> + <int value="671106855" label="Windows 10 1507 (Build 10240.18215)"/> + <int value="671106858" label="Windows 10 1507 (Build 10240.18218)"/> + <int value="671106884" label="Windows 10 1507 (Build 10240.18244)"/> + <int value="671106915" label="Windows 10 1507 (Build 10240.18275)"/> + <int value="693764099" label="Windows 10 1511 (Build 10586.3)"/> + <int value="693764107" label="Windows 10 1511 (Build 10586.11)"/> + <int value="693764110" label="Windows 10 1511 (Build 10586.14)"/> + <int value="693764113" label="Windows 10 1511 (Build 10586.17)"/> + <int value="693764125" label="Windows 10 1511 (Build 10586.29)"/> + <int value="693764132" label="Windows 10 1511 (Build 10586.36)"/> + <int value="693764138" label="Windows 10 1511 (Build 10586.42)"/> + <int value="693764159" label="Windows 10 1511 (Build 10586.63)"/> + <int value="693764167" label="Windows 10 1511 (Build 10586.71)"/> + <int value="693764200" label="Windows 10 1511 (Build 10586.104)"/> + <int value="693764218" label="Windows 10 1511 (Build 10586.122)"/> + <int value="693764250" label="Windows 10 1511 (Build 10586.154)"/> + <int value="693764260" label="Windows 10 1511 (Build 10586.164)"/> + <int value="693764314" label="Windows 10 1511 (Build 10586.218)"/> + <int value="693764414" label="Windows 10 1511 (Build 10586.318)"/> + <int value="693764590" label="Windows 10 1511 (Build 10586.494)"/> + <int value="693764641" label="Windows 10 1511 (Build 10586.545)"/> + <int value="693764685" label="Windows 10 1511 (Build 10586.589)"/> + <int value="693764729" label="Windows 10 1511 (Build 10586.633)"/> + <int value="693764775" label="Windows 10 1511 (Build 10586.679)"/> + <int value="693764809" label="Windows 10 1511 (Build 10586.713)"/> + <int value="693764849" label="Windows 10 1511 (Build 10586.753)"/> + <int value="693764935" label="Windows 10 1511 (Build 10586.839)"/> + <int value="693764969" label="Windows 10 1511 (Build 10586.873)"/> + <int value="693765012" label="Windows 10 1511 (Build 10586.916)"/> + <int value="693765058" label="Windows 10 1511 (Build 10586.962)"/> + <int value="693765061" label="Windows 10 1511 (Build 10586.965)"/> + <int value="693765103" label="Windows 10 1511 (Build 10586.1007)"/> + <int value="693765141" label="Windows 10 1511 (Build 10586.1045)"/> + <int value="693765202" label="Windows 10 1511 (Build 10586.1106)"/> + <int value="693765272" label="Windows 10 1511 (Build 10586.1176)"/> + <int value="693765273" label="Windows 10 1511 (Build 10586.1177)"/> + <int value="693765328" label="Windows 10 1511 (Build 10586.1232)"/> + <int value="693765391" label="Windows 10 1511 (Build 10586.1295)"/> + <int value="693765452" label="Windows 10 1511 (Build 10586.1356)"/> + <int value="693765454" label="Windows 10 1511 (Build 10586.1358)"/> + <int value="693765513" label="Windows 10 1511 (Build 10586.1417)"/> + <int value="693765574" label="Windows 10 1511 (Build 10586.1478)"/> + <int value="943259649" label="Windows 10 1607 (Build 14393.1)"/> + <int value="943259699" label="Windows 10 1607 (Build 14393.51)"/> + <int value="943259730" label="Windows 10 1607 (Build 14393.82)"/> + <int value="943259753" label="Windows 10 1607 (Build 14393.105)"/> + <int value="943259796" label="Windows 10 1607 (Build 14393.148)"/> + <int value="943259815" label="Windows 10 1607 (Build 14393.167)"/> + <int value="943259825" label="Windows 10 1607 (Build 14393.177)"/> + <int value="943259835" label="Windows 10 1607 (Build 14393.187)"/> + <int value="943259870" label="Windows 10 1607 (Build 14393.222)"/> + <int value="943259891" label="Windows 10 1607 (Build 14393.243)"/> + <int value="943259906" label="Windows 10 1607 (Build 14393.258)"/> + <int value="943259915" label="Windows 10 1607 (Build 14393.267)"/> + <int value="943259969" label="Windows 10 1607 (Build 14393.321)"/> + <int value="943259999" label="Windows 10 1607 (Build 14393.351)"/> + <int value="943260095" label="Windows 10 1607 (Build 14393.447)"/> + <int value="943260127" label="Windows 10 1607 (Build 14393.479)"/> + <int value="943260224" label="Windows 10 1607 (Build 14393.576)"/> + <int value="943260341" label="Windows 10 1607 (Build 14393.693)"/> + <int value="943260601" label="Windows 10 1607 (Build 14393.953)"/> + <int value="943260617" label="Windows 10 1607 (Build 14393.969)"/> + <int value="943260714" label="Windows 10 1607 (Build 14393.1066)"/> + <int value="943260846" label="Windows 10 1607 (Build 14393.1198)"/> + <int value="943261006" label="Windows 10 1607 (Build 14393.1358)"/> + <int value="943261026" label="Windows 10 1607 (Build 14393.1378)"/> + <int value="943261180" label="Windows 10 1607 (Build 14393.1532)"/> + <int value="943261185" label="Windows 10 1607 (Build 14393.1537)"/> + <int value="943261241" label="Windows 10 1607 (Build 14393.1593)"/> + <int value="943261261" label="Windows 10 1607 (Build 14393.1613)"/> + <int value="943261363" label="Windows 10 1607 (Build 14393.1715)"/> + <int value="943261385" label="Windows 10 1607 (Build 14393.1737)"/> + <int value="943261442" label="Windows 10 1607 (Build 14393.1794)"/> + <int value="943261445" label="Windows 10 1607 (Build 14393.1797)"/> + <int value="943261532" label="Windows 10 1607 (Build 14393.1884)"/> + <int value="943261562" label="Windows 10 1607 (Build 14393.1914)"/> + <int value="943261592" label="Windows 10 1607 (Build 14393.1944)"/> + <int value="943261655" label="Windows 10 1607 (Build 14393.2007)"/> + <int value="943261683" label="Windows 10 1607 (Build 14393.2035)"/> + <int value="943261716" label="Windows 10 1607 (Build 14393.2068)"/> + <int value="943261745" label="Windows 10 1607 (Build 14393.2097)"/> + <int value="943261773" label="Windows 10 1607 (Build 14393.2125)"/> + <int value="943261803" label="Windows 10 1607 (Build 14393.2155)"/> + <int value="943261804" label="Windows 10 1607 (Build 14393.2156)"/> + <int value="943261837" label="Windows 10 1607 (Build 14393.2189)"/> + <int value="943261862" label="Windows 10 1607 (Build 14393.2214)"/> + <int value="943261896" label="Windows 10 1607 (Build 14393.2248)"/> + <int value="943261921" label="Windows 10 1607 (Build 14393.2273)"/> + <int value="943261960" label="Windows 10 1607 (Build 14393.2312)"/> + <int value="943261987" label="Windows 10 1607 (Build 14393.2339)"/> + <int value="943262011" label="Windows 10 1607 (Build 14393.2363)"/> + <int value="943262016" label="Windows 10 1607 (Build 14393.2368)"/> + <int value="943262043" label="Windows 10 1607 (Build 14393.2395)"/> + <int value="943262044" label="Windows 10 1607 (Build 14393.2396)"/> + <int value="943262105" label="Windows 10 1607 (Build 14393.2457)"/> + <int value="943262133" label="Windows 10 1607 (Build 14393.2485)"/> + <int value="943262163" label="Windows 10 1607 (Build 14393.2515)"/> + <int value="943262199" label="Windows 10 1607 (Build 14393.2551)"/> + <int value="943262256" label="Windows 10 1607 (Build 14393.2608)"/> + <int value="943262287" label="Windows 10 1607 (Build 14393.2639)"/> + <int value="943262289" label="Windows 10 1607 (Build 14393.2641)"/> + <int value="943262313" label="Windows 10 1607 (Build 14393.2665)"/> + <int value="943262372" label="Windows 10 1607 (Build 14393.2724)"/> + <int value="943262407" label="Windows 10 1607 (Build 14393.2759)"/> + <int value="943262439" label="Windows 10 1607 (Build 14393.2791)"/> + <int value="943262476" label="Windows 10 1607 (Build 14393.2828)"/> + <int value="943262496" label="Windows 10 1607 (Build 14393.2848)"/> + <int value="943262527" label="Windows 10 1607 (Build 14393.2879)"/> + <int value="943262554" label="Windows 10 1607 (Build 14393.2906)"/> + <int value="943262556" label="Windows 10 1607 (Build 14393.2908)"/> + <int value="943262589" label="Windows 10 1607 (Build 14393.2941)"/> + <int value="943262617" label="Windows 10 1607 (Build 14393.2969)"/> + <int value="943262620" label="Windows 10 1607 (Build 14393.2972)"/> + <int value="943262647" label="Windows 10 1607 (Build 14393.2999)"/> + <int value="943262673" label="Windows 10 1607 (Build 14393.3025)"/> + <int value="943262701" label="Windows 10 1607 (Build 14393.3053)"/> + <int value="943262704" label="Windows 10 1607 (Build 14393.3056)"/> + <int value="943262733" label="Windows 10 1607 (Build 14393.3085)"/> + <int value="943262763" label="Windows 10 1607 (Build 14393.3115)"/> + <int value="987168793" label="Windows 10 1703 (Build 15063.25)"/> + <int value="987168822" label="Windows 10 1703 (Build 15063.54)"/> + <int value="987168853" label="Windows 10 1703 (Build 15063.85)"/> + <int value="987168906" label="Windows 10 1703 (Build 15063.138)"/> + <int value="987169064" label="Windows 10 1703 (Build 15063.296)"/> + <int value="987169100" label="Windows 10 1703 (Build 15063.332)"/> + <int value="987169181" label="Windows 10 1703 (Build 15063.413)"/> + <int value="987169215" label="Windows 10 1703 (Build 15063.447)"/> + <int value="987169251" label="Windows 10 1703 (Build 15063.483)"/> + <int value="987169270" label="Windows 10 1703 (Build 15063.502)"/> + <int value="987169376" label="Windows 10 1703 (Build 15063.608)"/> + <int value="987169400" label="Windows 10 1703 (Build 15063.632)"/> + <int value="987169442" label="Windows 10 1703 (Build 15063.674)"/> + <int value="987169443" label="Windows 10 1703 (Build 15063.675)"/> + <int value="987169494" label="Windows 10 1703 (Build 15063.726)"/> + <int value="987169497" label="Windows 10 1703 (Build 15063.729)"/> + <int value="987169554" label="Windows 10 1703 (Build 15063.786)"/> + <int value="987169645" label="Windows 10 1703 (Build 15063.877)"/> + <int value="987169677" label="Windows 10 1703 (Build 15063.909)"/> + <int value="987169704" label="Windows 10 1703 (Build 15063.936)"/> + <int value="987169734" label="Windows 10 1703 (Build 15063.966)"/> + <int value="987169762" label="Windows 10 1703 (Build 15063.994)"/> + <int value="987169797" label="Windows 10 1703 (Build 15063.1029)"/> + <int value="987169826" label="Windows 10 1703 (Build 15063.1058)"/> + <int value="987169856" label="Windows 10 1703 (Build 15063.1088)"/> + <int value="987169880" label="Windows 10 1703 (Build 15063.1112)"/> + <int value="987169923" label="Windows 10 1703 (Build 15063.1155)"/> + <int value="987169950" label="Windows 10 1703 (Build 15063.1182)"/> + <int value="987169974" label="Windows 10 1703 (Build 15063.1206)"/> + <int value="987169977" label="Windows 10 1703 (Build 15063.1209)"/> + <int value="987170003" label="Windows 10 1703 (Build 15063.1235)"/> + <int value="987170034" label="Windows 10 1703 (Build 15063.1266)"/> + <int value="987170060" label="Windows 10 1703 (Build 15063.1292)"/> + <int value="987170092" label="Windows 10 1703 (Build 15063.1324)"/> + <int value="987170124" label="Windows 10 1703 (Build 15063.1356)"/> + <int value="987170155" label="Windows 10 1703 (Build 15063.1387)"/> + <int value="987170186" label="Windows 10 1703 (Build 15063.1418)"/> + <int value="987170214" label="Windows 10 1703 (Build 15063.1446)"/> + <int value="987170246" label="Windows 10 1703 (Build 15063.1478)"/> + <int value="987170274" label="Windows 10 1703 (Build 15063.1506)"/> + <int value="987170276" label="Windows 10 1703 (Build 15063.1508)"/> + <int value="987170331" label="Windows 10 1703 (Build 15063.1563)"/> + <int value="987170364" label="Windows 10 1703 (Build 15063.1596)"/> + <int value="987170399" label="Windows 10 1703 (Build 15063.1631)"/> + <int value="987170427" label="Windows 10 1703 (Build 15063.1659)"/> + <int value="987170457" label="Windows 10 1703 (Build 15063.1689)"/> + <int value="987170484" label="Windows 10 1703 (Build 15063.1716)"/> + <int value="987170514" label="Windows 10 1703 (Build 15063.1746)"/> + <int value="987170552" label="Windows 10 1703 (Build 15063.1784)"/> + <int value="987170553" label="Windows 10 1703 (Build 15063.1785)"/> + <int value="987170573" label="Windows 10 1703 (Build 15063.1805)"/> + <int value="987170576" label="Windows 10 1703 (Build 15063.1808)"/> + <int value="987170607" label="Windows 10 1703 (Build 15063.1839)"/> + <int value="987170636" label="Windows 10 1703 (Build 15063.1868)"/> + <int value="987170665" label="Windows 10 1703 (Build 15063.1897)"/> + <int value="987170666" label="Windows 10 1703 (Build 15063.1898)"/> + <int value="987170696" label="Windows 10 1703 (Build 15063.1928)"/> + <int value="987170723" label="Windows 10 1703 (Build 15063.1955)"/> + <int value="1068171283" label="Windows 10 1709 (Build 16299.19)"/> + <int value="1068171328" label="Windows 10 1709 (Build 16299.64)"/> + <int value="1068171346" label="Windows 10 1709 (Build 16299.82)"/> + <int value="1068171362" label="Windows 10 1709 (Build 16299.98)"/> + <int value="1068171379" label="Windows 10 1709 (Build 16299.115)"/> + <int value="1068171389" label="Windows 10 1709 (Build 16299.125)"/> + <int value="1068171456" label="Windows 10 1709 (Build 16299.192)"/> + <int value="1068171458" label="Windows 10 1709 (Build 16299.194)"/> + <int value="1068171465" label="Windows 10 1709 (Build 16299.201)"/> + <int value="1068171478" label="Windows 10 1709 (Build 16299.214)"/> + <int value="1068171512" label="Windows 10 1709 (Build 16299.248)"/> + <int value="1068171515" label="Windows 10 1709 (Build 16299.251)"/> + <int value="1068171573" label="Windows 10 1709 (Build 16299.309)"/> + <int value="1068171598" label="Windows 10 1709 (Build 16299.334)"/> + <int value="1068171635" label="Windows 10 1709 (Build 16299.371)"/> + <int value="1068171666" label="Windows 10 1709 (Build 16299.402)"/> + <int value="1068171695" label="Windows 10 1709 (Build 16299.431)"/> + <int value="1068171725" label="Windows 10 1709 (Build 16299.461)"/> + <int value="1068171756" label="Windows 10 1709 (Build 16299.492)"/> + <int value="1068171786" label="Windows 10 1709 (Build 16299.522)"/> + <int value="1068171811" label="Windows 10 1709 (Build 16299.547)"/> + <int value="1068171815" label="Windows 10 1709 (Build 16299.551)"/> + <int value="1068171843" label="Windows 10 1709 (Build 16299.579)"/> + <int value="1068171875" label="Windows 10 1709 (Build 16299.611)"/> + <int value="1068171901" label="Windows 10 1709 (Build 16299.637)"/> + <int value="1068171929" label="Windows 10 1709 (Build 16299.665)"/> + <int value="1068171930" label="Windows 10 1709 (Build 16299.666)"/> + <int value="1068171963" label="Windows 10 1709 (Build 16299.699)"/> + <int value="1068171990" label="Windows 10 1709 (Build 16299.726)"/> + <int value="1068172019" label="Windows 10 1709 (Build 16299.755)"/> + <int value="1068172049" label="Windows 10 1709 (Build 16299.785)"/> + <int value="1068172110" label="Windows 10 1709 (Build 16299.846)"/> + <int value="1068172111" label="Windows 10 1709 (Build 16299.847)"/> + <int value="1068172168" label="Windows 10 1709 (Build 16299.904)"/> + <int value="1068172200" label="Windows 10 1709 (Build 16299.936)"/> + <int value="1068172231" label="Windows 10 1709 (Build 16299.967)"/> + <int value="1068172268" label="Windows 10 1709 (Build 16299.1004)"/> + <int value="1068172293" label="Windows 10 1709 (Build 16299.1029)"/> + <int value="1068172323" label="Windows 10 1709 (Build 16299.1059)"/> + <int value="1068172351" label="Windows 10 1709 (Build 16299.1087)"/> + <int value="1068172391" label="Windows 10 1709 (Build 16299.1127)"/> + <int value="1068172410" label="Windows 10 1709 (Build 16299.1146)"/> + <int value="1068172446" label="Windows 10 1709 (Build 16299.1182)"/> + <int value="1068172481" label="Windows 10 1709 (Build 16299.1217)"/> + <int value="1068172501" label="Windows 10 1709 (Build 16299.1237)"/> + <int value="1068172503" label="Windows 10 1709 (Build 16299.1239)"/> + <int value="1068172532" label="Windows 10 1709 (Build 16299.1268)"/> + <int value="1068172560" label="Windows 10 1709 (Build 16299.1296)"/> + <int value="1122893856" label="Windows 10 1803 (Build 17134.32)"/> + <int value="1122893872" label="Windows 10 1803 (Build 17134.48)"/> + <int value="1122893883" label="Windows 10 1803 (Build 17134.59)"/> + <int value="1122893905" label="Windows 10 1803 (Build 17134.81)"/> + <int value="1122893907" label="Windows 10 1803 (Build 17134.83)"/> + <int value="1122893910" label="Windows 10 1803 (Build 17134.86)"/> + <int value="1122893936" label="Windows 10 1803 (Build 17134.112)"/> + <int value="1122893961" label="Windows 10 1803 (Build 17134.137)"/> + <int value="1122893989" label="Windows 10 1803 (Build 17134.165)"/> + <int value="1122893991" label="Windows 10 1803 (Build 17134.167)"/> + <int value="1122894015" label="Windows 10 1803 (Build 17134.191)"/> + <int value="1122894052" label="Windows 10 1803 (Build 17134.228)"/> + <int value="1122894078" label="Windows 10 1803 (Build 17134.254)"/> + <int value="1122894109" label="Windows 10 1803 (Build 17134.285)"/> + <int value="1122894110" label="Windows 10 1803 (Build 17134.286)"/> + <int value="1122894169" label="Windows 10 1803 (Build 17134.345)"/> + <int value="1122894200" label="Windows 10 1803 (Build 17134.376)"/> + <int value="1122894231" label="Windows 10 1803 (Build 17134.407)"/> + <int value="1122894265" label="Windows 10 1803 (Build 17134.441)"/> + <int value="1122894295" label="Windows 10 1803 (Build 17134.471)"/> + <int value="1122894296" label="Windows 10 1803 (Build 17134.472)"/> + <int value="1122894347" label="Windows 10 1803 (Build 17134.523)"/> + <int value="1122894380" label="Windows 10 1803 (Build 17134.556)"/> + <int value="1122894443" label="Windows 10 1803 (Build 17134.619)"/> + <int value="1122894472" label="Windows 10 1803 (Build 17134.648)"/> + <int value="1122894501" label="Windows 10 1803 (Build 17134.677)"/> + <int value="1122894530" label="Windows 10 1803 (Build 17134.706)"/> + <int value="1122894577" label="Windows 10 1803 (Build 17134.753)"/> + <int value="1122894589" label="Windows 10 1803 (Build 17134.765)"/> + <int value="1122894590" label="Windows 10 1803 (Build 17134.766)"/> + <int value="1122894623" label="Windows 10 1803 (Build 17134.799)"/> + <int value="1122894653" label="Windows 10 1803 (Build 17134.829)"/> + <int value="1122894682" label="Windows 10 1803 (Build 17134.858)"/> + <int value="1122894709" label="Windows 10 1803 (Build 17134.885)"/> + <int value="1122894739" label="Windows 10 1803 (Build 17134.915)"/> + <int value="1164115969" label="Windows 10 1809 (Build 17763.1)"/> + <int value="1164116023" label="Windows 10 1809 (Build 17763.55)"/> + <int value="1164116075" label="Windows 10 1809 (Build 17763.107)"/> + <int value="1164116102" label="Windows 10 1809 (Build 17763.134)"/> + <int value="1164116136" label="Windows 10 1809 (Build 17763.168)"/> + <int value="1164116162" label="Windows 10 1809 (Build 17763.194)"/> + <int value="1164116163" label="Windows 10 1809 (Build 17763.195)"/> + <int value="1164116221" label="Windows 10 1809 (Build 17763.253)"/> + <int value="1164116260" label="Windows 10 1809 (Build 17763.292)"/> + <int value="1164116284" label="Windows 10 1809 (Build 17763.316)"/> + <int value="1164116316" label="Windows 10 1809 (Build 17763.348)"/> + <int value="1164116347" label="Windows 10 1809 (Build 17763.379)"/> + <int value="1164116372" label="Windows 10 1809 (Build 17763.404)"/> + <int value="1164116405" label="Windows 10 1809 (Build 17763.437)"/> + <int value="1164116407" label="Windows 10 1809 (Build 17763.439)"/> + <int value="1164116443" label="Windows 10 1809 (Build 17763.475)"/> + <int value="1164116471" label="Windows 10 1809 (Build 17763.503)"/> + <int value="1164116472" label="Windows 10 1809 (Build 17763.504)"/> + <int value="1164116497" label="Windows 10 1809 (Build 17763.529)"/> + <int value="1164116525" label="Windows 10 1809 (Build 17763.557)"/> + <int value="1164116560" label="Windows 10 1809 (Build 17763.592)"/> + <int value="1164116561" label="Windows 10 1809 (Build 17763.593)"/> + <int value="1164116583" label="Windows 10 1809 (Build 17763.615)"/> + <int value="1164116620" label="Windows 10 1809 (Build 17763.652)"/> + <int value="1203372148" label="Windows 10 1903 (Build 18362.116)"/> + <int value="1203372177" label="Windows 10 1903 (Build 18362.145)"/> + <int value="1203372207" label="Windows 10 1903 (Build 18362.175)"/> + <int value="1203372239" label="Windows 10 1903 (Build 18362.207)"/> + <int value="1203372271" label="Windows 10 1903 (Build 18362.239)"/> +</enum> + <enum name="WindowsToastActivatorCLSIDMismatchReason"> <obsolete> Deprecated 12/2018 as this is no longer needed.
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index ca9493c..8c92b48 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -56,6 +56,17 @@ </summary> </histogram> +<histogram name="Accessibility.Android.ScreenReader" enum="BooleanEnabled" + expires_after="never"> +<!-- expires-never: usage drives a11y prioritization in browser and content. --> + + <owner>aleventhal@chromium.org</owner> + <summary> + Tracks whether a screen reader is enabled on Android (e.g. Talkback). This + is checked once, 45 seconds after startup. + </summary> +</histogram> + <histogram name="Accessibility.Android.TabSwitcherPreferenceEnabled" enum="BooleanEnabled"> <owner>twellington@chromium.org</owner> @@ -461,6 +472,17 @@ </summary> </histogram> +<histogram name="Accessibility.Mac.ScreenReader" enum="BooleanEnabled" + expires_after="never"> +<!-- expires-never: usage drives a11y prioritization in browser and content. --> + + <owner>aleventhal@chromium.org</owner> + <summary> + Tracks whether a screen reader is enabled on Mac (e.g. VoiceOver). This is + checked once, 45 seconds after startup. + </summary> +</histogram> + <histogram name="Accessibility.ManuallyEnabled" enum="BooleanEnabled" expires_after="M85"> <owner>dmazzoni@chromium.org</owner> @@ -580,9 +602,12 @@ </histogram> <histogram name="Accessibility.WinJAWS" enum="BooleanEnabled" - expires_after="2019-11-02"> + expires_after="never"> +<!-- expires-never: usage drives a11y prioritization in browser and content. --> + <owner>dmazzoni@chromium.org</owner> <owner>kenjibaheux@google.com</owner> + <owner>aleventhal@chromium.org</owner> <summary> Whether the third-party JAWS screen reader is running (checked once 45 secs after startup). @@ -590,9 +615,12 @@ </histogram> <histogram name="Accessibility.WinNVDA" enum="BooleanEnabled" - expires_after="2019-11-02"> + expires_after="never"> +<!-- expires-never: usage drives a11y prioritization in browser and content. --> + <owner>dmazzoni@chromium.org</owner> <owner>kenjibaheux@google.com</owner> + <owner>aleventhal@chromium.org</owner> <summary> Whether the third-party NVDA screen reader is running (checked once 45 secs after startup). @@ -621,19 +649,37 @@ </summary> </histogram> +<histogram name="Accessibility.WinScreenReader2" enum="BooleanEnabled"> +<!-- expires-never: usage drives a11y prioritization in browser and content. --> + + <owner>aleventhal@chromium.org</owner> + <summary> + Whether the accessibility mode flag shows that a screen reader is running + (checked once 45 secs after startup). In this case, Chrome has detected + accessibility calls that would normally only occur from a screen reader. See + also the more specific metrics such as Accessibility.WinJAWS/WinNVDA. + </summary> +</histogram> + <histogram name="Accessibility.WinStickyKeys" enum="BooleanEnabled" - expires_after="2019-11-02"> + expires_after="never"> +<!-- expires-never: usage drives a11y prioritization in browser and content. --> + <owner>dmazzoni@chromium.org</owner> <owner>kenjibaheux@google.com</owner> + <owner>aleventhal@chromium.org</owner> <summary> Whether Windows system settings show that Sticky Keys are enabled. </summary> </histogram> <histogram name="Accessibility.WinZoomText" enum="BooleanEnabled" - expires_after="2019-11-02"> + expires_after="never"> +<!-- expires-never: usage drives a11y prioritization in browser and content. --> + <owner>dmazzoni@chromium.org</owner> <owner>kenjibaheux@google.com</owner> + <owner>aleventhal@chromium.org</owner> <summary> Whether the third-party ZoomText screen magnifier is running. </summary> @@ -6729,15 +6775,14 @@ </summary> </histogram> -<histogram name="Ash.Pip.Events" enum="AshPipEvents" expires_after="2019-09-01"> +<histogram name="Ash.Pip.Events" enum="AshPipEvents" expires_after="M82"> <owner>edcourtney@chromium.org</owner> <summary> Various individiual Picture-in-picture related events. See AshPipEvents. </summary> </histogram> -<histogram name="Ash.Pip.FreeResizeFinishArea" units="%" - expires_after="2019-09-01"> +<histogram name="Ash.Pip.FreeResizeFinishArea" units="%" expires_after="M82"> <owner>edcourtney@chromium.org</owner> <summary> Area of a Picture-in-picture window when ending a free-resize, as a @@ -6745,8 +6790,7 @@ </summary> </histogram> -<histogram name="Ash.Pip.FreeResizeInitialArea" units="%" - expires_after="2019-09-01"> +<histogram name="Ash.Pip.FreeResizeInitialArea" units="%" expires_after="M82"> <owner>edcourtney@chromium.org</owner> <summary> Initial area of a Picture-in-picture window when beginning a free-resize, as @@ -6754,8 +6798,7 @@ </summary> </histogram> -<histogram name="Ash.Pip.Position" enum="AshPipPosition" - expires_after="2019-09-01"> +<histogram name="Ash.Pip.Position" enum="AshPipPosition" expires_after="M82"> <owner>edcourtney@chromium.org</owner> <summary> The position that a Picture-in-picture window was moved to by a user drag. @@ -11871,6 +11914,74 @@ </summary> </histogram> +<histogram base="true" name="Availability.Prober.CacheEntryAge" units="hours" + expires_after="2020-08-01"> + <owner>robertogden@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary> + How old a cached probe result was when it was used, in hours. + </summary> +</histogram> + +<histogram base="true" name="Availability.Prober.DidSucceed" + enum="BooleanSuccess" expires_after="2020-08-01"> + <owner>robertogden@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary>Records the completion status of a probe when it completes.</summary> +</histogram> + +<histogram base="true" name="Availability.Prober.NetError" enum="NetErrorCodes" + expires_after="2020-08-01"> + <owner>robertogden@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary> + Records the net error of a completed or timed out probe. Note that if a HTTP + response does not occur within the probe's TTL, when a sample will also be + added to the ERR_TIMED_OUT bucket. + </summary> +</histogram> + +<histogram base="true" name="Availability.Prober.NumAttemptsBeforeSuccess" + units="count" expires_after="2020-08-01"> + <owner>robertogden@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary> + Records the number of attempts that are made to achieve a successful probe + result. Only recorded on success. This metric is 1-based so if a probe + succeeds the first time, a sample of 1 will be recorded. + </summary> +</histogram> + +<histogram base="true" name="Availability.Prober.ResponseCode" + enum="HttpResponseCode" expires_after="2020-08-01"> + <owner>robertogden@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary> + Records the HTTP response code of a completed probe, when a HTTP response is + received. + </summary> +</histogram> + +<histogram base="true" name="Availability.Prober.TimeUntilFailure" units="ms" + expires_after="2020-08-01"> + <owner>robertogden@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary> + Records the amount of time spent working on a single probe attempt to get to + a failed state. Recorded every time a probe fails. + </summary> +</histogram> + +<histogram base="true" name="Availability.Prober.TimeUntilSuccess" units="ms" + expires_after="2020-08-01"> + <owner>robertogden@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary> + Records the amount of time spent working on a single probe attempt to get to + a successful state. Recorded every time a probe succeeds. + </summary> +</histogram> + <histogram base="true" name="BackgroundFetch.EventDispatchFailure.Dispatch" enum="ServiceWorkerStatusCode"> <!-- Name completed by histogram_suffixes name="BackgroundFetchEvents" --> @@ -18436,20 +18547,41 @@ <histogram name="ChromeColors.AppliedColor" enum="ChromeColorsInfo" expires_after="2019-12-31"> <owner>gayane@chromium.org</owner> + <owner>yyushkina@chromium.org</owner> <summary> Records applied color id every time its applied from Colors menu. </summary> </histogram> +<histogram name="ChromeColors.ChangesConfirmed" + enum="BooleanChromeColorsChangesConfirmed" expires_after="2019-12-31"> + <owner>gayane@chromium.org</owner> + <owner>yyushkina@chromium.org</owner> + <summary> + Records whether color/theme changes were confirmed or reverted by + ChromeColorsService. + </summary> +</histogram> + <histogram name="ChromeColors.ColorOnLoad" enum="ChromeColorsInfo" expires_after="2019-12-31"> <owner>gayane@chromium.org</owner> + <owner>yyushkina@chromium.org</owner> <summary> Records installed color id every time theme service is initialized from prefs. Happens once per profile load. </summary> </histogram> +<histogram name="ChromeColors.RevertReason" enum="ChromeColorsRevertReason" + expires_after="2019-12-31"> + <owner>gayane@chromium.org</owner> + <owner>yyushkina@chromium.org</owner> + <summary> + Records the reason color/theme changes were reverted by ChromeColorsService. + </summary> +</histogram> + <histogram name="ChromeElf.ApplyHookResult" enum="NTSTATUS" expires_after="M77"> <owner>pmonette@chromium.org</owner> <summary> @@ -32864,7 +32996,7 @@ </histogram> <histogram name="DrmUtil.CreateDisplaySnapshot.HasEdidBlob" enum="Boolean" - expires_after="M77"> + expires_after="2020-07-24"> <owner>andrescj@chromium.org</owner> <owner>mcasas@chromium.org</owner> <summary> @@ -32874,7 +33006,7 @@ </histogram> <histogram name="DrmUtil.GetColorSpaceFromEdid.ChecksOutcome" - enum="EdidColorSpaceChecksOutcome" expires_after="M77"> + enum="EdidColorSpaceChecksOutcome" expires_after="2020-07-24"> <owner>andrescj@chromium.org</owner> <owner>mcasas@chromium.org</owner> <summary> @@ -38841,9 +38973,9 @@ </histogram> <histogram name="ExtensionBlacklist.BlacklistInstalled" - enum="ExtensionLocation"> - <owner>vakh@chromium.org</owner> - <owner>chrome-safebrowsing-alerts@google.com</owner> + enum="ExtensionLocation" expires_after="M78"> + <owner>rdevlin.cronin@chromium.org</owner> + <owner>extensions-core@chromium.org</owner> <summary> The number of extensions that were blacklisted when already installed, grouped by Extension::Location. Logged when ExtensionService blackists and @@ -38852,9 +38984,9 @@ </histogram> <histogram name="ExtensionBlacklist.BlockCRX" enum="ExtensionLocation" - expires_after="M77"> - <owner>vakh@chromium.org</owner> - <owner>chrome-safebrowsing-alerts@google.com</owner> + expires_after="M78"> + <owner>rdevlin.cronin@chromium.org</owner> + <owner>extensions-core@chromium.org</owner> <summary> The number of extensions that have been blocked from installing grouped by Extension::Location. Logged when ExtensionService refuses to install a @@ -38862,9 +38994,10 @@ </summary> </histogram> -<histogram name="ExtensionBlacklist.SilentInstall" enum="ExtensionLocation"> - <owner>vakh@chromium.org</owner> - <owner>chrome-safebrowsing-alerts@google.com</owner> +<histogram name="ExtensionBlacklist.SilentInstall" enum="ExtensionLocation" + expires_after="M78"> + <owner>rdevlin.cronin@chromium.org</owner> + <owner>extensions-core@chromium.org</owner> <summary> The number of extensions that have been silently installed in a blacklisted state, grouped by Extension::Location. Logged when ExtensionService installs @@ -38875,9 +39008,9 @@ </histogram> <histogram name="ExtensionBlacklist.UnblacklistInstalled" - enum="ExtensionLocation" expires_after="M77"> - <owner>vakh@chromium.org</owner> - <owner>chrome-safebrowsing-alerts@google.com</owner> + enum="ExtensionLocation" expires_after="M78"> + <owner>rdevlin.cronin@chromium.org</owner> + <owner>extensions-core@chromium.org</owner> <summary> The number of extensions that were unblacklisted when installed, grouped by Extension::Location. Logged when ExtensionService unblacklists and loads a @@ -40195,6 +40328,9 @@ <histogram name="Extensions.DeclarativeWebRequest.WebViewRequestDeclarativeRules" enum="BooleanDeclarativeRules" expires_after="M78"> + <obsolete> + Removed July 2019. + </obsolete> <owner>karandeepb@chromium.org</owner> <summary> Whether a network request from a guest webview has any declarative web @@ -53660,6 +53796,175 @@ </summary> </histogram> +<histogram name="Kerberos.AcquireKerberosTgtTime" units="ms" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Time in milliseconds to acquire a Kerberos ticket. The value is recorded no + matter if the operation was successful or not. + </summary> +</histogram> + +<histogram name="Kerberos.DailyActiveUsers" enum="KerberosUserType" + expires_after="2021-05-31"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Type of the Chrome OS login user (primary user) who requests Kerberos + tickets. Reported at most once a day by the Kerberos daemon when a Kebreros + ticket is acquired or Kerberos files are requested, which happens e.g. on + Chrome startup. + </summary> +</histogram> + +<histogram name="Kerberos.NumberOfAccounts.Managed" expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Number of managed Kerberos accounts owned by the current Chrome OS user. A + managed account is an account that got added via the KerberosAccounts + policy. Reported at most once a day similar to Kerberos.DailyActiveUsers. + </summary> +</histogram> + +<histogram name="Kerberos.NumberOfAccounts.RememberedPassword" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Number of Kerberos accounts owned by the current Chrome OS user that use the + 'Remember password' feature, i.e. the account password is stored by the + Kerberos daemon. Reported at most once a day similar to + Kerberos.DailyActiveUsers. + </summary> +</histogram> + +<histogram name="Kerberos.NumberOfAccounts.Total" expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Total number of Kerberos accounts owned by the current Chrome OS user. + Reported at most once a day similar to Kerberos.DailyActiveUsers. + </summary> +</histogram> + +<histogram name="Kerberos.NumberOfAccounts.Unmanaged" expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Number of unmanaged Kerberos accounts owned by the current Chrome OS user. + An unmanaged account is an account that was added manually by the user. + Reported at most once a day similar to Kerberos.DailyActiveUsers. + </summary> +</histogram> + +<histogram name="Kerberos.NumberOfAccounts.UseLoginPassword" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Number of Kerberos accounts owned by the current Chrome OS user that use the + login password for authentication. These accounts were added via the + KerberosAccounts policy, using the '${PASSWORD}' placeholder as password. + Reported at most once a day similar to Kerberos.DailyActiveUsers. + </summary> +</histogram> + +<histogram name="Kerberos.Result.AcquireKerberosTgt" enum="KerberosErrorType" + expires_after="2021-05-31"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Result from an attempt to acquire a Kerberos ticket. This happens whenever a + new ticket is added or an existing ticket is reauthenticated. + </summary> +</histogram> + +<histogram name="Kerberos.Result.AddAccount" enum="KerberosErrorType" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Result from an attempt to add a new Kerberos account, either through the + Kerberos Tickets settings page or via the KerberosAccounts policy. + </summary> +</histogram> + +<histogram name="Kerberos.Result.ClearAccounts" enum="KerberosErrorType" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Result from an attempt to clear Kerberos accounts, usually through toggling + Kerberos related policies. For instance, disabling the KerberosEnabled + policy clears all accounts. + </summary> +</histogram> + +<histogram name="Kerberos.Result.GetKerberosFiles" enum="KerberosErrorType" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Result from an attempt to retrieve a Kerberos ticket from the Kerberos + daemon. Systems using Kerberos (Chrome, SMB file shares) perform this action + during startup and when they get notified that the files changed. + </summary> +</histogram> + +<histogram name="Kerberos.Result.ListAccounts" enum="KerberosErrorType" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Result from an attempt to list Kerberos accounts, usually through opening + the Kerberos Tickets settings page or making changes to accounts. + </summary> +</histogram> + +<histogram name="Kerberos.Result.RemoveAccount" enum="KerberosErrorType" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Result from an attempt to remove a new Kerberos account through the Kerberos + Tickets settings page. + </summary> +</histogram> + +<histogram name="Kerberos.Result.SetConfig" enum="KerberosErrorType" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Result from an attempt to set Kerberos configuration. This happens right + before acquiring a Kerberos ticket. + </summary> +</histogram> + +<histogram name="Kerberos.Result.ValidateConfig" enum="KerberosErrorType" + expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Result from an attempt to validate Kerberos configuration. This happens when + the user tries to set configuration in the Advanced section of the dialog to + add new Kerberos tickets. + </summary> +</histogram> + +<histogram name="Kerberos.ValidateConfigErrorCode" + enum="KerberosConfigErrorCode" expires_after="M83"> + <owner>ljusten@chromium.org</owner> + <owner>rsorokin@chromium.org</owner> + <summary> + Error code from an attempt validate Kerberos configuration. Contains more + specific information than KerberosErrorType about the result of the + validation. + </summary> +</histogram> + <histogram name="Keyboard.KeystrokeDeltas" units="ms" expires_after="2016-07-28"> <obsolete> @@ -105492,74 +105797,6 @@ <summary>Records why the page load ended on a given preview type.</summary> </histogram> -<histogram base="true" name="Previews.Prober.CacheEntryAge" units="hours" - expires_after="2020-08-01"> - <owner>robertogden@chromium.org</owner> - <owner>tbansal@chromium.org</owner> - <summary> - How old a cached probe result was when it was used, in hours. - </summary> -</histogram> - -<histogram base="true" name="Previews.Prober.DidSucceed" enum="BooleanSuccess" - expires_after="2020-08-01"> - <owner>robertogden@chromium.org</owner> - <owner>tbansal@chromium.org</owner> - <summary>Records the completion status of a probe when it completes.</summary> -</histogram> - -<histogram base="true" name="Previews.Prober.NetError" enum="NetErrorCodes" - expires_after="2020-08-01"> - <owner>robertogden@chromium.org</owner> - <owner>tbansal@chromium.org</owner> - <summary> - Records the net error of a completed or timed out probe. Note that if a HTTP - response does not occur within the probe's TTL, when a sample will also be - added to the ERR_TIMED_OUT bucket. - </summary> -</histogram> - -<histogram base="true" name="Previews.Prober.NumAttemptsBeforeSuccess" - units="count" expires_after="2020-08-01"> - <owner>robertogden@chromium.org</owner> - <owner>tbansal@chromium.org</owner> - <summary> - Records the number of attempts that are made to achieve a successful probe - result. Only recorded on success. This metric is 1-based so if a probe - succeeds the first time, a sample of 1 will be recorded. - </summary> -</histogram> - -<histogram base="true" name="Previews.Prober.ResponseCode" - enum="HttpResponseCode" expires_after="2020-08-01"> - <owner>robertogden@chromium.org</owner> - <owner>tbansal@chromium.org</owner> - <summary> - Records the HTTP response code of a completed probe, when a HTTP response is - received. - </summary> -</histogram> - -<histogram base="true" name="Previews.Prober.TimeUntilFailure" units="ms" - expires_after="2020-08-01"> - <owner>robertogden@chromium.org</owner> - <owner>tbansal@chromium.org</owner> - <summary> - Records the amount of time spent working on a single probe attempt to get to - a failed state. Recorded every time a probe fails. - </summary> -</histogram> - -<histogram base="true" name="Previews.Prober.TimeUntilSuccess" units="ms" - expires_after="2020-08-01"> - <owner>robertogden@chromium.org</owner> - <owner>tbansal@chromium.org</owner> - <summary> - Records the amount of time spent working on a single probe attempt to get to - a successful state. Recorded every time a probe succeeds. - </summary> -</histogram> - <histogram name="Previews.ProcessHintsResult" enum="PreviewsProcessHintsResult"> <obsolete> Merged with OptimizationGuide.ProcessHintsResult in 07/2019. @@ -114079,7 +114316,10 @@ </histogram> <histogram name="SafeBrowsing.V4Store.IsStoreAvailable.ValidStore" - enum="BooleanAvailable" expires_after="M78"> + enum="BooleanAvailable" expires_after="M77"> + <obsolete> + Removed in M77 since the histogram was very stable: crbug.com/984286. + </obsolete> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -115326,7 +115566,7 @@ </histogram> <histogram name="SB2.RemoteCall.CanUseLocalBlacklists" - enum="SB2RemoteCallCanUseLocalBlacklists" expires_after="M77"> + enum="SB2RemoteCallCanUseLocalBlacklists" expires_after="M81"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -115414,7 +115654,10 @@ </histogram> <histogram name="SB2.RemoteCall.InternalErrorStatusCode2" - enum="GooglePlayServicesConnectionResult" expires_after="M77"> + enum="GooglePlayServicesConnectionResult" expires_after="never"> +<!-- expires-never: This tracks the result of connecting to GmsCore for +Safe Browsing lookups, which is critical for security. --> + <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -115427,7 +115670,7 @@ </histogram> <histogram name="SB2.RemoteCall.LocalBlacklistsAgeInMs" units="ms" - expires_after="M77"> + expires_after="M81"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -115450,7 +115693,7 @@ </histogram> <histogram name="SB2.RemoteCall.LocalBlacklistsUpdateSucceeded" - enum="BooleanSuccess" expires_after="M77"> + enum="BooleanSuccess" expires_after="M81"> <owner>vakh@chromium.org</owner> <owner>chrome-safebrowsing-alerts@google.com</owner> <summary> @@ -122952,6 +123195,18 @@ </summary> </histogram> +<histogram name="ServiceWorkerCache.PeakParallelSharedOps" units="operations" + expires_after="M85"> + <owner>wanderview@chromium.org</owner> + <owner>chrome-owp-storage@google.com</owner> + <summary> + The peak number of shared operations that ran simultaneously during a single + "batch" of operations. A batch is defined as the time from when an + idle scheduler begins running a shared operation until the count of running + shared operations drops back to zero. + </summary> +</histogram> + <histogram name="ServiceWorkerCache.Response.HasDeprecatedURL" enum="Boolean" expires_after="M77"> <obsolete> @@ -125017,6 +125272,8 @@ <histogram name="Sharing.ClickToCallAppsToShow" units="apps" expires_after="2020-02-02"> +<!-- Name completed by histogram_suffixes name="SharingClickToCallUi" --> + <owner>mvanouwerkerk@chromium.org</owner> <owner>peter@chromium.org</owner> <summary> @@ -125027,6 +125284,8 @@ <histogram name="Sharing.ClickToCallDevicesToShow" units="devices" expires_after="2020-02-02"> +<!-- Name completed by histogram_suffixes name="SharingClickToCallUi" --> + <owner>mvanouwerkerk@chromium.org</owner> <owner>peter@chromium.org</owner> <summary> @@ -125046,6 +125305,16 @@ </summary> </histogram> +<histogram name="Sharing.ClickToCallDialogShown" + enum="SharingClickToCallDialogType" expires_after="2020-02-02"> + <owner>mvanouwerkerk@chromium.org</owner> + <owner>knollr@chromium.org</owner> + <summary> + Logged whenever a dialog is shown for the Click to Call feature. Desktop + only. + </summary> +</histogram> + <histogram name="Sharing.ClickToCallSelectedAppIndex" units="index" expires_after="2020-02-02"> <!-- Name completed by histogram_suffixes name="SharingClickToCallUi" --> @@ -125562,21 +125831,14 @@ </summary> </histogram> -<histogram base="true" name="Signin.AndroidGetAccountsTime" units="ms" - expires_after="M81"> - <owner>bsazonov@chromium.org</owner> - <owner>alexilin@chromium.org</owner> +<histogram name="Signin.AndroidGetAccountsTime" units="ms"> + <owner>nyquist@chromium.org</owner> <summary> - The time it takes to populate or update the accounts cache in - AccountManagerFacade. + The time it takes to retrieve the list of accounts from the system. </summary> </histogram> <histogram name="Signin.AndroidGetAccountsTimeUiThread" units="ms"> - <obsolete> - Removed in 07/2019. The list of accounts is no longer retrieved on the UI - thread. - </obsolete> <owner>bsazonov@chromium.org</owner> <summary> The time it takes to retrieve the list of accounts from the system on the UI @@ -134909,6 +135171,9 @@ <histogram name="Sync.MemoryPressureWarningBeforeCleanShutdown" units="count" expires_after="M77"> + <obsolete> + Removed 2019-07. + </obsolete> <owner>gangwu@chromium.org</owner> <summary> Counts the number of times a user's sync service received a @@ -134925,6 +135190,9 @@ <histogram name="Sync.MemoryPressureWarningBeforeUncleanShutdown" units="count" expires_after="M77"> + <obsolete> + Removed 2019-07. + </obsolete> <owner>gangwu@chromium.org</owner> <summary> Counts the number of times a user's sync service received a @@ -139864,7 +140132,7 @@ </summary> </histogram> -<histogram name="Thumbnails.CopyFromSurfaceTime" units="ms" expires_after="M78"> +<histogram name="Thumbnails.CopyFromSurfaceTime" units="ms" expires_after="M81"> <owner>dfried@chromium.org</owner> <owner>pbos@chromium.org</owner> <summary> @@ -139895,7 +140163,7 @@ </summary> </histogram> -<histogram name="Thumbnails.ProcessBitmapTime" units="ms" expires_after="M78"> +<histogram name="Thumbnails.ProcessBitmapTime" units="ms" expires_after="M81"> <owner>dfried@chromium.org</owner> <owner>pbos@chromium.org</owner> <summary> @@ -140307,6 +140575,16 @@ </summary> </histogram> +<histogram name="Tracing.Background.FinalizationDisallowedReason" + enum="TracingFinalizationDisallowedReason" expires_after="2020-01-30"> + <owner>ssid@chromium.org</owner> + <summary> + Reason why background tracing finalization was not allowed. Also see + "Tracing.Background.ScenarioState" metric, which records the total + number of times finalization was allowed and not allowed. + </summary> +</histogram> + <histogram name="Tracing.Background.FinalizingTraceSizeInKB" units="KB"> <owner>oysteine@chromium.org</owner> <summary> @@ -140314,6 +140592,24 @@ </summary> </histogram> +<histogram name="Tracing.Background.NetworkConnectionTypeWhenStarted" + enum="NetworkConnectionType" expires_after="2019-10-10"> + <owner>ssid@chromium.org</owner> + <summary> + Connection type of the network used to determine the trace buffer size, when + background tracing was triggered. Recorded only on Android. + </summary> +</histogram> + +<histogram name="Tracing.Background.NetworkConnectionTypeWhenUploaded" + enum="NetworkConnectionType" expires_after="2019-10-10"> + <owner>ssid@chromium.org</owner> + <summary> + Connection type of the network used to determine the trace upload limit, + when background tracing upload was started. Recorded only on Android. + </summary> +</histogram> + <histogram name="Tracing.Background.ScenarioState" enum="BackgroundTracingState"> <owner>oysteine@chromium.org</owner> @@ -142553,7 +142849,8 @@ <histogram name="UnifiedConsent.SyncAndGoogleServicesSettings" enum="UnifiedConsentSyncAndGoogleServicesSettings" - expires_after="2019-08-21"> + expires_after="2019-12-21"> + <owner>msarda@chromium.org</owner> <owner>tangltom@chromium.org</owner> <owner>droger@chromium.org</owner> <summary> @@ -144795,6 +145092,20 @@ </summary> </histogram> +<histogram name="V8.TurboFan1KTicks" units="1000 ticks" + expires_after="2020-01-23"> + <owner>tebbi@chromium.org</owner> + <owner>mvstanton@chromium.org</owner> + <summary> + Number of ticks (in 1000s of ticks) from starting optimizing to installing + the code object. Recorded on each regular optimization of a function. + + Similar to V8.TurboFanOptimizeTotalTime, but instead of counting time, we + count a deterministic number of ticks sprinkled throughout the Turbofan + compiler. + </summary> +</histogram> + <histogram name="V8.TurboFanOptimizeExecute" units="microseconds" expires_after="M80"> <owner>bmeurer@chromium.org</owner> @@ -153557,6 +153868,19 @@ </summary> </histogram> +<histogram name="Windows.PatchLevel" enum="WindowsPatchLevel"> + <owner>wfh@chromium.org</owner> + <owner>brucedawson@chromium.org</owner> + <summary> + A 32-bit value formed from combining the minor and patch level of the + currently running Windows operating system. E.g. "Windows 10 OS Version + 1809 (Build 17763.503)" would be 17763 (0x4563), combined with 503 + (0x1F7) = 0x456301F7. If either minor or patch level exceeds the value that + can fit in a 16-bit unsigned integer, then this histogram will report 0. + Reported once, shortly after browser startup. + </summary> +</histogram> + <histogram base="true" name="Windows.PostOperationState" enum="PostOperationState"> <owner>grt@chromium.org</owner> @@ -154769,24 +155093,11 @@ <affected-histogram name="Bluetooth.Web.Android"/> </histogram_suffixes> -<histogram_suffixes name="AndroidGetAccountsAPITypes" separator="_"> - <suffix base="true" name="AccountManager" - label="Using Android AccountManager API."/> - <suffix base="true" name="GoogleAuthUtil" label="Using GoogleAuthUtil API."/> +<histogram_suffixes name="AndroidGetAccountsTypes" separator="_"> + <suffix name="AccountManager" label="Using Android AccountManager API"/> + <suffix name="GoogleAuthUtil" label="Using GoogleAuthUtil API"/> <affected-histogram name="Signin.AndroidGetAccountsTime"/> - <affected-histogram name="Signin.AndroidGetAccountsTimeUiThread"> - <obsolete> - Removed in 07/2019. - </obsolete> - </affected-histogram> -</histogram_suffixes> - -<histogram_suffixes name="AndroidGetAccountsDurationTypes" separator="."> - <suffix name="Accounts" label="Obtaining a list of all accounts."/> - <suffix name="Ids" label="Getting account ids for all accounts."/> - <suffix name="Total" label="Total duration."/> - <affected-histogram name="Signin.AndroidGetAccountsTime_AccountManager"/> - <affected-histogram name="Signin.AndroidGetAccountsTime_GoogleAuthUtil"/> + <affected-histogram name="Signin.AndroidGetAccountsTimeUiThread"/> </histogram_suffixes> <histogram_suffixes name="AndroidProcessType" separator="."> @@ -155328,6 +155639,17 @@ <affected-histogram name="Autofill.WalletCards2"/> </histogram_suffixes> +<histogram_suffixes name="Availability.Prober.Clients" separator="."> + <suffix name="Litepages" label="Lite page HTTPS Server Previews"/> + <affected-histogram name="Availability.Prober.CacheEntryAge"/> + <affected-histogram name="Availability.Prober.DidSucceed"/> + <affected-histogram name="Availability.Prober.NetError"/> + <affected-histogram name="Availability.Prober.NumAttemptsBeforeSuccess"/> + <affected-histogram name="Availability.Prober.ResponseCode"/> + <affected-histogram name="Availability.Prober.TimeUntilFailure"/> + <affected-histogram name="Availability.Prober.TimeUntilSuccess"/> +</histogram_suffixes> + <histogram_suffixes name="BackgroundFetchDatabaseStorageErrors" separator="."> <suffix name="CleanupTask" label="CleanupTask"/> <suffix name="CreateMetadataTask" label="CreateMetadata DatabaseTask"/> @@ -165326,17 +165648,6 @@ <affected-histogram name="Prerender.TimeUntilUsed2"/> </histogram_suffixes> -<histogram_suffixes name="Previews.Prober.Clients" separator="."> - <suffix name="Litepages" label="Lite page HTTPS Server Previews"/> - <affected-histogram name="Previews.Prober.CacheEntryAge"/> - <affected-histogram name="Previews.Prober.DidSucceed"/> - <affected-histogram name="Previews.Prober.NetError"/> - <affected-histogram name="Previews.Prober.NumAttemptsBeforeSuccess"/> - <affected-histogram name="Previews.Prober.ResponseCode"/> - <affected-histogram name="Previews.Prober.TimeUntilFailure"/> - <affected-histogram name="Previews.Prober.TimeUntilSuccess"/> -</histogram_suffixes> - <histogram_suffixes name="Previews.ServerLitePage.Penalty.Types" separator="."> <suffix name="Bypass" label="Bypass"/> <suffix name="Failure" label="Failure"/> @@ -167656,6 +167967,8 @@ <histogram_suffixes name="SharingClickToCallUi" separator="."> <suffix name="ContextMenu" label="Context menu"/> <suffix name="Dialog" label="Dialog"/> + <affected-histogram name="Sharing.ClickToCallAppsToShow"/> + <affected-histogram name="Sharing.ClickToCallDevicesToShow"/> <affected-histogram name="Sharing.ClickToCallSelectedAppIndex"/> <affected-histogram name="Sharing.ClickToCallSelectedDeviceIndex"/> </histogram_suffixes> @@ -168473,6 +168786,7 @@ </histogram_suffixes> <histogram_suffixes name="SystemNotificationAgeType" separator="."> + <suffix name="ClickToCall" label="Click To Call"/> <suffix name="SendTabToSelf" label="Send Tab To Self"/> <affected-histogram name="Mobile.SystemNotification.Action.Click.Age"/> <affected-histogram name="Mobile.SystemNotification.Content.Click.Age"/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index 61948da3..1074ce8b 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -678,6 +678,237 @@ </metric> </event> +<event name="AppListNonAppImpression"> + <owner>jiameng@chromium.org</owner> + <owner>thanhdng@chromium.org</owner> + <owner>tby@chromium.org</owner> + <summary> + Records details of impressions and launches of non-apps in the ChromeOS + launcher, such as files, omnibox results, and answer cards. + </summary> + <metric name="Category" enum="AppListNonAppImpressionCategory"> + <summary> + The kind of launcher item. Corresponds to the value of + ChromeSearchResult::result_[sub]type. + </summary> + </metric> + <metric name="DayOfWeek"> + <summary> + The day of the week that the event was logged on, in the local time zone. + Sunday is 0. + </summary> + </metric> + <metric name="DeviceMode" enum="AppListNonAppImpressionDeviceMode"> + <summary> + The mode of the device. + </summary> + </metric> + <metric name="EventId"> + <summary> + An ID linking together events within a single set of launcher search + results. One of these may be a launch, and the rest impressions. + </summary> + </metric> + <metric name="FileExtension" enum="AppListNonAppImpressionFileExtension"> + <summary> + An enum representing the file extension if this event represents a local + or DriveFS file. + </summary> + </metric> + <metric name="HourOfDay"> + <summary> + The hour of the day that the event was logged in. Hours measured from + midnight in the local timezone. + </summary> + </metric> + <metric name="IsLaunched" enum="Boolean"> + <summary> + True if the item represented by this event was launched, false otherwise. + </summary> + </metric> + <metric name="LaunchesAtHour00"> + <summary> + The number of launches within the last 24 hours at hour 0. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour01"> + <summary> + The number of launches within the last 24 hours at hour 1. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour02"> + <summary> + The number of launches within the last 24 hours at hour 2. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour03"> + <summary> + The number of launches within the last 24 hours at hour 3. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour04"> + <summary> + The number of launches within the last 24 hours at hour 4. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour05"> + <summary> + The number of launches within the last 24 hours at hour 5. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour06"> + <summary> + The number of launches within the last 24 hours at hour 6. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour07"> + <summary> + The number of launches within the last 24 hours at hour 7. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour08"> + <summary> + The number of launches within the last 24 hours at hour 8. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour09"> + <summary> + The number of launches within the last 24 hours at hour 9. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour10"> + <summary> + The number of launches within the last 24 hours at hour 10. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour11"> + <summary> + The number of launches within the last 24 hours at hour 11. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour12"> + <summary> + The number of launches within the last 24 hours at hour 12. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour13"> + <summary> + The number of launches within the last 24 hours at hour 13. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour14"> + <summary> + The number of launches within the last 24 hours at hour 14. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour15"> + <summary> + The number of launches within the last 24 hours at hour 15. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour16"> + <summary> + The number of launches within the last 24 hours at hour 16. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour17"> + <summary> + The number of launches within the last 24 hours at hour 17. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour18"> + <summary> + The number of launches within the last 24 hours at hour 18. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour19"> + <summary> + The number of launches within the last 24 hours at hour 19. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour20"> + <summary> + The number of launches within the last 24 hours at hour 20. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour21"> + <summary> + The number of launches within the last 24 hours at hour 21. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour22"> + <summary> + The number of launches within the last 24 hours at hour 22. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesAtHour23"> + <summary> + The number of launches within the last 24 hours at hour 23. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="LaunchesThisSession"> + <summary> + How many times this item has been launched during this session. Rounded + down to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="Position"> + <summary> + The index of this item in the search results list. Indices start at 0. + </summary> + </metric> + <metric name="QueryLength"> + <summary> + The length of the raw search query with whitespace trimmed. Rounded down + to the nearest exponential bucket, with a bucket ratio of 1.15. + </summary> + </metric> + <metric name="RelevanceScore"> + <summary> + The raw relevance score returned by the relevant search provider for this + item. + </summary> + </metric> + <metric name="TimeOfLastLaunch"> + <summary> + The hour when the previous launch of this item occurred. Hours measured + from midnight in the local timezone. This can be any value 0-23, as the + last launch could have been on a previous day. + </summary> + </metric> + <metric name="TimeSinceLastLaunch"> + <summary> + Seconds since this item was last launched in this session. Rounded down to + the nearest exponential bucket, with a bucket ratio of 1.045. This makes + the bucket at 24 hour mark approximately 1 hour long. + </summary> + </metric> +</event> + <event name="Autofill.CardUploadDecision"> <owner>sebsg@chromium.org</owner> <metric name="UploadDecision">
diff --git a/tools/perf/scripts_smoke_unittest.py b/tools/perf/scripts_smoke_unittest.py index d08bff42..c3f31c2 100644 --- a/tools/perf/scripts_smoke_unittest.py +++ b/tools/perf/scripts_smoke_unittest.py
@@ -33,8 +33,6 @@ return_code = proc.returncode return return_code, stdout - # TODO(crbug.com/985712): Re-enable after new command line interface lands. - @decorators.Disabled('all') def testRunBenchmarkHelp(self): return_code, stdout = self.RunPerfScript('run_benchmark --help') self.assertEquals(return_code, 0, stdout) @@ -45,8 +43,6 @@ self.assertIn('Pass --browser to list benchmarks', stdout) self.assertNotEquals(return_code, 0) - # TODO(crbug.com/985712): Re-enable after new command line interface lands. - @decorators.Disabled('all') def testRunBenchmarkRunNonExistingBenchmark(self): return_code, stdout = self.RunPerfScript('run_benchmark foo') self.assertIn('no such benchmark: foo', stdout)
diff --git a/tools/polymer/BUILD.gn b/tools/polymer/BUILD.gn new file mode 100644 index 0000000..092066b --- /dev/null +++ b/tools/polymer/BUILD.gn
@@ -0,0 +1,15 @@ +# 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. + +group("polymer_tools_python_unittests") { + testonly = true + + data = [ + "//testing/scripts/common.py", + "//testing/scripts/run_isolated_script_test.py", + "//testing/xvfb.py", + "//tools/polymer/", + "//third_party/catapult/third_party/typ/", + ] +}
diff --git a/tools/polymer/run_polymer_tools_tests.py b/tools/polymer/run_polymer_tools_tests.py new file mode 100755 index 0000000..6a258b0e --- /dev/null +++ b/tools/polymer/run_polymer_tools_tests.py
@@ -0,0 +1,28 @@ +#!/usr/bin/env python +# 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. + +'''Unit test suite that collects all test cases for Polymer.''' + +import os +import sys + +CUR_DIR = os.path.dirname(os.path.realpath(__file__)) +SRC_DIR = os.path.dirname(os.path.dirname(CUR_DIR)) +TYP_DIR = os.path.join( + SRC_DIR, 'third_party', 'catapult', 'third_party', 'typ') + +if TYP_DIR not in sys.path: + sys.path.insert(0, TYP_DIR) + +import typ + + +def main(args): + os.chdir(CUR_DIR) + return typ.main(top_level_dirs=[CUR_DIR]) + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) +
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index 6181c08..300eeeb 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -159,7 +159,7 @@ <item id="ntp_custom_link_checker_request" hash_code="78408551" type="0" deprecated="2018-10-26" content_hash_code="13407730" file_path=""/> <item id="ntp_icon_source" hash_code="29197139" type="0" content_hash_code="16399294" os_list="linux,windows" file_path="chrome/browser/search/ntp_icon_source.cc"/> <item id="ntp_snippets_fetch" hash_code="15418154" type="0" content_hash_code="10078959" os_list="linux,windows" file_path="components/ntp_snippets/remote/json_request.cc"/> - <item id="nux_ntp_background_preview" hash_code="124847649" type="0" content_hash_code="31404656" os_list="linux,windows" file_path="chrome/browser/ui/webui/welcome/nux/ntp_background_fetcher.cc"/> + <item id="nux_ntp_background_preview" hash_code="124847649" type="0" content_hash_code="31404656" os_list="linux,windows" file_path="chrome/browser/ui/webui/welcome/ntp_background_fetcher.cc"/> <item id="oauth2_access_token_fetcher" hash_code="27915688" type="0" content_hash_code="33501872" os_list="linux,windows" file_path="google_apis/gaia/oauth2_access_token_fetcher_impl.cc"/> <item id="oauth2_api_call_flow" hash_code="29188932" type="2" content_hash_code="108831236" os_list="linux,windows" policy_fields="-1" file_path="google_apis/gaia/oauth2_api_call_flow.cc"/> <item id="oauth2_mint_token_flow" hash_code="1112842" type="1" second_id="29188932" content_hash_code="91581432" os_list="linux,windows" semantics_fields="1,2,3,4,5" policy_fields="3,4" file_path="google_apis/gaia/oauth2_mint_token_flow.cc"/>
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h index 6aed3474..d0cd8be8 100644 --- a/ui/accessibility/ax_tree_serializer.h +++ b/ui/accessibility/ax_tree_serializer.h
@@ -162,6 +162,9 @@ // Invalidate the subtree rooted at this node. void InvalidateClientSubtree(ClientTreeNode* client_node); + // Delete all descendants of this node. + void DeleteDescendants(ClientTreeNode* client_node); + // Delete the client subtree rooted at this node. void DeleteClientSubtree(ClientTreeNode* client_node); @@ -406,7 +409,7 @@ out_update->node_id_to_clear = tree_->GetId(lca); ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca)); CHECK(client_lca); - DeleteClientSubtree(client_lca); + DeleteDescendants(client_lca); } } } while (need_delete); @@ -462,11 +465,20 @@ template <typename AXSourceNode, typename AXNodeData, typename AXTreeData> void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>:: DeleteClientSubtree(ClientTreeNode* client_node) { - for (size_t i = 0; i < client_node->children.size(); ++i) { - client_id_map_.erase(client_node->children[i]->id); - DeleteClientSubtree(client_node->children[i]); - delete client_node->children[i]; + if (client_node == client_root_) { + Reset(); // Do not try to reuse a bad root later. + } else { + DeleteDescendants(client_node); + client_id_map_.erase(client_node->id); + delete client_node; } +} + +template <typename AXSourceNode, typename AXNodeData, typename AXTreeData> +void AXTreeSerializer<AXSourceNode, AXNodeData, AXTreeData>::DeleteDescendants( + ClientTreeNode* client_node) { + for (size_t i = 0; i < client_node->children.size(); ++i) + DeleteClientSubtree(client_node->children[i]); client_node->children.clear(); } @@ -531,7 +543,8 @@ // There shouldn't be any reparenting because we've already handled it // above. If this happens, reset and return an error. - ClientTreeNode* client_child = client_id_map_[new_child_id]; + + ClientTreeNode* client_child = ClientTreeNodeById(new_child_id); if (client_child && client_child->parent != client_node) { DVLOG(1) << "Reparenting detected"; Reset(); @@ -552,9 +565,7 @@ ClientTreeNode* old_child = old_children[i]; int old_child_id = old_child->id; if (new_child_ids.find(old_child_id) == new_child_ids.end()) { - client_id_map_.erase(old_child_id); DeleteClientSubtree(old_child); - delete old_child; } else { client_child_id_map[old_child_id] = old_child; } @@ -593,8 +604,10 @@ new_child_ids.erase(child_id); actual_serialized_node_child_ids.push_back(child_id); - if (client_child_id_map.find(child_id) != client_child_id_map.end()) { - ClientTreeNode* reused_child = client_child_id_map[child_id]; + ClientTreeNode* reused_child = nullptr; + if (client_child_id_map.find(child_id) != client_child_id_map.end()) + reused_child = ClientTreeNodeById(child_id); + if (reused_child) { client_node->children.push_back(reused_child); const bool ignored_state_changed = reused_child->ignored !=
diff --git a/ui/base/cocoa/menu_controller_unittest.mm b/ui/base/cocoa/menu_controller_unittest.mm index 87d84c40..c1769f2 100644 --- a/ui/base/cocoa/menu_controller_unittest.mm +++ b/ui/base/cocoa/menu_controller_unittest.mm
@@ -5,10 +5,10 @@ #import <Cocoa/Cocoa.h> #include "base/mac/mac_util.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.h" #import "testing/gtest_mac.h" #include "third_party/skia/include/core/SkBitmap.h" #import "ui/base/cocoa/menu_controller.h" @@ -73,8 +73,7 @@ const int kTestLabelResourceId = IDS_APP_SCROLLBAR_CXMENU_SCROLLHERE; -class MenuControllerTest : public CocoaTest { -}; +class MenuControllerTest : public CocoaTest {}; class TestSimpleMenuModelVisibility : public SimpleMenuModel { public: @@ -239,11 +238,9 @@ class FontListMenuModel : public SimpleMenuModel { public: FontListMenuModel(SimpleMenuModel::Delegate* delegate, - const gfx::FontList* font_list, int index) - : SimpleMenuModel(delegate), - font_list_(font_list), - index_(index) { - } + const gfx::FontList* font_list, + int index) + : SimpleMenuModel(delegate), font_list_(font_list), index_(index) {} ~FontListMenuModel() override {} const gfx::FontList* GetLabelFontListAt(int index) const override { return (index == index_) ? font_list_ : NULL; @@ -377,9 +374,9 @@ // Tests hiding a submenu item. If a submenu item with children is set to // hidden, then the submenu should hide. TEST_F(MenuControllerTest, HiddenSubmenu) { - // SimpleMenuModel posts a task that calls Delegate::MenuClosed. Create - // a MessageLoop for that purpose. - base::MessageLoopForUI message_loop; + // SimpleMenuModel posts a task that calls Delegate::MenuClosed. + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); // Create the model. Delegate delegate; @@ -424,9 +421,9 @@ } TEST_F(MenuControllerTest, DisabledSubmenu) { - // SimpleMenuModel posts a task that calls Delegate::MenuClosed. Create - // a MessageLoop for that purpose. - base::MessageLoopForUI message_loop; + // SimpleMenuModel posts a task that calls Delegate::MenuClosed. + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); // Create the model. Delegate delegate; @@ -611,9 +608,9 @@ } TEST_F(MenuControllerTest, OpenClose) { - // SimpleMenuModel posts a task that calls Delegate::MenuClosed. Create - // a MessageLoop for that purpose. - base::MessageLoopForUI message_loop; + // SimpleMenuModel posts a task that calls Delegate::MenuClosed. + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); // Create the model. Delegate delegate; @@ -633,7 +630,7 @@ // In the event tracking run loop mode of the menu, verify that the controller // resports the menu as open. CFRunLoopPerformBlock(CFRunLoopGetCurrent(), NSEventTrackingRunLoopMode, ^{ - EXPECT_TRUE([menu isMenuOpen]); + EXPECT_TRUE([menu isMenuOpen]); }); // Pop open the menu, which will spin an event-tracking run loop. @@ -682,7 +679,8 @@ if (![NSMenuItem instancesRespondToSelector:@selector(_sendItemSelectedNote)]) return; - base::MessageLoopForUI message_loop; + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); Delegate delegate; delegate.auto_close_ = false; @@ -787,7 +785,8 @@ // MenuControllerCocoa and destroys itself. Note this usually needs asan to // actually crash (before it was fixed). TEST_F(MenuControllerTest, OwningDelegate) { - base::MessageLoopForUI message_loop; + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); bool did_delete = false; BOOL did_dealloc = NO; OwningDelegate* delegate;
diff --git a/ui/base/ime/input_method_base_unittest.cc b/ui/base/ime/input_method_base_unittest.cc index 209cefe..157da3b 100644 --- a/ui/base/ime/input_method_base_unittest.cc +++ b/ui/base/ime/input_method_base_unittest.cc
@@ -8,9 +8,9 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/scoped_observer.h" +#include "base/test/scoped_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/ime/dummy_text_input_client.h" #include "ui/base/ime/input_method_observer.h" @@ -110,20 +110,9 @@ }; class InputMethodBaseTest : public testing::Test { - protected: - InputMethodBaseTest() { - } - ~InputMethodBaseTest() override {} - - void SetUp() override { - message_loop_ = std::make_unique<base::MessageLoopForUI>(); - } - - void TearDown() override { message_loop_.reset(); } - private: - std::unique_ptr<base::MessageLoop> message_loop_; - DISALLOW_COPY_AND_ASSIGN(InputMethodBaseTest); + base::test::ScopedTaskEnvironment scoped_task_environment_{ + base::test::ScopedTaskEnvironment::MainThreadType::UI}; }; class MockInputMethodBase : public InputMethodBase {
diff --git a/ui/base/models/simple_combobox_model.cc b/ui/base/models/simple_combobox_model.cc index edf339d..ff4f04f 100644 --- a/ui/base/models/simple_combobox_model.cc +++ b/ui/base/models/simple_combobox_model.cc
@@ -4,12 +4,12 @@ #include "ui/base/models/simple_combobox_model.h" +#include <utility> + namespace ui { -SimpleComboboxModel::SimpleComboboxModel( - const std::vector<base::string16>& items) - : items_(items) { -} +SimpleComboboxModel::SimpleComboboxModel(std::vector<base::string16> items) + : items_(std::move(items)) {} SimpleComboboxModel::~SimpleComboboxModel() { }
diff --git a/ui/base/models/simple_combobox_model.h b/ui/base/models/simple_combobox_model.h index 06e534a..a50373a 100644 --- a/ui/base/models/simple_combobox_model.h +++ b/ui/base/models/simple_combobox_model.h
@@ -16,7 +16,7 @@ // An empty string will be a separator. class UI_BASE_EXPORT SimpleComboboxModel : public ComboboxModel { public: - explicit SimpleComboboxModel(const std::vector<base::string16>& items); + explicit SimpleComboboxModel(std::vector<base::string16> items); ~SimpleComboboxModel() override; // ui::ComboboxModel:
diff --git a/ui/base/test/scoped_fake_nswindow_fullscreen_unittest.mm b/ui/base/test/scoped_fake_nswindow_fullscreen_unittest.mm index 22ff976..c848882 100644 --- a/ui/base/test/scoped_fake_nswindow_fullscreen_unittest.mm +++ b/ui/base/test/scoped_fake_nswindow_fullscreen_unittest.mm
@@ -7,9 +7,9 @@ #import "base/mac/mac_util.h" #import "base/mac/scoped_nsobject.h" #import "base/mac/sdk_forward_declarations.h" -#include "base/message_loop/message_loop.h" -#import "testing/gtest_mac.h" +#include "base/test/scoped_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" +#import "testing/gtest_mac.h" #import "ui/base/test/windowed_nsnotification_observer.h" #import "ui/gfx/mac/nswindow_frame_controls.h" @@ -41,7 +41,8 @@ // Test the order of notifications sent when faking fullscreen transitions. TEST(ScopedFakeNSWindowFullscreenTest, TestOrdering) { - base::MessageLoopForUI message_loop; + base::test::ScopedTaskEnvironment scoped_task_environment( + base::test::ScopedTaskEnvironment::MainThreadType::UI); NSUInteger style_mask = NSTexturedBackgroundWindowMask | NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask |
diff --git a/ui/base/x/BUILD.gn b/ui/base/x/BUILD.gn index b0a62f8a..115be2e 100644 --- a/ui/base/x/BUILD.gn +++ b/ui/base/x/BUILD.gn
@@ -12,6 +12,8 @@ output_name = "ui_base_x" sources = [ + "x11_display_manager.cc", + "x11_display_manager.h", "x11_display_util.cc", "x11_display_util.h", "x11_menu_list.cc",
diff --git a/ui/base/x/selection_requestor_unittest.cc b/ui/base/x/selection_requestor_unittest.cc index 74b55ed..2954b66 100644 --- a/ui/base/x/selection_requestor_unittest.cc +++ b/ui/base/x/selection_requestor_unittest.cc
@@ -10,8 +10,8 @@ #include "base/bind.h" #include "base/macros.h" #include "base/memory/ref_counted_memory.h" -#include "base/message_loop/message_loop.h" #include "base/single_thread_task_runner.h" +#include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/x/selection_utils.h" @@ -89,7 +89,8 @@ std::unique_ptr<PlatformEventSource> event_source_; std::unique_ptr<SelectionRequestor> requestor_; - base::MessageLoopForUI message_loop_; + base::test::ScopedTaskEnvironment scoped_task_environment_{ + base::test::ScopedTaskEnvironment::MainThreadType::UI}; private: DISALLOW_COPY_AND_ASSIGN(SelectionRequestorTest);
diff --git a/ui/base/x/x11_display_manager.cc b/ui/base/x/x11_display_manager.cc new file mode 100644 index 0000000..bb99a04 --- /dev/null +++ b/ui/base/x/x11_display_manager.cc
@@ -0,0 +1,130 @@ +// 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. + +#include "ui/base/x/x11_display_manager.h" + +#include <utility> + +#include "base/bind.h" +#include "base/threading/thread_task_runner_handle.h" +#include "ui/base/x/x11_display_util.h" +#include "ui/gfx/x/x11.h" +#include "ui/gfx/x/x11_atom_cache.h" + +namespace ui { + +namespace { + +constexpr int kMinXrandrVersion = 103; // Need at least xrandr version 1.3 +constexpr auto kDisplayListUpdateDelay = base::TimeDelta::FromMilliseconds(250); + +} // namespace + +XDisplayManager::XDisplayManager(Delegate* delegate) + : delegate_(delegate), + xdisplay_(gfx::GetXDisplay()), + x_root_window_(DefaultRootWindow(xdisplay_)), + xrandr_version_(GetXrandrVersion(xdisplay_)) {} + +XDisplayManager::~XDisplayManager() = default; + +void XDisplayManager::Init() { + if (IsXrandrAvailable()) { + int error_base_ignored = 0; + XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored); + + XRRSelectInput(xdisplay_, x_root_window_, + RRScreenChangeNotifyMask | RROutputChangeNotifyMask | + RRCrtcChangeNotifyMask); + } + FetchDisplayList(); +} + +// Need at least xrandr version 1.3 +bool XDisplayManager::IsXrandrAvailable() const { + return xrandr_version_ >= kMinXrandrVersion; +} + +display::Display XDisplayManager::GetPrimaryDisplay() const { + DCHECK(!displays_.empty()); + return displays_[primary_display_index_]; +} + +void XDisplayManager::AddObserver(display::DisplayObserver* observer) { + change_notifier_.AddObserver(observer); +} + +void XDisplayManager::RemoveObserver(display::DisplayObserver* observer) { + change_notifier_.RemoveObserver(observer); +} + +bool XDisplayManager::CanProcessEvent(const XEvent& xev) { + return xev.type - xrandr_event_base_ == RRScreenChangeNotify || + xev.type - xrandr_event_base_ == RRNotify || + (xev.type == PropertyNotify && + xev.xproperty.window == x_root_window_ && + xev.xproperty.atom == gfx::GetAtom("_NET_WORKAREA")); +} + +bool XDisplayManager::ProcessEvent(XEvent* xev) { + DCHECK(xev); + int ev_type = xev->type - xrandr_event_base_; + if (ev_type == RRScreenChangeNotify) { + // Pass the event through to xlib. + XRRUpdateConfiguration(xev); + return true; + } + if (ev_type == RRNotify || + (xev->type == PropertyNotify && + xev->xproperty.atom == gfx::GetAtom("_NET_WORKAREA"))) { + DispatchDelayedDisplayListUpdate(); + return true; + } + return false; +} + +void XDisplayManager::SetDisplayList(std::vector<display::Display> displays) { + displays_ = std::move(displays); + delegate_->OnXDisplayListUpdated(); +} + +// Talks to xrandr to get the information of the outputs for a screen and +// updates display::Display list. The minimum required version of xrandr is +// 1.3. +void XDisplayManager::FetchDisplayList() { + std::vector<display::Display> displays; + float scale = delegate_->GetXDisplayScaleFactor(); + if (IsXrandrAvailable()) { + displays = BuildDisplaysFromXRandRInfo(xrandr_version_, scale, + &primary_display_index_); + } else { + displays = GetFallbackDisplayList(scale); + } + SetDisplayList(std::move(displays)); +} + +void XDisplayManager::UpdateDisplayList() { + std::vector<display::Display> old_displays = displays_; + FetchDisplayList(); + change_notifier_.NotifyDisplaysChanged(old_displays, displays_); +} + +void XDisplayManager::DispatchDelayedDisplayListUpdate() { + delayed_update_task_.Reset(base::BindOnce(&XDisplayManager::UpdateDisplayList, + base::Unretained(this))); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, delayed_update_task_.callback(), kDisplayListUpdateDelay); +} + +gfx::Point XDisplayManager::GetCursorLocation() const { + XID root, child; + int root_x, root_y, win_x, win_y; + unsigned int mask; + XQueryPointer(xdisplay_, x_root_window_, &root, &child, &root_x, &root_y, + &win_x, &win_y, &mask); + + return gfx::Point(root_x, root_y); +} + +} // namespace ui
diff --git a/ui/base/x/x11_display_manager.h b/ui/base/x/x11_display_manager.h new file mode 100644 index 0000000..40d54fa --- /dev/null +++ b/ui/base/x/x11_display_manager.h
@@ -0,0 +1,98 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_X_X11_DISPLAY_MANAGER_H_ +#define UI_BASE_X_X11_DISPLAY_MANAGER_H_ + +#include <memory> +#include <vector> + +#include "base/cancelable_callback.h" +#include "base/component_export.h" +#include "ui/display/display.h" +#include "ui/display/display_change_notifier.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/x/x11_types.h" + +namespace views { +class DesktopScreenX11Test; +} + +namespace ui { +class X11ScreenOzoneTest; + +//////////////////////////////////////////////////////////////////////////////// +// XDisplayManager class +// +// Responsible for fetching and maintaining list of |display::Display|s +// representing X11 screens connected to the system. XRandR extension is used +// when version >= 1.3 is available, otherwise it falls back to +// |DefaultScreenOfDisplay| Xlib API. +// +// Scale Factor information and simple hooks are delegated to API clients +// through |XDisplayManager::Delegate| interface. To get notifications about +// dynamic display changes, clients must register |DisplayObserver| instances +// and feed |XDisplayManager| with |XEvent|s. +// +// All bounds and size values are assumed to be expressed in pixels. +class COMPONENT_EXPORT(UI_BASE_X) XDisplayManager { + public: + class Delegate; + + explicit XDisplayManager(Delegate* delegate); + virtual ~XDisplayManager(); + + void Init(); + bool IsXrandrAvailable() const; + bool CanProcessEvent(const XEvent& xev); + bool ProcessEvent(XEvent* xev); + void UpdateDisplayList(); + void DispatchDelayedDisplayListUpdate(); + display::Display GetPrimaryDisplay() const; + + void AddObserver(display::DisplayObserver* observer); + void RemoveObserver(display::DisplayObserver* observer); + + const std::vector<display::Display>& displays() const { return displays_; } + gfx::Point GetCursorLocation() const; + + private: + friend class ui::X11ScreenOzoneTest; + friend class views::DesktopScreenX11Test; + + void SetDisplayList(std::vector<display::Display> displays); + void FetchDisplayList(); + + Delegate* const delegate_; + std::vector<display::Display> displays_; + display::DisplayChangeNotifier change_notifier_; + + XDisplay* const xdisplay_; + XID x_root_window_; + int64_t primary_display_index_ = 0; + + // XRandR version. MAJOR * 100 + MINOR. Zero if no xrandr is present. + const int xrandr_version_; + + // The base of the event numbers used to represent XRandr events used in + // decoding events regarding output add/remove. + int xrandr_event_base_ = 0; + + // The task to delay fetching display info. We delay it so that we can + // coalesce events. + base::CancelableOnceClosure delayed_update_task_; + + DISALLOW_COPY_AND_ASSIGN(XDisplayManager); +}; + +class COMPONENT_EXPORT(UI_BASE_X) XDisplayManager::Delegate { + public: + virtual ~Delegate() = default; + virtual void OnXDisplayListUpdated() = 0; + virtual float GetXDisplayScaleFactor() = 0; +}; + +} // namespace ui + +#endif // UI_BASE_X_X11_DISPLAY_MANAGER_H_
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn index afdde4f..73018b9 100644 --- a/ui/events/BUILD.gn +++ b/ui/events/BUILD.gn
@@ -504,6 +504,10 @@ "blink/fling_booster_unittest.cc", "blink/input_handler_proxy_unittest.cc", "blink/input_scroll_elasticity_controller_unittest.cc", + "blink/prediction/empty_filter_unittests.cc", + "blink/prediction/filter_factory_unittests.cc", + "blink/prediction/input_filter_unittest_helpers.cc", + "blink/prediction/input_filter_unittest_helpers.h", "blink/prediction/input_predictor_unittest_helpers.cc", "blink/prediction/input_predictor_unittest_helpers.h", "blink/prediction/kalman_predictor_unittest.cc",
diff --git a/ui/events/blink/BUILD.gn b/ui/events/blink/BUILD.gn index 1613613..e4b823f 100644 --- a/ui/events/blink/BUILD.gn +++ b/ui/events/blink/BUILD.gn
@@ -37,8 +37,13 @@ "input_scroll_elasticity_controller.h", "momentum_scroll_jank_tracker.cc", "momentum_scroll_jank_tracker.h", + "prediction/empty_filter.cc", + "prediction/empty_filter.h", "prediction/empty_predictor.cc", "prediction/empty_predictor.h", + "prediction/filter_factory.cc", + "prediction/filter_factory.h", + "prediction/input_filter.h", "prediction/input_predictor.h", "prediction/kalman_filter.cc", "prediction/kalman_filter.h",
diff --git a/ui/events/blink/blink_features.cc b/ui/events/blink/blink_features.cc index 545195b..54965ec 100644 --- a/ui/events/blink/blink_features.cc +++ b/ui/events/blink/blink_features.cc
@@ -9,6 +9,9 @@ const base::Feature kResamplingScrollEvents{"ResamplingScrollEvents", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kFilteringScrollPrediction{ + "FilteringScrollPrediction", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kSendMouseLeaveEvents{"SendMouseLeaveEvents", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ui/events/blink/blink_features.h b/ui/events/blink/blink_features.h index d51e49d..b05f1559 100644 --- a/ui/events/blink/blink_features.h +++ b/ui/events/blink/blink_features.h
@@ -14,6 +14,10 @@ COMPONENT_EXPORT(BLINK_FEATURES) extern const base::Feature kResamplingScrollEvents; +// Enables filtering of predicted scroll events on compositor thread. +COMPONENT_EXPORT(BLINK_FEATURES) +extern const base::Feature kFilteringScrollPrediction; + // This feature allows native ET_MOUSE_EXIT events to be passed // through to blink as mouse leave events. Traditionally these events were // converted to mouse move events due to a number of inconsistencies on
diff --git a/ui/events/blink/prediction/empty_filter.cc b/ui/events/blink/prediction/empty_filter.cc new file mode 100644 index 0000000..dd3a3ff1 --- /dev/null +++ b/ui/events/blink/prediction/empty_filter.cc
@@ -0,0 +1,28 @@ +// 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. + +#include "ui/events/blink/prediction/empty_filter.h" +#include "ui/events/blink/prediction/filter_factory.h" + +namespace ui { + +EmptyFilter::EmptyFilter() {} +EmptyFilter::~EmptyFilter() {} + +bool EmptyFilter::Filter(const base::TimeTicks timestamp, + gfx::PointF* position) const { + return true; +} + +const char* EmptyFilter::GetName() const { + return input_prediction::kFilterNameEmpty; +} + +InputFilter* EmptyFilter::Clone() { + return new EmptyFilter(); +} + +void EmptyFilter::Reset() {} + +} // namespace ui
diff --git a/ui/events/blink/prediction/empty_filter.h b/ui/events/blink/prediction/empty_filter.h new file mode 100644 index 0000000..4b8bdd5 --- /dev/null +++ b/ui/events/blink/prediction/empty_filter.h
@@ -0,0 +1,38 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_BLINK_PREDICTION_EMPTY_FILTER_H_ +#define UI_EVENTS_BLINK_PREDICTION_EMPTY_FILTER_H_ + +#include "ui/events/blink/prediction/input_filter.h" + +namespace ui { + +// Empty filter is a fake filter. Always returns the same input position as +// the filtered position. Mainly used for testing purpose. +class EmptyFilter : public InputFilter { + public: + explicit EmptyFilter(); + ~EmptyFilter() override; + + // Filters the position sent to the filter at a specific timestamp. + // Returns true if the value is filtered, false otherwise. + bool Filter(const base::TimeTicks timestamp, + gfx::PointF* position) const override; + + // Returns the name of the filter + const char* GetName() const override; + + // Returns a copy of the filter. + InputFilter* Clone() override; + + // Reset the filter to its initial state + void Reset() override; + + DISALLOW_COPY_AND_ASSIGN(EmptyFilter); +}; + +} // namespace ui + +#endif // UI_EVENTS_BLINK_PREDICTION_EMPTY_FILTER_H_
diff --git a/ui/events/blink/prediction/empty_filter_unittests.cc b/ui/events/blink/prediction/empty_filter_unittests.cc new file mode 100644 index 0000000..a8b3c36 --- /dev/null +++ b/ui/events/blink/prediction/empty_filter_unittests.cc
@@ -0,0 +1,47 @@ +// 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. + +#include "base/rand_util.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/blink/prediction/empty_filter.h" +#include "ui/events/blink/prediction/filter_factory.h" +#include "ui/events/blink/prediction/input_filter_unittest_helpers.h" + +namespace ui { +namespace test { + +class EmptyFilterTest : public InputFilterTest { + public: + explicit EmptyFilterTest() {} + + void SetUp() override { filter_ = std::make_unique<ui::EmptyFilter>(); } + + DISALLOW_COPY_AND_ASSIGN(EmptyFilterTest); +}; + +// Test the Clone function of the filter +TEST_F(EmptyFilterTest, TestClone) { + TestCloneFilter(); +} + +// Test the Reset function of the filter +TEST_F(EmptyFilterTest, TestReset) { + TestResetFilter(); +} + +// Test the empty filter gives the same values +TEST_F(EmptyFilterTest, filteringValues) { + base::TimeTicks ts = blink::WebInputEvent::GetStaticTimeStampForTests(); + gfx::PointF point, filtered_point; + for (int i = 0; i < 100; i++) { + point.SetPoint(base::RandDouble(), base::RandDouble()); + filtered_point = point; + EXPECT_TRUE(filter_->Filter(ts, &filtered_point)); + EXPECT_EQ(point.x(), filtered_point.x()); + EXPECT_EQ(point.y(), filtered_point.y()); + } +} + +} // namespace test +} // namespace ui \ No newline at end of file
diff --git a/ui/events/blink/prediction/filter_factory.cc b/ui/events/blink/prediction/filter_factory.cc new file mode 100644 index 0000000..65de8e9c --- /dev/null +++ b/ui/events/blink/prediction/filter_factory.cc
@@ -0,0 +1,30 @@ +// 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. + +#include "ui/events/blink/prediction/filter_factory.h" +#include "ui/events/blink/prediction/empty_filter.h" + +namespace ui { + +namespace input_prediction { + +const char kFilterNameEmpty[] = "empty_filter"; + +} // namespace input_prediction + +namespace { +using input_prediction::FilterType; +} // namespace + +FilterType FilterFactory::GetFilterTypeFromName( + const std::string& filter_name) { + return FilterType::kEmpty; +} + +std::unique_ptr<InputFilter> FilterFactory::CreateFilter( + input_prediction::FilterType filter_type) { + return std::make_unique<EmptyFilter>(); +} + +} // namespace ui
diff --git a/ui/events/blink/prediction/filter_factory.h b/ui/events/blink/prediction/filter_factory.h new file mode 100644 index 0000000..12da7406 --- /dev/null +++ b/ui/events/blink/prediction/filter_factory.h
@@ -0,0 +1,42 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_BLINK_PREDICTION_FILTER_FACTORY_H_ +#define UI_EVENTS_BLINK_PREDICTION_FILTER_FACTORY_H_ + +#include "ui/events/blink/prediction/input_filter.h" + +namespace ui { + +namespace input_prediction { + +extern const char kFilterNameEmpty[]; + +enum class FilterType { + kEmpty, +}; +} // namespace input_prediction + +// FilterFactory is a class containing static public methods to create filters. +// It defines filters name and type constants. It also reads filter settings +// from fieldtrials if needed. +class FilterFactory { + public: + // Returns the FilterType associated to the given filter + // name if found, otherwise returns kFilterTypeEmpty + static input_prediction::FilterType GetFilterTypeFromName( + const std::string& filter_name); + + // Returns the filter designed by its type. + static std::unique_ptr<InputFilter> CreateFilter( + input_prediction::FilterType filter_type); + + private: + FilterFactory() = delete; + ~FilterFactory() = delete; +}; + +} // namespace ui + +#endif // UI_EVENTS_BLINK_PREDICTION_FILTER_FACTORY_H_ \ No newline at end of file
diff --git a/ui/events/blink/prediction/filter_factory_unittests.cc b/ui/events/blink/prediction/filter_factory_unittests.cc new file mode 100644 index 0000000..4cc7906 --- /dev/null +++ b/ui/events/blink/prediction/filter_factory_unittests.cc
@@ -0,0 +1,35 @@ +// 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. + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/blink/prediction/filter_factory.h" + +namespace ui { +namespace test { + +class FilterFactoryTest : public testing::Test { + public: + explicit FilterFactoryTest() {} + + DISALLOW_COPY_AND_ASSIGN(FilterFactoryTest); +}; + +// Check if the FilterType returned is correct +TEST_F(FilterFactoryTest, TestGetFilterType) { + EXPECT_EQ( + input_prediction::FilterType::kEmpty, + FilterFactory::GetFilterTypeFromName(input_prediction::kFilterNameEmpty)); + // Default type Empty + EXPECT_EQ(input_prediction::FilterType::kEmpty, + FilterFactory::GetFilterTypeFromName("")); +} + +TEST_F(FilterFactoryTest, TestGetFilter) { + EXPECT_STREQ(input_prediction::kFilterNameEmpty, + FilterFactory::CreateFilter(input_prediction::FilterType::kEmpty) + ->GetName()); +} + +} // namespace test +} // namespace ui \ No newline at end of file
diff --git a/ui/events/blink/prediction/input_filter.h b/ui/events/blink/prediction/input_filter.h new file mode 100644 index 0000000..68aab232 --- /dev/null +++ b/ui/events/blink/prediction/input_filter.h
@@ -0,0 +1,36 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_BLINK_PREDICTION_INPUT_FILTER_H_ +#define UI_EVENTS_BLINK_PREDICTION_INPUT_FILTER_H_ + +#include "ui/events/base_event_utils.h" +#include "ui/gfx/geometry/point_f.h" + +namespace ui { + +// This class expects a sequence of inputs with coordinates and timestamps to +// return a smooth path from the sent coordinates. +class InputFilter { + public: + virtual ~InputFilter() = default; + + // Filters the position sent to the filter at a specific timestamp. + // Returns true if the value is filtered, false otherwise. + virtual bool Filter(const base::TimeTicks timestamp, + gfx::PointF* position) const = 0; + + // Returns the name of the filter + virtual const char* GetName() const = 0; + + // Returns a copy of the filter. + virtual InputFilter* Clone() = 0; + + // Reset the filter to its initial state + virtual void Reset() = 0; +}; + +} // namespace ui + +#endif // UI_EVENTS_BLINK_PREDICTION_INPUT_FILTER_H_ \ No newline at end of file
diff --git a/ui/events/blink/prediction/input_filter_unittest_helpers.cc b/ui/events/blink/prediction/input_filter_unittest_helpers.cc new file mode 100644 index 0000000..0cd6be4 --- /dev/null +++ b/ui/events/blink/prediction/input_filter_unittest_helpers.cc
@@ -0,0 +1,81 @@ +// 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. + +#include "ui/events/blink/prediction/input_filter_unittest_helpers.h" + +#include "base/rand_util.h" + +namespace ui { +namespace test { + +InputFilterTest::InputFilterTest() = default; +InputFilterTest::~InputFilterTest() = default; + +// Check if the filter is well cloned. We send random values to the filter and +// then we clone it. If we send the same new random values to both filters, +// we should have the same filtered results +void InputFilterTest::TestCloneFilter() { + gfx::PointF point; + base::TimeTicks ts = blink::WebInputEvent::GetStaticTimeStampForTests(); + base::TimeDelta delta = base::TimeDelta::FromMilliseconds(8); + + for (int i = 0; i < 100; i++) { + point.SetPoint(base::RandDouble(), base::RandDouble()); + EXPECT_TRUE(filter_->Filter(ts, &point)); // We just feed the filter + ts += delta; + } + + std::unique_ptr<InputFilter> fork_filter; + fork_filter.reset(filter_->Clone()); + + gfx::PointF filtered_point, fork_filtered_point; + for (int i = 0; i < 100; i++) { + point.SetPoint(base::RandDouble(), base::RandDouble()); + filtered_point = point; + fork_filtered_point = point; + EXPECT_TRUE(filter_->Filter(ts, &filtered_point)); + EXPECT_TRUE(fork_filter->Filter(ts, &fork_filtered_point)); + EXPECT_NEAR(filtered_point.x(), fork_filtered_point.x(), kEpsilon); + EXPECT_NEAR(filtered_point.y(), fork_filtered_point.y(), kEpsilon); + ts += delta; + } +} + +// Check if the filter is well reset. We send random values, save the values and +// results, then we reset the filter. We send again the same values and see if +// we have the same results, which would be statistically impossible with 100 +// random without a proper resetting. +void InputFilterTest::TestResetFilter() { + std::vector<gfx::PointF> points; + std::vector<base::TimeTicks> timestamps; + std::vector<gfx::PointF> results; + gfx::PointF point; + base::TimeTicks ts = blink::WebInputEvent::GetStaticTimeStampForTests(); + base::TimeDelta delta = base::TimeDelta::FromMilliseconds(8); + + for (int i = 0; i < 100; i++) { + point.SetPoint(base::RandDouble(), base::RandDouble()); + points.push_back(point); + timestamps.push_back(ts); + EXPECT_TRUE(filter_->Filter(ts, &point)); + results.push_back(point); + ts += delta; + } + + filter_->Reset(); + + EXPECT_EQ((int)points.size(), 100); + EXPECT_EQ((int)timestamps.size(), 100); + EXPECT_EQ((int)results.size(), 100); + + for (int i = 0; i < 100; i++) { + point = points[i]; + EXPECT_TRUE(filter_->Filter(timestamps[i], &point)); + EXPECT_NEAR(results[i].x(), point.x(), kEpsilon); + EXPECT_NEAR(results[i].y(), point.y(), kEpsilon); + } +} + +} // namespace test +} // namespace ui
diff --git a/ui/events/blink/prediction/input_filter_unittest_helpers.h b/ui/events/blink/prediction/input_filter_unittest_helpers.h new file mode 100644 index 0000000..fef5b10 --- /dev/null +++ b/ui/events/blink/prediction/input_filter_unittest_helpers.h
@@ -0,0 +1,37 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_BLINK_PREDICTION_INPUT_FILTER_UNITTEST_HELPERS_H_ +#define UI_EVENTS_BLINK_PREDICTION_INPUT_FILTER_UNITTEST_HELPERS_H_ + +#include "ui/events/blink/prediction/input_filter.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/blink/blink_event_util.h" + +namespace ui { +namespace test { + +constexpr double kEpsilon = 0.0001; + +// Base class for predictor unit tests +class InputFilterTest : public testing::Test { + public: + InputFilterTest(); + ~InputFilterTest() override; + + void TestCloneFilter(); + + void TestResetFilter(); + + protected: + std::unique_ptr<InputFilter> filter_; + + DISALLOW_COPY_AND_ASSIGN(InputFilterTest); +}; + +} // namespace test +} // namespace ui + +#endif // UI_EVENTS_BLINK_PREDICTION_INPUT_FILTER_UNITTEST_HELPERS_H_
diff --git a/ui/events/blink/scroll_predictor.cc b/ui/events/blink/scroll_predictor.cc index 3234f0d..e973aac 100644 --- a/ui/events/blink/scroll_predictor.cc +++ b/ui/events/blink/scroll_predictor.cc
@@ -8,6 +8,7 @@ #include "base/metrics/field_trial_params.h" #include "base/metrics/histogram_functions.h" #include "base/trace_event/trace_event.h" +#include "ui/events/blink/prediction/filter_factory.h" #include "ui/events/blink/prediction/predictor_factory.h" using blink::WebInputEvent; @@ -16,12 +17,26 @@ namespace ui { ScrollPredictor::ScrollPredictor() { + // Get the predictor from feature flags std::string predictor_name = GetFieldTrialParamValueByFeature( features::kResamplingScrollEvents, "predictor"); input_prediction::PredictorType predictor_type = ui::PredictorFactory::GetPredictorTypeFromName(predictor_name); predictor_ = ui::PredictorFactory::GetPredictor(predictor_type); + + filtering_enabled_ = + base::FeatureList::IsEnabled(features::kFilteringScrollPrediction); + + if (filtering_enabled_) { + // Get the filter from feature flags + std::string filter_name = GetFieldTrialParamValueByFeature( + features::kFilteringScrollPrediction, "filter"); + + input_prediction::FilterType filter_type = + ui::FilterFactory::GetFilterTypeFromName(filter_name); + filter_ = ui::FilterFactory::CreateFilter(filter_type); + } } ScrollPredictor::~ScrollPredictor() = default; @@ -79,6 +94,8 @@ void ScrollPredictor::Reset() { predictor_->Reset(); + if (filtering_enabled_) + filter_->Reset(); current_accumulated_delta_ = gfx::PointF(); last_accumulated_delta_ = gfx::PointF(); } @@ -114,7 +131,7 @@ InputPredictor::InputData result; base::TimeDelta prediction_delta = time_stamp - gesture_event->TimeStamp(); - + bool predicted = false; // Disable prediction when dt < 0. if (prediction_delta > base::TimeDelta()) { // For resampling, we don't want to predict too far away because the result @@ -131,9 +148,17 @@ predictor_->GeneratePrediction(prediction_time, &result)) { predicted_accumulated_delta = result.pos; gesture_event->SetTimeStamp(prediction_time); + predicted = true; } } + // Feed the filter with the first non-predicted events but only apply + // filtering on predicted events + gfx::PointF filtered_pos = predicted_accumulated_delta; + if (filtering_enabled_ && filter_->Filter(time_stamp, &filtered_pos) && + predicted) + predicted_accumulated_delta = filtered_pos; + // If the last resampled GSU over predict the delta, new GSU might try to // scroll back to make up the difference, which cause the scroll to jump back. // So we set the new delta to 0 when predicted delta is in different direction
diff --git a/ui/events/blink/scroll_predictor.h b/ui/events/blink/scroll_predictor.h index ac85b9d..08d50cb5 100644 --- a/ui/events/blink/scroll_predictor.h +++ b/ui/events/blink/scroll_predictor.h
@@ -9,6 +9,7 @@ #include "ui/events/base_event_utils.h" #include "ui/events/blink/event_with_callback.h" +#include "ui/events/blink/prediction/input_filter.h" #include "ui/events/blink/prediction/input_predictor.h" namespace ui { @@ -60,6 +61,10 @@ void ComputeAccuracy(const WebScopedInputEvent& event); std::unique_ptr<InputPredictor> predictor_; + std::unique_ptr<InputFilter> filter_; + + // Whether predicted scroll events should be filtered or not + bool filtering_enabled_ = false; // Total scroll delta, used for prediction. Reset when GestureScrollBegin gfx::PointF current_accumulated_delta_;
diff --git a/ui/events/blink/scroll_predictor_unittest.cc b/ui/events/blink/scroll_predictor_unittest.cc index 679f7eb..568d57f96 100644 --- a/ui/events/blink/scroll_predictor_unittest.cc +++ b/ui/events/blink/scroll_predictor_unittest.cc
@@ -10,7 +10,9 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/blink/blink_event_util.h" #include "ui/events/blink/blink_features.h" +#include "ui/events/blink/prediction/empty_filter.h" #include "ui/events/blink/prediction/empty_predictor.h" +#include "ui/events/blink/prediction/filter_factory.h" #include "ui/events/blink/prediction/kalman_predictor.h" #include "ui/events/blink/prediction/least_squares_predictor.h" #include "ui/events/blink/prediction/linear_predictor.h" @@ -107,8 +109,10 @@ return scroll_predictor_->should_resample_scroll_events_; } - void ConfigureFieldTrial(const base::Feature& feature, - const std::string& predictor_type) { + bool isFilteringEnabled() { return scroll_predictor_->filtering_enabled_; } + + void ConfigurePredictorFieldTrial(const base::Feature& feature, + const std::string& predictor_type) { base::FieldTrialParams params; params["predictor"] = predictor_type; @@ -122,6 +126,21 @@ EXPECT_EQ(expected_type, scroll_predictor_->predictor_->GetName()); } + void ConfigureFilterFieldTrial(const base::Feature& feature, + const std::string& filter_name) { + base::FieldTrialParams params; + params["filter"] = filter_name; + + scoped_feature_list_.Reset(); + scoped_feature_list_.InitAndEnableFeatureWithParameters(feature, params); + EXPECT_EQ(params["filter"], + GetFieldTrialParamValueByFeature(feature, "filter")); + } + + void VerifyFilterType(const char* expected_type) { + EXPECT_EQ(expected_type, scroll_predictor_->filter_->GetName()); + } + protected: EventWithCallback::OriginalEventList original_events_; std::unique_ptr<ScrollPredictor> scroll_predictor_; @@ -378,26 +397,80 @@ // When resampling is enabled, predictor type is set from // kResamplingScrollEvents. - ConfigureFieldTrial(features::kResamplingScrollEvents, - input_prediction::kScrollPredictorNameEmpty); + ConfigurePredictorFieldTrial(features::kResamplingScrollEvents, + input_prediction::kScrollPredictorNameEmpty); scroll_predictor_ = std::make_unique<ScrollPredictor>(); VerifyPredictorType(input_prediction::kScrollPredictorNameEmpty); - ConfigureFieldTrial(features::kResamplingScrollEvents, - input_prediction::kScrollPredictorNameLsq); + ConfigurePredictorFieldTrial(features::kResamplingScrollEvents, + input_prediction::kScrollPredictorNameLsq); scroll_predictor_ = std::make_unique<ScrollPredictor>(); VerifyPredictorType(input_prediction::kScrollPredictorNameLsq); - ConfigureFieldTrial(features::kResamplingScrollEvents, - input_prediction::kScrollPredictorNameKalman); + ConfigurePredictorFieldTrial(features::kResamplingScrollEvents, + input_prediction::kScrollPredictorNameKalman); scroll_predictor_ = std::make_unique<ScrollPredictor>(); VerifyPredictorType(input_prediction::kScrollPredictorNameKalman); - ConfigureFieldTrial(features::kResamplingScrollEvents, - input_prediction::kScrollPredictorNameLinearFirst); + ConfigurePredictorFieldTrial( + features::kResamplingScrollEvents, + input_prediction::kScrollPredictorNameLinearFirst); scroll_predictor_ = std::make_unique<ScrollPredictor>(); VerifyPredictorType(input_prediction::kScrollPredictorNameLinearFirst); } +// Check the right filter is selected +TEST_F(ScrollPredictorTest, DefaultFilter) { + ConfigureFilterFieldTrial(features::kFilteringScrollPrediction, ""); + scroll_predictor_ = std::make_unique<ScrollPredictor>(); + VerifyFilterType(input_prediction::kFilterNameEmpty); + EXPECT_TRUE(isFilteringEnabled()); + + ConfigureFilterFieldTrial(features::kFilteringScrollPrediction, + input_prediction::kFilterNameEmpty); + scroll_predictor_ = std::make_unique<ScrollPredictor>(); + VerifyFilterType(input_prediction::kFilterNameEmpty); + EXPECT_TRUE(isFilteringEnabled()); +} + +// We first send 100 events to the scroll predictor with kalman predictor +// enabled and filetring disable and save the results. +// We then send the same events with kalman and the empty filter, we should +// expect the same results. +TEST_F(ScrollPredictorTest, FilteringPrediction) { + ConfigureFilterFieldTrial(features::kResamplingScrollEvents, + input_prediction::kScrollPredictorNameKalman); + scroll_predictor_ = std::make_unique<ScrollPredictor>(); + + std::vector<double> accumulated_deltas; + WebScopedInputEvent gesture_update; + + for (int i = 0; i < 100; i++) { + // Create event at time 8*i + gesture_update = CreateGestureScrollUpdate(0, 3 * i, 8 * i /* ms */); + // Handle the event 5 ms later + HandleResampleScrollEvents(gesture_update, 8 * i + 5 /* ms */); + EXPECT_FALSE(isFilteringEnabled()); + accumulated_deltas.push_back(GetLastAccumulatedDelta().y()); + } + EXPECT_EQ((int)accumulated_deltas.size(), 100); + + // Now we enable filtering and compare the deltas + ConfigurePredictorFieldTrial(features::kResamplingScrollEvents, + input_prediction::kScrollPredictorNameKalman); + ConfigureFilterFieldTrial(features::kFilteringScrollPrediction, + input_prediction::kFilterNameEmpty); + scroll_predictor_ = std::make_unique<ScrollPredictor>(); + + for (int i = 0; i < 100; i++) { + // Create event at time 8*i + gesture_update = CreateGestureScrollUpdate(0, 3 * i, 8 * i /* ms */); + // Handle the event 5 ms later + HandleResampleScrollEvents(gesture_update, 8 * i + 5 /* ms */); + EXPECT_TRUE(isFilteringEnabled()); + EXPECT_NEAR(accumulated_deltas[i], GetLastAccumulatedDelta().y(), 0.00001); + } +} + } // namespace test } // namespace ui
diff --git a/ui/events/platform/platform_event_source_unittest.cc b/ui/events/platform/platform_event_source_unittest.cc index 8dba043b..3be3623 100644 --- a/ui/events/platform/platform_event_source_unittest.cc +++ b/ui/events/platform/platform_event_source_unittest.cc
@@ -12,10 +12,10 @@ #include <vector> #include "base/bind.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" +#include "base/test/scoped_task_environment.h" #include "base/threading/thread_task_runner_handle.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/platform/platform_event_dispatcher.h" @@ -498,7 +498,7 @@ ~PlatformEventTestWithMessageLoop() override {} void Run() { - message_loop_.task_runner()->PostTask( + scoped_task_environment_.GetMainThreadTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&PlatformEventTestWithMessageLoop::RunTestImpl, base::Unretained(this))); @@ -509,7 +509,8 @@ virtual void RunTestImpl() = 0; private: - base::MessageLoopForUI message_loop_; + base::test::ScopedTaskEnvironment scoped_task_environment_{ + base::test::ScopedTaskEnvironment::MainThreadType::UI}; DISALLOW_COPY_AND_ASSIGN(PlatformEventTestWithMessageLoop); };
diff --git a/ui/file_manager/base/js/volume_manager_types.js b/ui/file_manager/base/js/volume_manager_types.js index 2e74b938..6fc10e7 100644 --- a/ui/file_manager/base/js/volume_manager_types.js +++ b/ui/file_manager/base/js/volume_manager_types.js
@@ -43,9 +43,9 @@ * @const */ VolumeManagerCommon.FileSystemTypeVolumeNameLengthLimit = { - [VolumeManagerCommon.FileSystemType.VFAT]: 11, - [VolumeManagerCommon.FileSystemType.EXFAT]: 15, - [VolumeManagerCommon.FileSystemType.NTFS]: 32, + 'vfat': 11, + 'exfat': 15, + 'ntfs': 32, }; /**
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js index d973f885..f27ca5c 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -631,7 +631,15 @@ CommandHandler.COMMANDS_['format'] = new class extends Command { execute(event, fileManager) { const directoryModel = fileManager.directoryModel; - let root = CommandUtil.getCommandEntry(fileManager, event.target); + let root; + if (event.target instanceof DirectoryItem || + event.target instanceof DirectoryTree) { + // The command is executed from the directory tree context menu. + root = CommandUtil.getCommandEntry(fileManager, event.target); + } else { + // The command is executed from the gear menu. + root = directoryModel.getCurrentDirEntry(); + } // If an entry is not found from the event target, use the current // directory. This can happen for the format button for unsupported and // unrecognized volumes. @@ -658,7 +666,15 @@ /** @override */ canExecute(event, fileManager) { const directoryModel = fileManager.directoryModel; - let root = CommandUtil.getCommandEntry(fileManager, event.target); + let root; + if (event.target instanceof DirectoryItem || + event.target instanceof DirectoryTree) { + // The command is executed from the directory tree context menu. + root = CommandUtil.getCommandEntry(fileManager, event.target); + } else { + // The command is executed from the gear menu. + root = directoryModel.getCurrentDirEntry(); + } // |root| is null for unrecognized volumes. Enable format command for such // volumes. const isUnrecognizedVolume = (root == null);
diff --git a/ui/gfx/platform_font_skia.h b/ui/gfx/platform_font_skia.h index 9822bf7..d38e6d6 100644 --- a/ui/gfx/platform_font_skia.h +++ b/ui/gfx/platform_font_skia.h
@@ -57,8 +57,6 @@ int GetFontSize() const override; const FontRenderParams& GetFontRenderParams() override; - sk_sp<SkTypeface> typeface() const { return typeface_; } - private: // Create a new instance of this object with the specified properties. Called // from DeriveFont.
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc index 90938df..415bc43 100644 --- a/ui/gl/direct_composition_surface_win.cc +++ b/ui/gl/direct_composition_surface_win.cc
@@ -281,6 +281,16 @@ } // static +bool DirectCompositionSurfaceWin::IsDecodeSwapChainSupported() { + if (base::FeatureList::IsEnabled( + features::kDirectCompositionUseNV12DecodeSwapChain)) { + InitializeHardwareOverlaySupport(); + return GetOverlayFormatUsed() == DXGI_FORMAT_NV12; + } + return false; +} + +// static void DirectCompositionSurfaceWin::DisableOverlays() { g_supports_overlays = false; }
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h index b43e1da..b504372 100644 --- a/ui/gl/direct_composition_surface_win.h +++ b/ui/gl/direct_composition_surface_win.h
@@ -52,6 +52,9 @@ // --enable-direct-composition-layers and --disable-direct-composition-layers. static bool AreOverlaysSupported(); + // Returns true if zero copy decode swap chain is supported. + static bool IsDecodeSwapChainSupported(); + // After this is called, hardware overlay support is disabled during the // current GPU process' lifetime. static void DisableOverlays();
diff --git a/ui/ozone/platform/x11/BUILD.gn b/ui/ozone/platform/x11/BUILD.gn index 42637c3..5203655d 100644 --- a/ui/ozone/platform/x11/BUILD.gn +++ b/ui/ozone/platform/x11/BUILD.gn
@@ -88,6 +88,7 @@ ":x11", "//testing/gmock", "//testing/gtest", + "//ui/base/x", "//ui/events:test_support", "//ui/events/devices/x11", "//ui/events/platform/x11",
diff --git a/ui/ozone/platform/x11/x11_screen_ozone.cc b/ui/ozone/platform/x11/x11_screen_ozone.cc index b2188c9..5ad33f03 100644 --- a/ui/ozone/platform/x11/x11_screen_ozone.cc +++ b/ui/ozone/platform/x11/x11_screen_ozone.cc
@@ -4,18 +4,12 @@ #include "ui/ozone/platform/x11/x11_screen_ozone.h" -#include "base/bind.h" -#include "base/threading/thread_task_runner_handle.h" -#include "ui/base/x/x11_display_util.h" #include "ui/base/x/x11_util.h" #include "ui/display/display_finder.h" #include "ui/display/util/display_util.h" -#include "ui/display/util/x11/edid_parser_x11.h" #include "ui/events/platform/x11/x11_event_source.h" #include "ui/gfx/font_render_params.h" #include "ui/gfx/geometry/dip_util.h" -#include "ui/gfx/x/x11.h" -#include "ui/gfx/x/x11_atom_cache.h" #include "ui/ozone/platform/x11/x11_window_manager_ozone.h" #include "ui/ozone/platform/x11/x11_window_ozone.h" @@ -23,10 +17,6 @@ namespace { -constexpr int kMinVersionXrandr = 103; // Need at least xrandr version 1.3. - -constexpr auto kDisplayListUpdateDelay = base::TimeDelta::FromMilliseconds(250); - float GetDeviceScaleFactor() { float device_scale_factor = 1.0f; // TODO(crbug.com/891175): Implement PlatformScreen for X11 @@ -111,44 +101,31 @@ X11ScreenOzone::X11ScreenOzone(X11WindowManagerOzone* window_manager) : window_manager_(window_manager), - xdisplay_(gfx::GetXDisplay()), - x_root_window_(DefaultRootWindow(xdisplay_)), - xrandr_version_(GetXrandrVersion(xdisplay_)) { + x11_display_manager_(std::make_unique<XDisplayManager>(this)) { DCHECK(window_manager_); } X11ScreenOzone::~X11ScreenOzone() { - if (xrandr_version_ >= kMinVersionXrandr && + if (x11_display_manager_->IsXrandrAvailable() && X11EventSourceLibevent::GetInstance()) { X11EventSourceLibevent::GetInstance()->RemoveXEventDispatcher(this); } } void X11ScreenOzone::Init() { - // Need at least xrandr version 1.3. - if (xrandr_version_ >= kMinVersionXrandr) { - int error_base_ignored = 0; - XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored); - - DCHECK(X11EventSourceLibevent::GetInstance()); + if (x11_display_manager_->IsXrandrAvailable() && + X11EventSourceLibevent::GetInstance()) { X11EventSourceLibevent::GetInstance()->AddXEventDispatcher(this); - - XRRSelectInput(xdisplay_, x_root_window_, - RRScreenChangeNotifyMask | RROutputChangeNotifyMask | - RRCrtcChangeNotifyMask); } - FetchDisplayList(); + x11_display_manager_->Init(); } const std::vector<display::Display>& X11ScreenOzone::GetAllDisplays() const { - return displays_; + return x11_display_manager_->displays(); } display::Display X11ScreenOzone::GetPrimaryDisplay() const { - auto iter = displays_.begin(); - if (iter == displays_.end()) - return display::Display::GetDefaultDisplay(); - return *iter; + return x11_display_manager_->GetPrimaryDisplay(); } display::Display X11ScreenOzone::GetDisplayForAcceleratedWidget( @@ -190,82 +167,35 @@ const gfx::Rect& match_rect) const { const display::Display* matching_display = display::FindDisplayWithBiggestIntersection( - displays_, gfx::ConvertRectToDIP(GetDeviceScaleFactor(), match_rect)); + x11_display_manager_->displays(), + gfx::ConvertRectToDIP(GetDeviceScaleFactor(), match_rect)); return matching_display ? *matching_display : GetPrimaryDisplay(); } void X11ScreenOzone::AddObserver(display::DisplayObserver* observer) { - change_notifier_.AddObserver(observer); + x11_display_manager_->AddObserver(observer); } void X11ScreenOzone::RemoveObserver(display::DisplayObserver* observer) { - change_notifier_.RemoveObserver(observer); + x11_display_manager_->RemoveObserver(observer); } -// TODO(nickdiego): Factor event dispatching and display fetching so that it -// can be shared between ozone and non-ozone code paths. bool X11ScreenOzone::DispatchXEvent(XEvent* xev) { - DCHECK(xev); - int ev_type = xev->type - xrandr_event_base_; - if (ev_type == RRScreenChangeNotify) { - // Pass the event through to xlib. - XRRUpdateConfiguration(xev); - return true; - } - if (ev_type == RRNotify || - (xev->type == PropertyNotify && - xev->xproperty.atom == gfx::GetAtom("_NET_WORKAREA"))) { - RestartDelayedUpdateDisplayListTask(); - return true; - } - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// X11ScreenOzone, private: - -void X11ScreenOzone::SetDisplayList(std::vector<display::Display> displays) { - displays_ = std::move(displays); - gfx::SetFontRenderParamsDeviceScaleFactor( - GetPrimaryDisplay().device_scale_factor()); -} - -// Talks to xrandr to get the information of the outputs for a screen and -// updates display::Display list. The minimum required version of xrandr is -// 1.3. -void X11ScreenOzone::FetchDisplayList() { - std::vector<display::Display> displays; - float scale = GetDeviceScaleFactor(); - if (xrandr_version_ >= kMinVersionXrandr) { - displays = BuildDisplaysFromXRandRInfo(xrandr_version_, scale, - &primary_display_index_); - } else { - displays = GetFallbackDisplayList(scale); - } - SetDisplayList(std::move(displays)); -} - -void X11ScreenOzone::UpdateDisplayList() { - std::vector<display::Display> old_displays = displays_; - FetchDisplayList(); - change_notifier_.NotifyDisplaysChanged(old_displays, displays_); -} - -void X11ScreenOzone::RestartDelayedUpdateDisplayListTask() { - delayed_update_task_.Reset(base::BindOnce(&X11ScreenOzone::UpdateDisplayList, - base::Unretained(this))); - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, delayed_update_task_.callback(), kDisplayListUpdateDelay); + return x11_display_manager_->ProcessEvent(xev); } gfx::Point X11ScreenOzone::GetCursorLocation() const { - ::Window root, child; - int root_x, root_y, win_x, win_y; - unsigned int mask; - XQueryPointer(xdisplay_, x_root_window_, &root, &child, &root_x, &root_y, - &win_x, &win_y, &mask); + return x11_display_manager_->GetCursorLocation(); +} - return gfx::Point(root_x, root_y); +void X11ScreenOzone::OnXDisplayListUpdated() { + float scale_factor = + x11_display_manager_->GetPrimaryDisplay().device_scale_factor(); + gfx::SetFontRenderParamsDeviceScaleFactor(scale_factor); +} + +float X11ScreenOzone::GetXDisplayScaleFactor() { + return GetDeviceScaleFactor(); } } // namespace ui
diff --git a/ui/ozone/platform/x11/x11_screen_ozone.h b/ui/ozone/platform/x11/x11_screen_ozone.h index 49eed35b..4afda89 100644 --- a/ui/ozone/platform/x11/x11_screen_ozone.h +++ b/ui/ozone/platform/x11/x11_screen_ozone.h
@@ -6,16 +6,14 @@ #define UI_OZONE_PLATFORM_X11_X11_SCREEN_OZONE_H_ #include <memory> +#include <utility> #include <vector> -#include "base/cancelable_callback.h" #include "base/macros.h" #include "base/observer_list.h" -#include "ui/display/display.h" -#include "ui/display/display_change_notifier.h" +#include "ui/base/x/x11_display_manager.h" #include "ui/events/platform/x11/x11_event_source_libevent.h" #include "ui/gfx/geometry/point.h" -#include "ui/gfx/x/x11_types.h" #include "ui/ozone/public/platform_screen.h" namespace ui { @@ -23,7 +21,9 @@ class X11WindowManagerOzone; // A PlatformScreen implementation for X11. -class X11ScreenOzone : public PlatformScreen, public XEventDispatcher { +class X11ScreenOzone : public PlatformScreen, + public XEventDispatcher, + public XDisplayManager::Delegate { public: explicit X11ScreenOzone(X11WindowManagerOzone* window_manager); ~X11ScreenOzone() override; @@ -52,31 +52,14 @@ private: friend class X11ScreenOzoneTest; - void SetDisplayList(std::vector<display::Display> displays); - void FetchDisplayList(); - void UpdateDisplayList(); - void RestartDelayedUpdateDisplayListTask(); + // Overridden from ui::XDisplayManager::Delegate: + void OnXDisplayListUpdated() override; + float GetXDisplayScaleFactor() override; + gfx::Point GetCursorLocation() const; - std::vector<display::Display> displays_; - display::DisplayChangeNotifier change_notifier_; - X11WindowManagerOzone* const window_manager_; - - XDisplay* const xdisplay_; - XID x_root_window_; - int64_t primary_display_index_ = 0; - - // XRandR version. MAJOR * 100 + MINOR. Zero if no xrandr is present. - const int xrandr_version_; - - // The base of the event numbers used to represent XRandr events used in - // decoding events regarding output add/remove. - int xrandr_event_base_ = 0; - - // The task to delay fetching display info. We delay it so that we can - // coalesce events. - base::CancelableOnceClosure delayed_update_task_; + std::unique_ptr<ui::XDisplayManager> x11_display_manager_; DISALLOW_COPY_AND_ASSIGN(X11ScreenOzone); };
diff --git a/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc b/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc index 5e51f7e..a5da019 100644 --- a/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc +++ b/ui/ozone/platform/x11/x11_screen_ozone_unittest.cc
@@ -9,6 +9,7 @@ #include "base/test/scoped_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/x/x11_display_manager.h" #include "ui/display/display.h" #include "ui/display/display_observer.h" #include "ui/events/platform/x11/x11_event_source_libevent.h" @@ -60,7 +61,7 @@ primary_display_ = std::make_unique<display::Display>( NextDisplayId(), kPrimaryDisplayBounds); screen_.reset(new X11ScreenOzone(window_manager_.get())); - screen_->SetDisplayList({*primary_display_}); + UpdateDisplayListForTest({*primary_display_}); screen_->AddObserver(&display_observer_); } @@ -73,23 +74,26 @@ } void AddDisplayForTest(const display::Display& display) { - std::vector<display::Display> new_displays(screen_->displays_); + auto display_list = screen_->GetAllDisplays(); + std::vector<display::Display> new_displays(display_list); new_displays.push_back(display); UpdateDisplayListForTest(std::move(new_displays)); } void RemoveDisplayForTest(const display::Display& display_to_remove) { - std::vector<display::Display> new_displays(screen_->displays_.size() - 1); - std::remove_copy(screen_->displays_.begin(), screen_->displays_.end(), + auto display_list = screen_->GetAllDisplays(); + std::vector<display::Display> new_displays(display_list.size() - 1); + std::remove_copy(display_list.begin(), display_list.end(), new_displays.begin(), display_to_remove); UpdateDisplayListForTest(std::move(new_displays)); } void UpdateDisplayListForTest(std::vector<display::Display> displays) { - std::vector<display::Display> old_displays = std::move(screen_->displays_); - screen_->SetDisplayList(std::move(displays)); - screen_->change_notifier_.NotifyDisplaysChanged(old_displays, - screen_->displays_); + ui::XDisplayManager* manager = screen_->x11_display_manager_.get(); + std::vector<display::Display> old_displays = std::move(manager->displays_); + manager->SetDisplayList(std::move(displays)); + manager->change_notifier_.NotifyDisplaysChanged(old_displays, + manager->displays_); } std::unique_ptr<X11WindowOzone> CreatePlatformWindow( @@ -121,7 +125,7 @@ // Initially only primary display is expected to be in place EXPECT_EQ(1u, screen()->GetAllDisplays().size()); EXPECT_CALL(display_observer_, OnDisplayAdded(_)).Times(2); - EXPECT_CALL(display_observer_, OnDisplayRemoved(_)).Times(3); + EXPECT_CALL(display_observer_, OnDisplayRemoved(_)).Times(2); auto display_2 = CreateDisplay(gfx::Rect(800, 0, 1280, 720)); AddDisplayForTest(*display_2); @@ -135,8 +139,6 @@ EXPECT_EQ(2u, screen()->GetAllDisplays().size()); RemoveDisplayForTest(*display_2); EXPECT_EQ(1u, screen()->GetAllDisplays().size()); - RemoveDisplayForTest(primary_display()); - EXPECT_EQ(0u, screen()->GetAllDisplays().size()); } // This test case exercises GetDisplayForAcceleratedWidget when simple cases
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd index b3a09ac4..e69dd4c 100644 --- a/ui/strings/ui_strings.grd +++ b/ui/strings/ui_strings.grd
@@ -977,7 +977,7 @@ Call this number from your phone? </message> <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TITLE_FAILED_TO_SEND" desc="The label to be shown as the title of the dialog when user click on a phone number, if sending it to a device failed."> - Number failed to send + Can't send number </message> <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_HELP_TEXT_NO_DEVICES" desc="The label to be shown as a help text of the dialog when user click on a phone number, if there are no phones or apps to choose from."> To make a call from your phone, turn on sync. @@ -985,11 +985,8 @@ <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_SYNC_HELP_TEXT" desc="The label to be shown on the dialog when user click on a phone number for the link to a help page to turn on sync."> Learn how to turn on sync </message> - <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE" desc="The label to be shown on the dialog when user click on a phone number for the link to a help page to turn on sync."> - Looks like something has gone wrong. Try again or <ph name="TROUBLESHOOT_LINK">$1<ex>learn how to troubleshoot Click to Call</ex></ph>. - </message> - <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TROUBLESHOOT_LINK" desc="The label to be shown on the dialog when user click on a phone number for the link to a help page to turn on sync."> - learn how to troubleshoot Click to Call + <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE" desc="The label to be shown on the dialog when user click on a phone number, if sending it to a device failed."> + Check your phone's connection and try again </message> <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_SEND_SUCCESS" desc="The label to be shown next to the omnibox icon after a phone number got sent to a users device."> Sent to device
diff --git a/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE.png.sha1 b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE.png.sha1 index 6b80593..97e13fa 100644 --- a/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE.png.sha1 +++ b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE.png.sha1
@@ -1 +1 @@ -0118433c23636f72e89ecb6792a680d6e13b702f \ No newline at end of file +5ea3791f2b6f05be1604b41f540cfa0a2d2555eb \ No newline at end of file
diff --git a/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TITLE_FAILED_TO_SEND.png.sha1 b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TITLE_FAILED_TO_SEND.png.sha1 index 6b80593..97e13fa 100644 --- a/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TITLE_FAILED_TO_SEND.png.sha1 +++ b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TITLE_FAILED_TO_SEND.png.sha1
@@ -1 +1 @@ -0118433c23636f72e89ecb6792a680d6e13b702f \ No newline at end of file +5ea3791f2b6f05be1604b41f540cfa0a2d2555eb \ No newline at end of file
diff --git a/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TROUBLESHOOT_LINK.png.sha1 b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TROUBLESHOOT_LINK.png.sha1 deleted file mode 100644 index 6b80593..0000000 --- a/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TROUBLESHOOT_LINK.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -0118433c23636f72e89ecb6792a680d6e13b702f \ No newline at end of file
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.cc b/ui/views/controls/tabbed_pane/tabbed_pane.cc index 812c440..905c9144 100644 --- a/ui/views/controls/tabbed_pane/tabbed_pane.cc +++ b/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -751,6 +751,7 @@ DCHECK_LE(index, GetTabCount()); contents->SetVisible(false); contents->GetViewAccessibility().OverrideName(title); + contents->GetViewAccessibility().OverrideRole(ax::mojom::Role::kTab); tab_strip_->AddChildViewAt( std::make_unique<MdTab>(this, title, contents.get()),
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc index effb323..b92e074 100644 --- a/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc +++ b/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
@@ -34,6 +34,12 @@ return ax_node_data.GetString16Attribute(ax::mojom::StringAttribute::kName); } +ax::mojom::Role GetAccessibleRole(View* view) { + ui::AXNodeData ax_node_data; + view->GetViewAccessibility().GetAccessibleNodeData(&ax_node_data); + return ax_node_data.role; +} + } // namespace class TabbedPaneTest : public ViewsTestBase { @@ -294,5 +300,16 @@ EXPECT_EQ(kSecondTitle, GetAccessibleName(tab2_contents)); } +TEST_F(TabbedPaneTest, AccessiblePaneContentsRoleIsTab) { + const base::string16 kFirstTitle = ASCIIToUTF16("Tab1"); + const base::string16 kSecondTitle = ASCIIToUTF16("Tab2"); + View* const tab1_contents = + tabbed_pane_->AddTab(kFirstTitle, std::make_unique<View>()); + View* const tab2_contents = + tabbed_pane_->AddTab(kSecondTitle, std::make_unique<View>()); + EXPECT_EQ(ax::mojom::Role::kTab, GetAccessibleRole(tab1_contents)); + EXPECT_EQ(ax::mojom::Role::kTab, GetAccessibleRole(tab2_contents)); +} + } // namespace test } // namespace views
diff --git a/ui/views/test/OWNERS b/ui/views/test/OWNERS index 597e3ef..3b9f6f4 100644 --- a/ui/views/test/OWNERS +++ b/ui/views/test/OWNERS
@@ -1 +1,2 @@ per-file *_mac*=tapted@chromium.org +per-file *x11*=thomasanderson@chromium.org
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html index 949f3e08..e2be730 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html
@@ -7,6 +7,7 @@ <link rel="import" href="chrome://resources/cr_components/chromeos/cellular_setup/provisioning_page.html"> <link rel="import" href="chrome://resources/cr_components/chromeos/cellular_setup/final_page.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html"> <dom-module id="cellular-setup">
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html b/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html index 1cde306..ec6ef31 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html
@@ -2,13 +2,33 @@ <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/cr_components/chromeos/cellular_setup/base_page.html"> +<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> <dom-module id="sim-detect-page"> <template> - <base-page title="[[i18n('simDetectPageTitle')]]"> - <div slot="page-body"> - <!-- TODO(azeemarshad): Add page assets and strings --> - [[i18n('simDetectPageTitle')]] + <style include="iron-flex cr-hidden-style"> + paper-spinner-lite { + height: 200px; + width: 200px; + } + + #error-icon-container { + background-image: -webkit-image-set( + url(error_1x.png) 1x, + url(error_2x.png) 2x); + background-position: center center; + background-repeat: no-repeat; + height: 100%; + width: 100%; + } + </style> + <base-page title="[[getTitle_(showError)]]" + message="[[getMessage_(showError)]]"> + <div slot="page-body" class="layout horizontal center-center"> + <paper-spinner-lite active hidden$="[[showError]]"></paper-spinner-lite> + <div id="error-icon-container" hidden$="[[!showError]]"></div> </div> </base-page> </template>
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js index 8f6357dc..eb5581d 100644 --- a/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js +++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js
@@ -18,9 +18,25 @@ * Whether error state should be shown. * @type {boolean} */ - showError: { - type: Boolean, - value: false, - }, - } + showError: Boolean, + }, + + /** + * @param {boolean} showError + * @return {string} + * @private + */ + getTitle_: function(showError) { + return this.i18n( + showError ? 'simDetectPageErrorTitle' : 'simDetectPageTitle'); + }, + + /** + * @param {boolean} showError + * @return {string} + * @private + */ + getMessage_: function(showError) { + return showError ? this.i18n('simDetectPageErrorMessage') : ''; + }, });