diff --git a/DEPS b/DEPS index 2de60bc..4fb17fb 100644 --- a/DEPS +++ b/DEPS
@@ -304,11 +304,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': '32f4cfc2460b48e00f05c73ef41cdf2852617f0b', + 'skia_revision': 'bab970602f56a36149edc0b1781bb255ac6ea94f', # 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': 'ab2b75dcf8729614806334150606d018bc092f7d', + 'v8_revision': '2e6df1125542b4f2284301d807d546a9d00cdd57', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. @@ -375,7 +375,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': 'e40b8a3047f3b3b0471e26963b543f51a2b8abca', + 'catapult_revision': 'c8904f0248c4d61966bdf62d4e7f3bead51c4b27', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. @@ -431,7 +431,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '6c1812305823e7552cb877e3fdd47e9022c54752', + 'dawn_revision': 'c95576ed7b8609b0baa12bd912d374fa56b496ef', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -495,7 +495,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling beto-core # and whatever else without interference from each other. - 'betocore_revision': '6df0d1d7733a84d36b6a496f2f938c3577491d00', + 'betocore_revision': 'd905e113aa8df4f46e3f193a2433e59994510039', # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. @@ -796,7 +796,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - '2206d93464819bdca32639e3fd89f746fe59ebc0', + 'd358ebe285396c6f2c537634889e972ef5dc8c4d', 'condition': 'checkout_android and checkout_src_internal', }, @@ -895,7 +895,7 @@ 'packages': [ { 'package': 'chromium/rts/model/linux-amd64', - 'version': 'Ig2CwUlwBkICPY7DwtdWBMAibAVoWN9VzwMgn9wk9m8C', + 'version': '1HQv2efViD98yANoT-hHFtTP2WjbMM_C4kNA2ZGPL7kC', }, ], 'dep_type': 'cipd', @@ -906,7 +906,7 @@ 'packages': [ { 'package': 'chromium/rts/model/mac-amd64', - 'version': 'K9ZAgnmyEE30USYe2SK2xnBIvSuJvRPlMw7O_wiHiHgC', + 'version': 'MXgEsfu4itz-ZSmTvacF6xbE9XkkVh5BBpGRdX5VGKQC', }, ], 'dep_type': 'cipd', @@ -917,7 +917,7 @@ 'packages': [ { 'package': 'chromium/rts/model/windows-amd64', - 'version': 'x36-iYLaXE4ONPSClrrwGk7wNaDDl0ldymeNbblC7SkC', + 'version': 'TkqKOKFVbvnmyXX89FPmBkT1UpUgpXrE2OiiK9Akw6MC', }, ], 'dep_type': 'cipd', @@ -985,7 +985,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'QNAxUuOTpBt1SYYwm3OThELbjhGSxagL_Wf49uXtSS4C', + 'version': 'NpubdKxhjEsiLgadf-P8XMZ0emcO9p64vQxHKNfneNYC', }, ], 'condition': 'checkout_android', @@ -1220,7 +1220,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'f155639336aff1e8c3822974749ac695ec83b2b5', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '967cf672ebaa1d593be1d24e732cb5d0ddcfef1b', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1693,7 +1693,7 @@ Var('pdfium_git') + '/pdfium.git' + '@' + Var('pdfium_revision'), 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '6c650e1ad49593538b1bff04070cce56b8f036f9', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '0ce368c86c8aa9cf6338ddcd80c485c3bf1e5e7e', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1733,7 +1733,7 @@ 'packages': [ { 'package': 'chromium/third_party/r8', - 'version': '_46Jff_5DxQREre2ppSsZwebqQYn7rCXCukEvdhmjqsC', + 'version': '0gcMolQsxjUMbPA45S29WIXedlOUN8pu5W2H2cuJxwYC', }, ], 'condition': 'checkout_android', @@ -1838,7 +1838,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@da6d09fb0492cfeecc2a254152a07de5c3e0b11c', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@917d7c4c0a5824b93c4d4ce5d9d07df1f39f9fbe', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907', @@ -1878,7 +1878,7 @@ Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'e8dbfc3f48b4605bd0eb5bfb7c361434480b55fd', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '2d7424305d1d24d9c26c463b7a45eb58cc7d3362', + Var('webrtc_git') + '/src.git' + '@' + 'c0b470c327b8803000c61d93feafeb3fa5f0d2c0', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -1968,7 +1968,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': Var('chrome_git') + '/chrome/src-internal.git@674c93aad4f2c2ac75cd23f2ee77ac5637b60ab0', + 'url': Var('chrome_git') + '/chrome/src-internal.git@3201722c75cc9aac2e0827cde347d2616f508eda', 'condition': 'checkout_src_internal', }, @@ -1998,7 +1998,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/help_app/app', - 'version': 'ZI5GbVjUHhOwXBXMpvsi15R2s7fDynAZP8xV4ZR8M8gC', + 'version': '3MrPkELKn2N-dFJHXELe2WZLTgJ4G9CC-kW9z1cIRZ0C', }, ], 'condition': 'checkout_chromeos and checkout_src_internal', @@ -3954,7 +3954,7 @@ 'src/ui/gl/resources/angle-metal': { 'packages': [{ 'package': 'chromium/gpu/angle-metal-shader-libraries', - 'version': 'MgV6oAmR2qNXuqP5aVyQcQhZiOt3pjb8MNR_N7IkzjcC', + 'version': 'ixOfHKV8hd24AUIOOdBb8_wyTBlppezjgOOIaGdkQqoC', }], 'dep_type': 'cipd', 'condition': 'checkout_mac or checkout_ios', @@ -4167,7 +4167,7 @@ 'src/ios_internal': { 'url': '{chrome_git}/chrome/ios_internal.git' + '@' + - '9ed042536d45a402fa072578f3d1caaf23e21f62', + '1858ff8a4321479da1b94cd0cfa40b3b8e5d5840', 'condition': 'checkout_ios and checkout_src_internal', }, @@ -4409,6 +4409,7 @@ '-third_party/abseil-cpp/absl/random', '-third_party/abseil-cpp/absl/status/statusor.h', '-third_party/abseil-cpp/absl/strings', + '+third_party/abseil-cpp/absl/strings/ascii.h', '+third_party/abseil-cpp/absl/strings/cord.h', '-third_party/abseil-cpp/absl/synchronization', '-third_party/abseil-cpp/absl/time',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index ae1232a..9b8ad56 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -6050,6 +6050,7 @@ # - If the CL contains removed messages in grd files but the corresponding # .sha1 files aren't removed, warn the developer to remove them. unnecessary_screenshots = [] + invalid_sha1 = [] missing_sha1 = [] missing_sha1_modified = [] unnecessary_sha1_files = [] @@ -6061,18 +6062,33 @@ # break message extraction for translation, hence would block Chromium # translations until they are fixed. icu_syntax_errors = [] + sha1_pattern = input_api.re.compile(r'^[a-fA-F0-9]{40}$', + input_api.re.MULTILINE) def _CheckScreenshotAdded(screenshots_dir, message_id): sha1_path = input_api.os_path.join(screenshots_dir, message_id + '.png.sha1') if sha1_path not in new_or_added_paths: missing_sha1.append(sha1_path) + elif not _CheckValidSha1(sha1_path): + invalid_sha1.append(sha1_path) def _CheckScreenshotModified(screenshots_dir, message_id): sha1_path = input_api.os_path.join(screenshots_dir, message_id + '.png.sha1') if sha1_path not in new_or_added_paths: missing_sha1_modified.append(sha1_path) + elif not _CheckValidSha1(sha1_path): + invalid_sha1.append(sha1_path) + + def _CheckValidSha1(sha1_path): + return sha1_pattern.search( + next( + "\n".join(f.NewContents()) + for f in input_api.AffectedFiles() + if f.LocalPath() == sha1_path + ) + ) def _CheckScreenshotRemoved(screenshots_dir, message_id): sha1_path = input_api.os_path.join(screenshots_dir, @@ -6270,14 +6286,8 @@ modified_ids.add(key) elif old_id_to_msg_map[key].attrs['meaning'] != \ new_id_to_msg_map[key].attrs['meaning']: - # The message meaning changed. Ensure there is a screenshot for it. - sha1_path = input_api.os_path.join(screenshots_dir, - key + '.png.sha1') - if sha1_path not in new_or_added_paths and not \ - input_api.os_path.exists(sha1_path): - # There is neither a previous screenshot nor is a new one added now. - # Require a screenshot. - modified_ids.add(key) + # The message meaning changed. We later check for a screenshot. + modified_ids.add(key) if run_screenshot_check: # Check the screenshot directory for .png files. Warn if there is any. @@ -6318,6 +6328,13 @@ '(https://g.co/chrome/translation) and add these files to your ' 'changelist:', sorted(missing_sha1))) + if invalid_sha1: + results.append( + output_api.PresubmitError( + 'The following files do not seem to contain valid sha1 hashes. ' + 'Make sure they contain hashes created by ' + 'tools/translate/upload_screenshots.py:', sorted(invalid_sha1))) + if missing_sha1_modified: results.append( output_api.PresubmitError(
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py index 8437775..ea7797d 100755 --- a/PRESUBMIT_test.py +++ b/PRESUBMIT_test.py
@@ -3467,6 +3467,7 @@ '</message>', '</grit-part>') + VALID_SHA1 = ('0000000000000000000000000000000000000000',) DO_NOT_UPLOAD_PNG_MESSAGE = ('Do not include actual screenshots in the ' 'changelist. Run ' 'tools/translate/upload_screenshots.py to ' @@ -3481,6 +3482,9 @@ ICU_SYNTAX_ERROR_MESSAGE = ('ICU syntax errors were found in the following ' 'strings (problems or feedback? Contact ' 'rainhard@chromium.org):') + SHA1_FORMAT_MESSAGE = ('The following files do not seem to contain valid sha1 ' + 'hashes. Make sure they contain hashes created by ' + 'tools/translate/upload_screenshots.py:') def makeInputApi(self, files): input_api = MockInputApi() @@ -3549,7 +3553,7 @@ MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS3, self.NEW_GRDP_CONTENTS4, action='M'), MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'), - 'binary', action='A')]) + self.VALID_SHA1, action='A')]) warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi()) self.assertEqual(0, len(warnings)) @@ -3568,10 +3572,20 @@ MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS5, self.NEW_GRDP_CONTENTS6, action='M'), MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'), - 'binary', action='A')]) + self.VALID_SHA1, action='A')]) warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi()) self.assertEqual(0, len(warnings)) + def testModifiedIntroducedInvalidSha1(self): + # CL modified a message and the sha1 file changed to invalid + input_api = self.makeInputApi([ + MockAffectedFile('part.grdp', self.NEW_GRDP_CONTENTS5, + self.NEW_GRDP_CONTENTS6, action='M'), + MockAffectedFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'), + ('some invalid sha1',), self.VALID_SHA1, action='M')]) + warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi()) + self.assertEqual(1, len(warnings)) + def testPngAddedSha1NotAdded(self): # CL added one new message in a grd file and added the png file associated # with it, but did not add the corresponding sha1 file. This should warn @@ -3637,6 +3651,7 @@ os.path.join('test_grd', 'IDS_TEST1.png.sha1')], warnings[1].items) + def testScreenshotsWithSha1(self): # CL added four messages (two each in a grd and grdp) and their # corresponding .sha1 files. No warnings. @@ -3655,24 +3670,64 @@ # Added files: MockFile( os.path.join('test_grd', 'IDS_TEST1.png.sha1'), - 'binary', + self.VALID_SHA1, action='A'), MockFile( os.path.join('test_grd', 'IDS_TEST2.png.sha1'), - 'binary', + ('0000000000000000000000000000000000000000', ''), action='A'), MockFile( os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'), - 'binary', + self.VALID_SHA1, action='A'), MockFile( os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'), - 'binary', + self.VALID_SHA1, action='A'), ]) warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi()) self.assertEqual([], warnings) + + def testScreenshotsWithInvalidSha1(self): + input_api = self.makeInputApi([ + # Modified files: + MockAffectedFile( + 'test.grd', + self.NEW_GRD_CONTENTS2, + self.OLD_GRD_CONTENTS, + action='M'), + MockAffectedFile( + 'part.grdp', + self.NEW_GRDP_CONTENTS2, + self.OLD_GRDP_CONTENTS, + action='M'), + # Added files: + MockFile( + os.path.join('test_grd', 'IDS_TEST1.png.sha1'), + self.VALID_SHA1, + action='A'), + MockFile( + os.path.join('test_grd', 'IDS_TEST2.png.sha1'), + ('‰PNG', 'test'), + action='A'), + MockFile( + os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'), + self.VALID_SHA1, + action='A'), + MockFile( + os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'), + self.VALID_SHA1, + action='A'), + ]) + warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi()) + self.assertEqual(1, len(warnings)) + self.assertEqual('error', warnings[0].type) + self.assertEqual(self.SHA1_FORMAT_MESSAGE, warnings[0].message) + self.assertEqual([os.path.join('test_grd', 'IDS_TEST2.png.sha1')], + warnings[0].items) + + def testScreenshotsRemovedWithSha1(self): # Replace new contents with old contents in grd and grp files, removing # IDS_TEST1, IDS_TEST2, IDS_PART_TEST1 and IDS_PART_TEST2. @@ -3690,12 +3745,14 @@ self.NEW_GRDP_CONTENTS2, # old_contents action='M'), # Unmodified files: - MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'), 'binary', ''), - MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'), 'binary', ''), + MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'), + self.VALID_SHA1, ''), + MockFile(os.path.join('test_grd', 'IDS_TEST2.png.sha1'), + self.VALID_SHA1, ''), MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'), - 'binary', ''), + self.VALID_SHA1, ''), MockFile(os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'), - 'binary', '') + self.VALID_SHA1, '') ]) warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi()) self.assertEqual(1, len(warnings)) @@ -3722,9 +3779,10 @@ self.NEW_GRDP_CONTENTS2, # old_contents action='M'), # Unmodified files: - MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'), 'binary', ''), + MockFile(os.path.join('test_grd', 'IDS_TEST1.png.sha1'), + self.VALID_SHA1, ''), MockFile(os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'), - 'binary', ''), + self.VALID_SHA1, ''), # Deleted files: MockAffectedFile( os.path.join('test_grd', 'IDS_TEST2.png.sha1'), @@ -3761,19 +3819,19 @@ # Deleted files: MockFile( os.path.join('test_grd', 'IDS_TEST1.png.sha1'), - 'binary', + self.VALID_SHA1, action='D'), MockFile( os.path.join('test_grd', 'IDS_TEST2.png.sha1'), - 'binary', + self.VALID_SHA1, action='D'), MockFile( os.path.join('part_grdp', 'IDS_PART_TEST1.png.sha1'), - 'binary', + self.VALID_SHA1, action='D'), MockFile( os.path.join('part_grdp', 'IDS_PART_TEST2.png.sha1'), - 'binary', + self.VALID_SHA1, action='D') ]) warnings = PRESUBMIT.CheckStrings(input_api, MockOutputApi())
diff --git a/android_webview/browser/gfx/display_scheduler_webview.h b/android_webview/browser/gfx/display_scheduler_webview.h index 4248af4b..d202c0b6 100644 --- a/android_webview/browser/gfx/display_scheduler_webview.h +++ b/android_webview/browser/gfx/display_scheduler_webview.h
@@ -40,9 +40,10 @@ void DidSwapBuffers() override; void DidReceiveSwapBuffersAck() override {} void OutputSurfaceLost() override; - void ReportFrameTime( - base::TimeDelta frame_time, - base::flat_set<base::PlatformThreadId> thread_ids) override {} + void ReportFrameTime(base::TimeDelta frame_time, + base::flat_set<base::PlatformThreadId> thread_ids, + base::TimeTicks draw_start, + viz::HintSession::BoostType boost_type) override {} // DisplayDamageTrackerObserver implementation. void OnDisplayDamaged(viz::SurfaceId surface_id) override;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java index 3af176c..fe58ad7 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
@@ -517,10 +517,9 @@ AwFeatures.WEBVIEW_UMA_UPLOAD_QUALITY_OF_SERVICE_SET_TO_DEFAULT); if (AwFeatureList.isEnabled(AwFeatures.WEBVIEW_USE_METRICS_UPLOAD_SERVICE)) { - boolean waitForResults = AwFeatureList.isEnabled( + boolean isAsync = AwFeatureList.isEnabled( AndroidMetricsFeatures.ANDROID_METRICS_ASYNC_METRIC_LOGGING); - AwMetricsLogUploader uploader = - new AwMetricsLogUploader(waitForResults, useDefaultUploadQos); + AwMetricsLogUploader uploader = new AwMetricsLogUploader(isAsync, useDefaultUploadQos); // Open a connection during startup while connecting to other services such as // ComponentsProviderService and VariationSeedServer to try to avoid spinning the // nonembedded ":webview_service" twice.
diff --git a/android_webview/java/src/org/chromium/android_webview/metrics/AwMetricsLogUploader.java b/android_webview/java/src/org/chromium/android_webview/metrics/AwMetricsLogUploader.java index c52fdd33..e0b0590c 100644 --- a/android_webview/java/src/org/chromium/android_webview/metrics/AwMetricsLogUploader.java +++ b/android_webview/java/src/org/chromium/android_webview/metrics/AwMetricsLogUploader.java
@@ -15,7 +15,6 @@ import androidx.annotation.VisibleForTesting; import org.chromium.android_webview.AwBrowserProcess; -import org.chromium.android_webview.common.BadRequestRecorder; import org.chromium.android_webview.common.services.IMetricsUploadService; import org.chromium.android_webview.common.services.ServiceHelper; import org.chromium.android_webview.common.services.ServiceNames; @@ -26,12 +25,9 @@ import org.chromium.components.metrics.AndroidMetricsLogConsumer; import java.net.HttpURLConnection; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; /** * A custom WebView AndroidMetricsLogConsumer. It @@ -41,137 +37,109 @@ */ public class AwMetricsLogUploader implements AndroidMetricsLogConsumer { private static final String TAG = "AwMetricsLogUploader"; - private static final long SEND_DATA_TIMEOUT_MS = 10_000; + private static final long SERVICE_CONNECTION_TIMEOUT_MS = 10_000; - private final InitialMetricsServiceConnection mInitialConnection; - private final boolean mWaitForResults; + private final AtomicReference<MetricsLogUploaderServiceConnection> mInitialConnection; + private final boolean mIsAsync; private final boolean mUseDefaultUploadQos; /** - * @param waitForResults Whether logging should wait for a status for the platform or return - * early. + * @param isAsync Whether logging is happening on a background thread or if it is being called + * from the main thread. + * @param useDefaultUploadQos Used to experiment modifying the QOS upload rate. */ - public AwMetricsLogUploader(boolean waitForResults, boolean useDefaultUploadQos) { - mInitialConnection = new InitialMetricsServiceConnection(); - mWaitForResults = waitForResults; + public AwMetricsLogUploader(boolean isAsync, boolean useDefaultUploadQos) { + // A service connection that is used to establish an initial connection to the + // MetricsUploadService to keep it alive until the first metrics log is ready. + mInitialConnection = new AtomicReference(); + mIsAsync = isAsync; mUseDefaultUploadQos = useDefaultUploadQos; } - // A service connection that is used to establish an initial connection to the - // MetricsUploadService to keep it alive until the first metrics log is ready. Currently it does - // nothing but it can be later used to query metrics service configs like sampling state of the - // device ... etc, during startup. - private static class InitialMetricsServiceConnection implements ServiceConnection { - private final AtomicBoolean mBound = new AtomicBoolean(); - - @Override - public void onServiceConnected(ComponentName name, IBinder service) {} - - @Override - public void onServiceDisconnected(ComponentName name) {} - - public void initialize() { - boolean bindingResult = bindToMetricsUploadService(this); - mBound.set(bindingResult); - if (!bindingResult) { - Log.w(TAG, "Failed to initially bind to MetricsUploadService"); - } - } - - /** - * Unbind the service connection if it's still bound to the service, do nothing otherwise. - * - * This method is thread-safe. - */ - public void unbind() { - if (mBound.getAndSet(false)) { - ContextUtils.getApplicationContext().unbindService(this); - } - } - } - // A service connection that sends the given serialized metrics log data to // MetricsUploadService. It closes the connection after sending the metrics log. private static class MetricsLogUploaderServiceConnection implements ServiceConnection { private final boolean mUseDefaultUploadQos; - private final @NonNull byte[] mData; - private final CompletableFuture<Integer> mResult; - private final AtomicBoolean mPosted = new AtomicBoolean(); + private final LinkedBlockingQueue<IMetricsUploadService> mConnectionsQueue; public MetricsLogUploaderServiceConnection(boolean useDefaultUploadQos, - @NonNull byte[] data, @NonNull CompletableFuture<Integer> resultFuture) { + LinkedBlockingQueue<IMetricsUploadService> connectionsQueue) { mUseDefaultUploadQos = useDefaultUploadQos; - mData = data; - mResult = resultFuture; + mConnectionsQueue = connectionsQueue; + } + + public boolean bind() { + Intent intent = new Intent(); + intent.setClassName( + AwBrowserProcess.getWebViewPackageName(), ServiceNames.METRICS_UPLOAD_SERVICE); + return ServiceHelper.bindService( + ContextUtils.getApplicationContext(), intent, this, Context.BIND_AUTO_CREATE); } @Override public void onServiceConnected(ComponentName name, IBinder service) { - // We want to avoid re-posting if the service connection dies - // and reconnects. - if (mPosted.getAndSet(true)) { - return; + // If onServiceConnected is incorrectly called twice in a row without + // onServiceDisconnected, we will still try take the latest service connection for + // a hope of working. + mConnectionsQueue.clear(); + IMetricsUploadService uploadService = IMetricsUploadService.Stub.asInterface(service); + // Keep track of if the service is updated again since the last clear. + if (!mConnectionsQueue.offer(uploadService)) { + Log.d(TAG, "Attempted to re-bind with service twice."); } - // onServiceConnected is called on the app main looper so post it to a background thread - // for execution. No need to enforce the order in which the logs are sent to the service - // as this isn't required/enforced by UMA. - PostTask.postTask(TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> { - IMetricsUploadService uploadService = - IMetricsUploadService.Stub.asInterface(service); - try { - int status = uploadService.uploadMetricsLog(mData, mUseDefaultUploadQos); - mResult.complete(status); - } catch (RemoteException e) { - Log.d(TAG, "Failed to send serialized metrics data to service", e); - mResult.complete(HttpURLConnection.HTTP_INTERNAL_ERROR); - } finally { - ContextUtils.getApplicationContext().unbindService(this); - } - }); } @Override - public void onServiceDisconnected(ComponentName name) {} + public void onServiceDisconnected(ComponentName name) { + // If we get an unexpected disconnection, we should no longer trust the connection we + // have queued. + // If the metrics service already has a connection it will simply fail when trying to + // make a call. + // This should be helpful for the first connection where there is a more considerable + // delta between when we first bind, and when we try to send data. + mConnectionsQueue.clear(); + } - public int sendData(boolean waitForResults) { - bindToMetricsUploadService(this); - if (!waitForResults) { + /** + * Note: Once this method has run, it will automatically unbind the connection so this + * connection should not be used after calling this method "once". + */ + public int sendData(boolean isAsync, @NonNull byte[] data) { + // If we are on the main thread, we cannot block waiting to connect to the service so we + // need to fire and forget. In this case all we can do is report back OK. + if (!isAsync) { + PostTask.postTask( + TaskTraits.BEST_EFFORT_MAY_BLOCK, () -> { uploadToService(data); }); + return HttpURLConnection.HTTP_OK; } - // The logs could have still been sent by the service even if we haven't gotten a - // response here so our choice is to either drop the logs or allow for duplication. + + return uploadToService(data); + } + + private int uploadToService(@NonNull byte[] data) { try { - return mResult.get(SEND_DATA_TIMEOUT_MS, TimeUnit.MILLISECONDS); - } catch (CancellationException e) { - Log.e(TAG, "Request to send data cancelled", e); - // If the future was cancelled, we will treat this as a situation to retry. - return HttpURLConnection.HTTP_GONE; + IMetricsUploadService uploadService = mConnectionsQueue.poll( + SERVICE_CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); + + // Null returned from poll means we timed out + if (uploadService == null) { + Log.e(TAG, "Failed to receive response from upload service in time"); + return HttpURLConnection.HTTP_CLIENT_TIMEOUT; + } + + return uploadService.uploadMetricsLog(data, mUseDefaultUploadQos); + } catch (RemoteException e) { + Log.d(TAG, "Failed to send serialized metrics data to service", e); } catch (InterruptedException e) { Log.e(TAG, "Request to send data interrupted while waiting", e); return HttpURLConnection.HTTP_UNAVAILABLE; - } catch (ExecutionException e) { - Log.e(TAG, "Request to send data completed with exception", e); - // In this case the request hit the server so we will treat this as a discarded log. - // The Chromium metrics service will drop http 400s. - BadRequestRecorder.record(BadRequestRecorder.Reason.EXCEPTION_WAITING_FOR_SERVICE); - return HttpURLConnection.HTTP_BAD_REQUEST; - } catch (TimeoutException e) { - Log.e(TAG, "Failed to receive response from upload service in time", e); - // We decided to allow for duplication because there is quite a long time out so not - // receiving a response for this long probably means there was an issue with - // logging. This code path could also be called if the service connection has a - // failure. - return HttpURLConnection.HTTP_CLIENT_TIMEOUT; + } finally { + ContextUtils.getApplicationContext().unbindService(this); } - } - } - private static boolean bindToMetricsUploadService(ServiceConnection connection) { - Intent intent = new Intent(); - intent.setClassName( - AwBrowserProcess.getWebViewPackageName(), ServiceNames.METRICS_UPLOAD_SERVICE); - return ServiceHelper.bindService( - ContextUtils.getApplicationContext(), intent, connection, Context.BIND_AUTO_CREATE); + return HttpURLConnection.HTTP_INTERNAL_ERROR; + } } /** @@ -181,25 +149,43 @@ */ @Override public int log(@NonNull byte[] data) { - return log(data, new CompletableFuture()); + return log(data, new LinkedBlockingQueue(1)); } @VisibleForTesting - public int log(@NonNull byte[] data, @NonNull CompletableFuture<Integer> resultFuture) { - MetricsLogUploaderServiceConnection connection = - new MetricsLogUploaderServiceConnection(mUseDefaultUploadQos, data, resultFuture); - int status = connection.sendData(mWaitForResults); - // Unbind the initial connection if it's still bound, since a new connection is now bound to - // the service. - mInitialConnection.unbind(); - return status; + public int log(@NonNull byte[] data, + @NonNull LinkedBlockingQueue<IMetricsUploadService> connectionsQueue) { + MetricsLogUploaderServiceConnection connection = mInitialConnection.getAndSet(null); + + if (connection == null) { + connection = + new MetricsLogUploaderServiceConnection(mUseDefaultUploadQos, connectionsQueue); + + if (!connection.bind()) { + Log.w(TAG, "Failed to bind to MetricsUploadService"); + return HttpURLConnection.HTTP_UNAVAILABLE; + } + } + + return connection.sendData(mIsAsync, data); } /** * Initialize a connection to {@link org.chromium.android_webview.services.MetricsUploadService} * and keep it alive until the first metrics log data is sent for upload. + * + * We do this because we already pay the startup cost of the non-embedded process due to other + * webview non-embedded services running early on. + * We can hopefully save some time on initially spinning the process since we know we + * are going to attempt to upload pretty soon after starting up WebView the first time. */ public void initialize() { - mInitialConnection.initialize(); + MetricsLogUploaderServiceConnection connection = new MetricsLogUploaderServiceConnection( + mUseDefaultUploadQos, new LinkedBlockingQueue(1)); + if (connection.bind()) { + mInitialConnection.set(connection); + } else { + Log.w(TAG, "Failed to initially bind to MetricsUploadService"); + } } }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsLogUploaderTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsLogUploaderTest.java index e92917ab..a07d6924 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsLogUploaderTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwMetricsLogUploaderTest.java
@@ -19,6 +19,7 @@ import org.chromium.android_webview.AwBrowserProcess; import org.chromium.android_webview.common.PlatformServiceBridge; +import org.chromium.android_webview.common.services.IMetricsUploadService; import org.chromium.android_webview.metrics.AwMetricsLogUploader; import org.chromium.base.ContextUtils; import org.chromium.base.ThreadUtils; @@ -27,10 +28,7 @@ import java.net.HttpURLConnection; import java.util.ArrayList; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.LinkedBlockingQueue; /** * Instrumentation tests MetricsUploadService. These tests are not batched to make sure all unbinded @@ -95,38 +93,38 @@ } @Test - public void testSendingDataException_whenCancellationException() throws Throwable { - testSendingDataException(new CancellationException(), HttpURLConnection.HTTP_GONE); - } - - @Test public void testSendingDataException_whenInterruptedException() throws Throwable { testSendingDataException(new InterruptedException(), HttpURLConnection.HTTP_UNAVAILABLE); } @Test - public void testSendingDataException_whenExecutionException() throws Throwable { - testSendingDataException( - new ExecutionException("", null), HttpURLConnection.HTTP_BAD_REQUEST); - } - - @Test public void testSendingDataException_whenTimesOut() throws Throwable { - testSendingDataException(new TimeoutException(), HttpURLConnection.HTTP_CLIENT_TIMEOUT); + // When the AwMetricsLogUploader attempts to wait for log results, an exception of our + // choosing will be thrown. + final LinkedBlockingQueue<IMetricsUploadService> mockedResultsQueue = + mock(LinkedBlockingQueue.class); + when(mockedResultsQueue.poll(anyLong(), any())).thenReturn(null); + + AwMetricsLogUploader uploader = new AwMetricsLogUploader( + /* waitForResults= */ true, /* useDefaultUploadQos= */ false); + int status = uploader.log(SAMPLE_TEST_METRICS_LOG.toByteArray(), mockedResultsQueue); + + Assert.assertEquals(HttpURLConnection.HTTP_CLIENT_TIMEOUT, status); } private void testSendingDataException(Throwable exceptionThrown, int expectedStatus) throws Throwable { // When the AwMetricsLogUploader attempts to wait for log results, an exception of our // choosing will be thrown. - final CompletableFuture<Integer> mockedResultsFuture = mock(CompletableFuture.class); - when(mockedResultsFuture.get(anyLong(), any())).thenAnswer(invocation -> { + final LinkedBlockingQueue<IMetricsUploadService> mockedResultsQueue = + mock(LinkedBlockingQueue.class); + when(mockedResultsQueue.poll(anyLong(), any())).thenAnswer(invocation -> { throw exceptionThrown; }); AwMetricsLogUploader uploader = new AwMetricsLogUploader( /* waitForResults= */ true, /* useDefaultUploadQos= */ false); - int status = uploader.log(SAMPLE_TEST_METRICS_LOG.toByteArray(), mockedResultsFuture); + int status = uploader.log(SAMPLE_TEST_METRICS_LOG.toByteArray(), mockedResultsQueue); Assert.assertEquals(expectedStatus, status); }
diff --git a/android_webview/nonembedded/BUILD.gn b/android_webview/nonembedded/BUILD.gn index 06c44fd4..e82455c 100644 --- a/android_webview/nonembedded/BUILD.gn +++ b/android_webview/nonembedded/BUILD.gn
@@ -181,6 +181,7 @@ "//components/component_updater/installer_policies:installer_policies_no_content_deps", "//components/prefs", "//components/update_client", + "//components/update_client:buildflags", "//components/update_client:in_process_patcher", "//components/update_client:in_process_unzipper", "//components/version_info",
diff --git a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc index f0a64d0..0bea723 100644 --- a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc +++ b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.cc
@@ -9,6 +9,8 @@ #include <vector> #include "android_webview/nonembedded/net/network_impl.h" +#include "base/android/path_utils.h" +#include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/memory/scoped_refptr.h" #include "base/version.h" @@ -16,6 +18,7 @@ #include "components/component_updater/configurator_impl.h" #include "components/prefs/pref_service.h" #include "components/update_client/activity_data_service.h" +#include "components/update_client/buildflags.h" #include "components/update_client/crx_downloader_factory.h" #include "components/update_client/network.h" #include "components/update_client/patch/in_process_patcher.h" @@ -198,4 +201,15 @@ pref_service); } +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) +absl::optional<base::FilePath> AwComponentUpdaterConfigurator::GetCrxCachePath() + const { + base::FilePath path; + return base::android::GetCacheDirectory(&path) + ? absl::optional<base::FilePath>( + path.AppendASCII(("webview_crx_cache"))) + : absl::nullopt; +} +#endif + } // namespace android_webview
diff --git a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h index 0961d18..7df70cf 100644 --- a/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h +++ b/android_webview/nonembedded/component_updater/aw_component_updater_configurator.h
@@ -5,6 +5,7 @@ #ifndef ANDROID_WEBVIEW_NONEMBEDDED_COMPONENT_UPDATER_AW_COMPONENT_UPDATER_CONFIGURATOR_H_ #define ANDROID_WEBVIEW_NONEMBEDDED_COMPONENT_UPDATER_AW_COMPONENT_UPDATER_CONFIGURATOR_H_ +#include "base/files/file_path.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/time/time.h" @@ -12,6 +13,7 @@ #include "components/component_updater/configurator_impl.h" #include "components/prefs/pref_service.h" #include "components/update_client/activity_data_service.h" +#include "components/update_client/buildflags.h" #include "components/update_client/configurator.h" #include "components/update_client/crx_downloader_factory.h" #include "components/update_client/network.h" @@ -63,6 +65,9 @@ GetProtocolHandlerFactory() const override; absl::optional<bool> IsMachineExternallyManaged() const override; update_client::UpdaterStateProvider GetUpdaterStateProvider() const override; +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) + absl::optional<base::FilePath> GetCrxCachePath() const override; +#endif protected: friend class base::RefCountedThreadSafe<AwComponentUpdaterConfigurator>;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index d2990cd..be4721b 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -890,6 +890,8 @@ "user_education/user_education_delegate.h", "user_education/user_education_feature_controller.cc", "user_education/user_education_feature_controller.h", + "user_education/user_education_help_bubble_controller.cc", + "user_education/user_education_help_bubble_controller.h", "user_education/user_education_ping_controller.cc", "user_education/user_education_ping_controller.h", "user_education/user_education_private_api_key.h", @@ -3275,6 +3277,9 @@ "system/locale/locale_feature_pod_controller_unittest.cc", "system/lock_screen_notification_controller_unittest.cc", "system/media/media_tray_unittest.cc", + "system/media/quick_settings_media_view_container_unittest.cc", + "system/media/quick_settings_media_view_controller_unittest.cc", + "system/media/quick_settings_media_view_unittest.cc", "system/media/unified_media_controls_container_unittest.cc", "system/media/unified_media_controls_controller_unittest.cc", "system/media/unified_media_controls_detailed_view_controller_unittest.cc", @@ -3442,6 +3447,7 @@ "user_education/capture_mode_tour/capture_mode_tour_controller_unittest.cc", "user_education/holding_space_tour/holding_space_tour_controller_unittest.cc", "user_education/user_education_controller_unittest.cc", + "user_education/user_education_help_bubble_controller_unittest.cc", "user_education/user_education_ping_controller_unittest.cc", "user_education/user_education_util_unittest.cc", "user_education/welcome_tour/welcome_tour_controller_unittest.cc", @@ -3664,6 +3670,7 @@ "//components/language/core/browser:browser", "//components/live_caption:constants", "//components/media_message_center", + "//components/media_message_center:test_support", "//components/onc", "//components/password_manager/core/browser:hash_password_manager", "//components/prefs:test_support",
diff --git a/ash/ambient/ambient_controller.cc b/ash/ambient/ambient_controller.cc index 84ee8647..93d5c2e 100644 --- a/ash/ambient/ambient_controller.cc +++ b/ash/ambient/ambient_controller.cc
@@ -354,18 +354,19 @@ } void AmbientController::OnLoginOrLockScreenCreated() { - if (!LockScreen::HasInstance() || - LockScreen::Get()->screen_type() != LockScreen::ScreenType::kLogin || - !IsAmbientModeManagedScreensaverEnabled() || - ambient_ui_model_.ui_visibility() != AmbientUiVisibility::kClosed) { + if (!ambient::util::IsShowing(LockScreen::ScreenType::kLogin)) { return; } - - SetUiVisibilityHidden(); + OnLoginLockStateChanged(LockScreenState::kLogin); } void AmbientController::OnLockStateChanged(bool locked) { - if (!locked) { + OnLoginLockStateChanged(locked ? LockScreenState::kLocked + : LockScreenState::kUnlocked); +} + +void AmbientController::OnLoginLockStateChanged(LockScreenState state) { + if (state == LockScreenState::kUnlocked) { // Ambient screen will be destroyed along with the lock screen when user // logs in. SetUiVisibilityClosed(); @@ -410,6 +411,16 @@ } } +AmbientController::LockScreenState AmbientController::GetLockScreenState() { + if (!LockScreen::HasInstance()) { + return LockScreenState::kUnlocked; + } + if (ambient::util::IsShowing(LockScreen::ScreenType::kLogin)) { + return LockScreenState::kLogin; + } + return LockScreenState::kLocked; +} + void AmbientController::OnActiveUserPrefServiceChanged( PrefService* pref_service) { if (GetPrimaryUserPrefService() != pref_service) { @@ -442,18 +453,17 @@ ambient::prefs::kAmbientModeEnabled, base::BindRepeating(&AmbientController::OnEnabledPrefChanged, weak_ptr_factory_.GetWeakPtr())); - - OnEnabledPrefChanged(); } if (managed_screensaver_flag_enabled) { pref_change_registrar_->Add( ambient::prefs::kAmbientModeManagedScreensaverEnabled, - base::BindRepeating( - &AmbientController::OnManagedScreensaverEnabledPrefChanged, - weak_ptr_factory_.GetWeakPtr())); + base::BindRepeating(&AmbientController::OnEnabledPrefChanged, + weak_ptr_factory_.GetWeakPtr())); + } - OnManagedScreensaverEnabledPrefChanged(); + if (ambient_mode_allowed || managed_screensaver_flag_enabled) { + OnEnabledPrefChanged(); } } @@ -463,23 +473,17 @@ return; } - // Do not re-create the registrars if any registrar exists. This is done - // so that in case the user pref registrar already exists it takes - // priority. - if (sign_in_pref_change_registrar_ || pref_change_registrar_) { - return; - } - + CHECK(!sign_in_pref_change_registrar_); + CHECK(!pref_change_registrar_); sign_in_pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); sign_in_pref_change_registrar_->Init(pref_service); sign_in_pref_change_registrar_->Add( ambient::prefs::kAmbientModeManagedScreensaverEnabled, - base::BindRepeating( - &AmbientController::OnManagedScreensaverEnabledPrefChanged, - weak_ptr_factory_.GetWeakPtr())); + base::BindRepeating(&AmbientController::OnEnabledPrefChanged, + weak_ptr_factory_.GetWeakPtr())); - OnManagedScreensaverEnabledPrefChanged(); + OnEnabledPrefChanged(); } void AmbientController::OnPowerStatusChanged() { @@ -887,24 +891,7 @@ kAmbientModeManagedScreensaverImageDisplayIntervalSeconds))); } -void AmbientController::OnManagedScreensaverEnabledPrefChanged() { - ResetAmbientControllerResources(); - OnEnabledPrefChanged(); - - if (!IsAmbientModeManagedScreensaverEnabled()) { - return; - } - RemoveAmbientModeSettingsPrefObservers(); - AddManagedScreensaverPolicyPrefObservers(); - if (!LockScreen::HasInstance()) { - return; - } - // Start hidden ambient mode immediately if the lock screen has an instance - // and ambient mode is enabled. - SetUiVisibilityHidden(); -} - -void AmbientController::AddAmbientModeUserSettingsPolicyPrefObservers() { +void AmbientController::AddConsumerPrefObservers() { // Note: in case we ever want to enable the consumer screensaver on the // login screen we should change the pref_change_registrar here with // `GetActivePrefChangeRegistrar()` and the corresponding @@ -949,40 +936,67 @@ } void AmbientController::OnEnabledPrefChanged() { - if (IsAmbientModeEnabled()) { - if (is_initialized_) { - LOG(WARNING) << "Ambient mode is already enabled"; - return; - } - DVLOG(1) << "Ambient mode enabled"; - - AddAmbientModeUserSettingsPolicyPrefObservers(); - - photo_cache_ = AmbientPhotoCache::Create( - GetCacheRootPath().Append( - FILE_PATH_LITERAL(kAmbientModeCacheDirectoryName)), - *AmbientClient::Get(), access_token_controller_); - backup_photo_cache_ = AmbientPhotoCache::Create( - GetCacheRootPath().Append( - FILE_PATH_LITERAL(kAmbientModeBackupCacheDirectoryName)), - *AmbientClient::Get(), access_token_controller_); - CreateUiLauncher(); - - ambient_ui_model_observer_.Observe(&ambient_ui_model_); - auto* power_manager_client = chromeos::PowerManagerClient::Get(); - DCHECK(power_manager_client); - power_manager_client_observer_.Observe(power_manager_client); - - fingerprint_->AddFingerprintObserver( - fingerprint_observer_receiver_.BindNewPipeAndPassRemote()); - - ambient_animation_progress_tracker_ = - std::make_unique<AmbientAnimationProgressTracker>(); - - is_initialized_ = true; - } else { + if (!IsAmbientModeEnabled()) { DVLOG(1) << "Ambient mode disabled"; ResetAmbientControllerResources(); + return; + } + + DVLOG(1) << "Ambient mode enabled"; + + // A second initialization can happen in the following cases: + // 1) Ambient mode is enabled for the login screen via device policy on a + // managed device (first initialization), A consumer user with an email with + // @gmail.com logins into the device and has ambient mode enabled (Second + // initialization). + // + // 2) Ambient mode is enabled for the login screen via device policy on a + // managed device (first initialization), A managed user logins into the + // device and the managed screensaver is enabled via user policy. (Second + // initialization). + + if (is_initialized_) { + // In case the mode is initialized we reset and start from a clean slate so + // that we do not double allocate everything and always listen to the + // correct prefs. + // Note: We do not early return here as multiple calls to this method are + // valid and depending upon the type of ambient mode being enabled we have + // to do different things. + ResetAmbientControllerResources(); + } + is_initialized_ = true; + + if (IsAmbientModeManagedScreensaverEnabled()) { + AddManagedScreensaverPolicyPrefObservers(); + } else { + AddConsumerPrefObservers(); + } + + photo_cache_ = AmbientPhotoCache::Create( + GetCacheRootPath().Append( + FILE_PATH_LITERAL(kAmbientModeCacheDirectoryName)), + *AmbientClient::Get(), access_token_controller_); + backup_photo_cache_ = AmbientPhotoCache::Create( + GetCacheRootPath().Append( + FILE_PATH_LITERAL(kAmbientModeBackupCacheDirectoryName)), + *AmbientClient::Get(), access_token_controller_); + CreateUiLauncher(); + + ambient_ui_model_observer_.Observe(&ambient_ui_model_); + auto* power_manager_client = chromeos::PowerManagerClient::Get(); + DCHECK(power_manager_client); + power_manager_client_observer_.Observe(power_manager_client); + + fingerprint_->AddFingerprintObserver( + fingerprint_observer_receiver_.BindNewPipeAndPassRemote()); + + ambient_animation_progress_tracker_ = + std::make_unique<AmbientAnimationProgressTracker>(); + + // The policy update can happen on the login screen as well so we need to + // trigger the state change to start the ambient mode if required. + if (IsAmbientModeManagedScreensaverEnabled()) { + OnLoginLockStateChanged(GetLockScreenState()); } }
diff --git a/ash/ambient/ambient_controller.h b/ash/ambient/ambient_controller.h index 76969fac..66500134 100644 --- a/ash/ambient/ambient_controller.h +++ b/ash/ambient/ambient_controller.h
@@ -127,9 +127,7 @@ void OnInteractionStateChanged(InteractionState interaction_state) override; // Invoked by the `LockScreen` to notify ambient mode that either the login or - // lock screen has been created. Note: This should only be used for reacting - // to login screen creation. For LockScreen lock/unlock we should keep relying - // on `OnLockStateChanged` method. + // lock screen has been created. void OnLoginOrLockScreenCreated(); // Set the ui state to begin showing ambient mode. After calling this @@ -199,6 +197,10 @@ } private: + // Enum to indicate which state the lock screen is in. This is used + // by `OnLoginLockScreenStateChanged` method as a parameter to pass + // the correct information to the method. + enum LockScreenState { kLogin, kLocked, kUnlocked }; friend class AmbientAshTestBase; friend class AmbientControllerTest; FRIEND_TEST_ALL_PREFIXES(AmbientControllerTest, @@ -252,9 +254,9 @@ // Removes any and all ambient mode ui model related settings pref observers void RemoveAmbientModeSettingsPrefObservers(); - // Adds/Removes managed pref observers + // Adds/Removes pref observers void AddManagedScreensaverPolicyPrefObservers(); - void AddAmbientModeUserSettingsPolicyPrefObservers(); + void AddConsumerPrefObservers(); // Invoked when the Ambient mode prefs state changes. void OnEnabledPrefChanged(); @@ -268,7 +270,6 @@ void ResetAmbientControllerResources(); // Invoked when preferences change via policy updates. - void OnManagedScreensaverEnabledPrefChanged(); void OnManagedScreensaverLockScreenIdleTimeoutPrefChanged(); void OnManagedScreensaverPhotoRefreshIntervalPrefChanged(); @@ -277,6 +278,10 @@ bool IsUiLauncherActive() const; void OnUiLauncherInitialized(bool success); + void OnLoginLockStateChanged(LockScreenState state); + + LockScreenState GetLockScreenState(); + // Returns the active pref change registrar. Note: The registar for user // profile `pref_change_registrar_` will always be the active pref change // registrar when the user is logged in, when the user is not logged in @@ -359,7 +364,7 @@ // TODO(safarli): Remove this workaround when b/266234711 is fixed. bool last_mouse_event_was_move_ = false; - // Flag used to prevent multiple calls to OnEnabledPrefChanged initializing + // Flag used to handle calls to OnEnabledPrefChanged initializing // the controller. bool is_initialized_ = false;
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc index 002fcc5..6f59a09 100644 --- a/ash/app_list/views/app_list_item_view.cc +++ b/ash/app_list/views/app_list_item_view.cc
@@ -73,6 +73,7 @@ #include "ui/views/controls/label.h" #include "ui/views/controls/menu/menu_runner.h" #include "ui/views/focus/focus_manager.h" +#include "ui/views/view_utils.h" #include "ui/views/widget/widget.h" namespace ash { @@ -508,23 +509,26 @@ focus_ring->SetColorId(is_jelly_enabled ? static_cast<ui::ColorId>( cros_tokens::kCrosSysFocusRing) : ui::kColorAshFocusRing); - focus_ring->SetHasFocusPredicate([&](View* view) -> bool { + focus_ring->SetHasFocusPredicate(base::BindRepeating([](const View* view) { + const auto* v = views::AsViewClass<AppListItemView>(view); + CHECK(v); + // With a `view_delegate_` present, focus ring should only show when // button is focused and keyboard traversal is engaged. - if (view_delegate_ && !view_delegate_->KeyboardTraversalEngaged()) { + if (v->view_delegate_ && !v->view_delegate_->KeyboardTraversalEngaged()) { return false; } - if (drag_state_ != DragState::kNone) { + if (v->drag_state_ != DragState::kNone) { return false; } - if (waiting_for_context_menu_options_ || IsShowingAppMenu()) { + if (v->waiting_for_context_menu_options_ || v->IsShowingAppMenu()) { return false; } - return view->HasFocus(); - }); + return v->HasFocus(); + })); views::InstallRoundRectHighlightPathGenerator( this, gfx::Insets(1), app_list_config_->grid_focus_corner_radius());
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h index 97f2626..770ac36 100644 --- a/ash/app_list/views/app_list_item_view.h +++ b/ash/app_list/views/app_list_item_view.h
@@ -16,6 +16,7 @@ #include "base/memory/raw_ptr.h" #include "base/timer/timer.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/views/context_menu_controller.h" #include "ui/views/controls/button/button.h"
diff --git a/ash/app_list/views/app_list_toast_view.cc b/ash/app_list/views/app_list_toast_view.cc index 6d55e76..51025c3 100644 --- a/ash/app_list/views/app_list_toast_view.cc +++ b/ash/app_list/views/app_list_toast_view.cc
@@ -19,6 +19,7 @@ #include "ash/style/typography.h" #include "chromeos/constants/chromeos_features.h" #include "components/vector_icons/vector_icons.h" +#include "ui/base/metadata/metadata_impl_macros.h" #include "ui/chromeos/styles/cros_tokens_color_mappings.h" #include "ui/color/color_id.h" #include "ui/compositor/layer.h" @@ -364,14 +365,16 @@ Type type, const gfx::VectorIcon* icon) : PillButton(callback, text, type, icon), view_delegate_(view_delegate) { - views::FocusRing::Get(this)->SetHasFocusPredicate([&](View* view) -> bool { - // With a `view_delegate_` present, focus ring should only show when - // button is focused and keyboard traversal is engaged. - if (view_delegate_ && !view_delegate_->KeyboardTraversalEngaged()) - return false; - - return view->HasFocus(); - }); + views::FocusRing::Get(this)->SetHasFocusPredicate( + base::BindRepeating([](const View* view) { + const auto* v = views::AsViewClass<ToastPillButton>(view); + CHECK(v); + // With a `view_delegate_` present, focus ring should only show when + // button is focused and keyboard traversal is engaged. + return (!v->view_delegate_ || + v->view_delegate_->KeyboardTraversalEngaged()) && + v->HasFocus(); + })); } void AppListToastView::ToastPillButton::OnFocus() { @@ -384,6 +387,9 @@ views::FocusRing::Get(this)->SchedulePaint(); } +BEGIN_METADATA(AppListToastView, ToastPillButton, PillButton) +END_METADATA + void AppListToastView::UpdateIconImage() { if (!icon_) return;
diff --git a/ash/app_list/views/app_list_toast_view.h b/ash/app_list/views/app_list_toast_view.h index cdad7c6..fa683c3 100644 --- a/ash/app_list/views/app_list_toast_view.h +++ b/ash/app_list/views/app_list_toast_view.h
@@ -10,6 +10,7 @@ #include "ash/ash_export.h" #include "ash/style/pill_button.h" #include "base/memory/raw_ptr.h" +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/controls/button/button.h" #include "ui/views/view.h" @@ -127,6 +128,8 @@ private: class ToastPillButton : public PillButton { public: + METADATA_HEADER(ToastPillButton); + ToastPillButton(AppListViewDelegate* view_delegate, PressedCallback callback, const std::u16string& text,
diff --git a/ash/app_list/views/search_result_actions_view.cc b/ash/app_list/views/search_result_actions_view.cc index ca55368..13cdcdb 100644 --- a/ash/app_list/views/search_result_actions_view.cc +++ b/ash/app_list/views/search_result_actions_view.cc
@@ -20,6 +20,8 @@ #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/base/metadata/metadata_header_macros.h" +#include "ui/base/metadata/metadata_impl_macros.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/insets.h" @@ -32,6 +34,7 @@ #include "ui/views/controls/button/md_text_button.h" #include "ui/views/controls/highlight_path_generator.h" #include "ui/views/layout/box_layout.h" +#include "ui/views/view_utils.h" namespace ash { @@ -44,6 +47,8 @@ // SearchResultActionButton renders the button defined by SearchResult::Action. class SearchResultActionButton : public IconButton { public: + METADATA_HEADER(SearchResultActionButton); + SearchResultActionButton(SearchResultActionsView* parent, const SearchResult::Action& action, PressedCallback callback, @@ -65,7 +70,6 @@ private: int GetButtonRadius() const; - const char* GetClassName() const override; raw_ptr<SearchResultActionsView, ExperimentalAsh> parent_; bool to_be_activate_by_long_press_ = false; @@ -89,9 +93,12 @@ SetVisible(false); StyleUtil::SetUpFocusRingForView(this); - views::FocusRing::Get(this)->SetHasFocusPredicate([&](View* view) -> bool { - return view->HasFocus() || parent_->GetSelectedAction() == tag(); - }); + views::FocusRing::Get(this)->SetHasFocusPredicate( + base::BindRepeating([](const View* view) { + const auto* v = views::AsViewClass<SearchResultActionButton>(view); + CHECK(v); + return v->HasFocus() || v->parent_->GetSelectedAction() == v->tag(); + })); } void SearchResultActionButton::OnGestureEvent(ui::GestureEvent* event) { @@ -126,9 +133,8 @@ return width() / 2; } -const char* SearchResultActionButton::GetClassName() const { - return "SearchResultActionButton"; -} +BEGIN_METADATA(SearchResultActionButton, IconButton) +END_METADATA SearchResultActionsView::SearchResultActionsView( SearchResultActionsViewDelegate* delegate) @@ -170,10 +176,6 @@ static_cast<SearchResultActionButton*>(child)->UpdateOnStateChanged(); } -const char* SearchResultActionsView::GetClassName() const { - return "SearchResultActionsView"; -} - bool SearchResultActionsView::SelectInitialAction(bool reverse_tab_order) { if (GetActionCount() == 0) return false; @@ -269,4 +271,7 @@ PreferredSizeChanged(); } +BEGIN_METADATA(SearchResultActionsView, views::View) +END_METADATA + } // namespace ash
diff --git a/ash/app_list/views/search_result_actions_view.h b/ash/app_list/views/search_result_actions_view.h index b367744..91ff3df 100644 --- a/ash/app_list/views/search_result_actions_view.h +++ b/ash/app_list/views/search_result_actions_view.h
@@ -10,6 +10,7 @@ #include "ash/app_list/model/search/search_result.h" #include "ash/ash_export.h" #include "base/memory/raw_ptr.h" +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/view.h" namespace ash { @@ -21,6 +22,8 @@ // strip. Each action is presented as a button and horizontally laid out. class ASH_EXPORT SearchResultActionsView : public views::View { public: + METADATA_HEADER(SearchResultActionsView); + explicit SearchResultActionsView(SearchResultActionsViewDelegate* delegate); SearchResultActionsView(const SearchResultActionsView&) = delete; @@ -40,9 +43,6 @@ // Updates the button UI upon the SearchResultView's UI state change. void UpdateButtonsOnStateChanged(); - // views::View: - const char* GetClassName() const override; - // Selects the result action expected to be initially selected when the parent // result view gets selected. // |reverse_tab_order| - Whether the parent result view was selected in
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 258a164..f485905 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -3145,28 +3145,28 @@ Cellular: <ph name="ADDRESS">$1<ex>01:23:45:67:89:AB</ex></ph> </message> <message name="IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_INSTALLING_PROFILE" desc="Tooltip message for disabled add cellular button, indicating cellular network profile is being installed."> - Adding profile. Wait a few minutes. + Adding profile. This may take a few minutes. </message> <message name="IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REMOVING_PROFILE" desc="Tooltip message for disabled add cellular button, indicating cellular network profile is being removed."> - Removing profile. Wait a few minutes. + Removing profile. This may take a few minutes. </message> <message name="IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RENAMING_PROFILE" desc="Tooltip message for disabled add cellular button, indicating cellular network profile is being renamed."> - Renaming profile. Wait a few minutes. + Renaming profile. This may take a few minutes. </message> <message name="IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_CONNECTING_TO_PROFILE" desc="Tooltip message for disabled add cellular button, indicating cellular network profile is being connected to."> - Connecting to profile. Wait a few minutes. + Connecting to profile. This may take a few minutes. </message> <message name="IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REFRESHING_PROFILE_LIST" desc="Tooltip message for disabled add cellular button, indicating cellular network profile list is being refreshed."> - Refreshing profile list. Wait a few minutes. + Refreshing profile list. This may take a few minutes. </message> <message name="IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RESETTING_ESIM" desc="Tooltip message for disabled add cellular button, indicating cellular eSIM is being reset."> - Your administrator is resetting your eSIM. Wait a few minutes. + Your administrator is resetting your eSIM. This may take a few minutes. </message> <message name="IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_DISABLING_PROFILE" desc="Tooltip message for disabled add cellular button, indicating cellular network profile is being disabled."> - Disabling profile. Wait a few minutes. + Disabling profile. This may take a few minutes. </message> - <message name="IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REQUESTING_AVAILABLE_PROFILES" desc="Tooltip message for disabled add cellular button, indicating cellular device is requesting profiles available to install."> - Requesting available profiles. Wait a few minutes. + <message name="IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REQUESTING_AVAILABLE_PROFILES" desc="Tooltip message for disabled add cellular button, indicating cellular device is looking for profiles available to install."> + Looking for available profiles. This may take a few minutes. </message> <message name="IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR" desc="Message for the status area when initializing the cellular device."> Initializing...
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_CONNECTING_TO_PROFILE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_CONNECTING_TO_PROFILE.png.sha1 index b11355725..6446ef37 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_CONNECTING_TO_PROFILE.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_CONNECTING_TO_PROFILE.png.sha1
@@ -1 +1 @@ -6e59747f55ae8454b4c81857273215358c4fc3cf \ No newline at end of file +3c7bbd0d91e9428674f5441dc5c7b7b0a4786cdb \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_DISABLING_PROFILE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_DISABLING_PROFILE.png.sha1 index 556186ca..78fcc78a 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_DISABLING_PROFILE.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_DISABLING_PROFILE.png.sha1
@@ -1 +1 @@ -3bf5653c8ba9ba22dea8b30f1b45ebc23c340ee7 \ No newline at end of file +3cc2a0e593f9e7256ae0a8b15098d39181b7ee5e \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_INSTALLING_PROFILE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_INSTALLING_PROFILE.png.sha1 index c2f1765..d75a3b0f 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_INSTALLING_PROFILE.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_INSTALLING_PROFILE.png.sha1
@@ -1 +1 @@ -564d54f2f331947a8d60034ff0d169de75cf48cc \ No newline at end of file +f8aa447375560c07d9352abcdf10f27139c28d71 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REFRESHING_PROFILE_LIST.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REFRESHING_PROFILE_LIST.png.sha1 index dfacbd7..7b49b1af 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REFRESHING_PROFILE_LIST.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REFRESHING_PROFILE_LIST.png.sha1
@@ -1 +1 @@ -92d86eaad388669114e51719349517169907b448 \ No newline at end of file +b401958a680ed8024016f3c317fcc4392a3e8df9 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REMOVING_PROFILE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REMOVING_PROFILE.png.sha1 index d9a67f6..6d8232b0 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REMOVING_PROFILE.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REMOVING_PROFILE.png.sha1
@@ -1 +1 @@ -ed916e7a1a16dda2311bc9ff38c690ebb4ecf09b \ No newline at end of file +cdfbf33303109659d6039840c6b091ad28096d88 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RENAMING_PROFILE.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RENAMING_PROFILE.png.sha1 index bec5166..5b1ec9783 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RENAMING_PROFILE.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RENAMING_PROFILE.png.sha1
@@ -1 +1 @@ -65afd25f15e4702e832bd14de3a58c11788bd727 \ No newline at end of file +6d30712435f038ee2275a730fb53005ed864b630 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REQUESTING_AVAILABLE_PROFILES.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REQUESTING_AVAILABLE_PROFILES.png.sha1 index 8419e16..490098a 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REQUESTING_AVAILABLE_PROFILES.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_REQUESTING_AVAILABLE_PROFILES.png.sha1
@@ -1 +1 @@ -e08824203009078607bbb979c88d581302fe1b9d \ No newline at end of file +538c214cd46fe6ad3156677f25d568e0f708b063 \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RESETTING_ESIM.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RESETTING_ESIM.png.sha1 index 08109ac..3517373 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RESETTING_ESIM.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_TRAY_INHIBITED_CELLULAR_RESETTING_ESIM.png.sha1
@@ -1 +1 @@ -91b4974e3245ed9398e7ba3e7a258c8c9864ec99 \ No newline at end of file +23a400bafd7d74b21663dc44f92347044f97921c \ No newline at end of file
diff --git a/ash/capture_mode/capture_mode_session_focus_cycler.cc b/ash/capture_mode/capture_mode_session_focus_cycler.cc index 1fb2bb2..5dd7435 100644 --- a/ash/capture_mode/capture_mode_session_focus_cycler.cc +++ b/ash/capture_mode/capture_mode_session_focus_cycler.cc
@@ -280,8 +280,11 @@ : StyleUtil::SetUpFocusRingForView(view); // Use a custom focus predicate as the default one checks if |view| actually // has focus which won't be happening since our widgets are not activatable. - focus_ring_->SetHasFocusPredicate( - [&](views::View* view) { return view->GetVisible() && has_focus_; }); + focus_ring_->SetHasFocusPredicate(base::BindRepeating( + [](const HighlightableView* highlightable, const views::View* view) { + return view->GetVisible() && highlightable->has_focus_; + }, + base::Unretained(this))); } if (needs_highlight_path_) {
diff --git a/ash/capture_mode/capture_mode_test_util.cc b/ash/capture_mode/capture_mode_test_util.cc index c8ceb63e..0b2bfb096 100644 --- a/ash/capture_mode/capture_mode_test_util.cc +++ b/ash/capture_mode/capture_mode_test_util.cc
@@ -23,6 +23,7 @@ #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/files/safe_base_name.h" #include "base/location.h" #include "base/memory/ref_counted_memory.h" #include "base/ranges/algorithm.h" @@ -329,7 +330,8 @@ EXPECT_FALSE(projector_session->is_active()); auto* projector_controller = ProjectorController::Get(); EXPECT_CALL(projector_client_, MinimizeProjectorApp()); - projector_controller->StartProjectorSession("projector_data"); + projector_controller->StartProjectorSession( + base::SafeBaseName::Create("projector_data").value()); EXPECT_TRUE(projector_session->is_active()); auto* controller = CaptureModeController::Get(); EXPECT_EQ(controller->source(), CaptureModeSource::kFullscreen);
diff --git a/ash/capture_mode/capture_mode_unittests.cc b/ash/capture_mode/capture_mode_unittests.cc index 695f8a2a..5552afe 100644 --- a/ash/capture_mode/capture_mode_unittests.cc +++ b/ash/capture_mode/capture_mode_unittests.cc
@@ -64,6 +64,7 @@ #include "base/containers/contains.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/files/safe_base_name.h" #include "base/functional/bind.h" #include "base/functional/callback_forward.h" #include "base/functional/callback_helpers.h" @@ -5465,7 +5466,8 @@ auto* test_delegate = static_cast<TestCaptureModeDelegate*>(controller->delegate_for_testing()); test_delegate->set_is_allowed_by_policy(false); - ProjectorController::Get()->StartProjectorSession("projector_data"); + ProjectorController::Get()->StartProjectorSession( + base::SafeBaseName::Create("projector_data").value()); // Both sessions will never start. EXPECT_FALSE(controller->IsActive());
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index f077e35..a039177 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -1856,7 +1856,7 @@ "ProjectorUseApiKeyForTranslation", base::FEATURE_ENABLED_BY_DEFAULT); -// Enable or disable quick settings revamped view. +// Enable or disable quick settings revamped view (go/qsrevamp). BASE_FEATURE(kQsRevamp, "QsRevamp", base::FEATURE_DISABLED_BY_DEFAULT); // Controls whether the Projector Viewer supports the user experience for
diff --git a/ash/projector/model/projector_session_impl.cc b/ash/projector/model/projector_session_impl.cc index 1fc50762..adb3354b 100644 --- a/ash/projector/model/projector_session_impl.cc +++ b/ash/projector/model/projector_session_impl.cc
@@ -5,6 +5,7 @@ #include "ash/projector/model/projector_session_impl.h" #include "ash/projector/projector_metrics.h" +#include "base/files/safe_base_name.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" @@ -32,7 +33,7 @@ ProjectorSessionImpl::~ProjectorSessionImpl() = default; -void ProjectorSessionImpl::Start(const std::string& storage_dir) { +void ProjectorSessionImpl::Start(const base::SafeBaseName& storage_dir) { DCHECK(!active_); active_ = true;
diff --git a/ash/projector/model/projector_session_impl.h b/ash/projector/model/projector_session_impl.h index 2a4d600..9abc5fc 100644 --- a/ash/projector/model/projector_session_impl.h +++ b/ash/projector/model/projector_session_impl.h
@@ -10,6 +10,7 @@ #include "ash/ash_export.h" #include "ash/public/cpp/projector/projector_session.h" #include "base/files/file_path.h" +#include "base/files/safe_base_name.h" #include "base/observer_list.h" #include "base/observer_list_types.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -23,7 +24,7 @@ ProjectorSessionImpl& operator=(const ProjectorSessionImpl&) = delete; ~ProjectorSessionImpl() override; - const std::string& storage_dir() const { return storage_dir_; } + const base::SafeBaseName& storage_dir() const { return storage_dir_; } void set_screencast_container_path( const base::FilePath& screencast_container_path) { screencast_container_path_ = screencast_container_path; @@ -35,7 +36,7 @@ // Start a projector session. `storage_dir` is the container directory name // for screencasts and will be used to create the storage path. - void Start(const std::string& storage_dir); + void Start(const base::SafeBaseName& storage_dir); void Stop(); void AddObserver(ProjectorSessionObserver* observer) override; @@ -48,7 +49,7 @@ private: void NotifySessionActiveStateChanged(bool active); - std::string storage_dir_; + base::SafeBaseName storage_dir_; // The file path of the screencast container. Only contains value after // recording is started and the container directory is created. Value will be
diff --git a/ash/projector/model/projector_session_impl_unittest.cc b/ash/projector/model/projector_session_impl_unittest.cc index e909f81..3ecf763 100644 --- a/ash/projector/model/projector_session_impl_unittest.cc +++ b/ash/projector/model/projector_session_impl_unittest.cc
@@ -51,12 +51,12 @@ EXPECT_TRUE(base::Time::FromString("2 Jan 2021 20:02:10", &start_time)); base::TimeDelta forward_by = start_time - base::Time::Now(); task_environment()->AdvanceClock(forward_by); - session_->Start("projector_data"); + session_->Start(base::SafeBaseName::Create("projector_data").value()); histogram_tester.ExpectUniqueSample(kProjectorCreationFlowHistogramName, ProjectorCreationFlow::kSessionStarted, /*count=*/1); EXPECT_TRUE(session_->is_active()); - EXPECT_EQ("projector_data", session_->storage_dir()); + EXPECT_EQ("projector_data", session_->storage_dir().path().MaybeAsASCII()); EXPECT_EQ("Screencast 2021-01-02 20.02.10", session_->screencast_name()); session_->Stop(); @@ -70,8 +70,10 @@ #if DCHECK_IS_ON() TEST_F(ProjectorSessionImplTest, OnlyOneProjectorSessionAllowed) { - session_->Start("projector_data"); - EXPECT_DEATH_IF_SUPPORTED(session_->Start("projector_data"), ""); + session_->Start(base::SafeBaseName::Create("projector_data").value()); + EXPECT_DEATH_IF_SUPPORTED( + session_->Start(base::SafeBaseName::Create("projector_data").value()), + ""); } #endif
diff --git a/ash/projector/projector_controller_impl.cc b/ash/projector/projector_controller_impl.cc index f418116..57e96ed 100644 --- a/ash/projector/projector_controller_impl.cc +++ b/ash/projector/projector_controller_impl.cc
@@ -23,6 +23,7 @@ #include "base/check.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/files/safe_base_name.h" #include "base/functional/bind.h" #include "base/memory/ref_counted_memory.h" #include "base/scoped_multi_source_observation.h" @@ -180,7 +181,7 @@ } void ProjectorControllerImpl::StartProjectorSession( - const std::string& storage_dir) { + const base::SafeBaseName& storage_dir) { DCHECK_EQ(GetNewScreencastPrecondition().state, NewScreencastPreconditionState::kEnabled);
diff --git a/ash/projector/projector_controller_impl.h b/ash/projector/projector_controller_impl.h index e4b1abb..0d564740 100644 --- a/ash/projector/projector_controller_impl.h +++ b/ash/projector/projector_controller_impl.h
@@ -12,6 +12,7 @@ #include "ash/capture_mode/capture_mode_observer.h" #include "ash/projector/model/projector_session_impl.h" #include "ash/public/cpp/projector/projector_controller.h" +#include "base/files/safe_base_name.h" #include "base/memory/raw_ptr.h" #include "base/timer/timer.h" #include "chromeos/ash/components/audio/cras_audio_handler.h" @@ -70,7 +71,7 @@ static void RegisterProfilePrefs(PrefRegistrySimple* registry); // ProjectorController: - void StartProjectorSession(const std::string& storage_dir) override; + void StartProjectorSession(const base::SafeBaseName& storage_dir) override; void SetClient(ProjectorClient* client) override; void OnSpeechRecognitionAvailabilityChanged() override; void OnTranscription(const media::SpeechRecognitionResult& result) override;
diff --git a/ash/projector/projector_controller_unittest.cc b/ash/projector/projector_controller_unittest.cc index 178d7e9..4b2c3f9 100644 --- a/ash/projector/projector_controller_unittest.cc +++ b/ash/projector/projector_controller_unittest.cc
@@ -25,6 +25,7 @@ #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/files/safe_base_name.h" #include "base/files/scoped_temp_dir.h" #include "base/functional/bind.h" #include "base/functional/callback_forward.h" @@ -311,7 +312,8 @@ auto* root = Shell::GetPrimaryRootWindow(); EXPECT_CALL(*mock_ui_controller_, ShowAnnotationTray(root)).Times(1); - controller_->projector_session()->Start("projector_data"); + controller_->projector_session()->Start( + base::SafeBaseName::Create("projector_data").value()); histogram_tester_.ExpectUniqueSample( kProjectorCreationFlowHistogramName, /*sample=*/ProjectorCreationFlow::kSessionStarted, @@ -338,7 +340,8 @@ NewScreencastPreconditionState::kDisabled, {NewScreencastPreconditionReason::kInProjectorSession}))); - controller_->projector_session()->Start("projector_data"); + controller_->projector_session()->Start( + base::SafeBaseName::Create("projector_data").value()); histogram_tester_.ExpectUniqueSample( kProjectorCreationFlowHistogramName, /*sample=*/ProjectorCreationFlow::kSessionStarted, @@ -441,7 +444,8 @@ base::TimeDelta forward_by = start_time - base::Time::Now(); task_environment()->AdvanceClock(forward_by); - controller_->projector_session()->Start("projector_data"); + controller_->projector_session()->Start( + base::SafeBaseName::Create("projector_data").value()); histogram_tester_.ExpectUniqueSample( kProjectorCreationFlowHistogramName, /*sample=*/ProjectorCreationFlow::kSessionStarted, @@ -625,7 +629,8 @@ // The screencast name, which is used to form the screencast folder/files // paths, is generated on projector session starts auto* projector_session = controller_->projector_session(); - projector_session->Start("projector_data"); + projector_session->Start( + base::SafeBaseName::Create("projector_data").value()); const base::FilePath expect_container_path = mounted_path.Append("root") .Append(projector_session->storage_dir()) @@ -689,7 +694,8 @@ availability.use_on_device ? kSpeechRecognitionEndStateOnDevice : kSpeechRecognitionEndStateServerBased; auto* projector_session = controller_->projector_session(); - projector_session->Start("projector_data"); + projector_session->Start( + base::SafeBaseName::Create("projector_data").value()); auto* root = Shell::GetPrimaryRootWindow();
diff --git a/ash/public/cpp/login_accelerators.cc b/ash/public/cpp/login_accelerators.cc index 9d6e42f2..af8004d 100644 --- a/ash/public/cpp/login_accelerators.cc +++ b/ash/public/cpp/login_accelerators.cc
@@ -66,6 +66,10 @@ kLaunchDiagnostics, ui::VKEY_ESCAPE, ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN, true, kScopeOobe | kScopeLogin, + }, { + kEnableQuickStart, + ui::VKEY_Q, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN, + false, kScopeOobe, }, }; // clang-format on
diff --git a/ash/public/cpp/login_accelerators.h b/ash/public/cpp/login_accelerators.h index edb57b57..0502018 100644 --- a/ash/public/cpp/login_accelerators.h +++ b/ash/public/cpp/login_accelerators.h
@@ -7,8 +7,6 @@ #include <stddef.h> -#include <string> - #include "ash/public/cpp/ash_public_export.h" #include "ui/events/event_constants.h" #include "ui/events/keycodes/keyboard_codes.h" @@ -42,6 +40,7 @@ kDeviceRequisitionRemora, kStartDemoMode, kLaunchDiagnostics, + kEnableQuickStart, }; struct LoginAcceleratorData {
diff --git a/ash/public/cpp/projector/projector_controller.h b/ash/public/cpp/projector/projector_controller.h index 81e47c1..16e763dc 100644 --- a/ash/public/cpp/projector/projector_controller.h +++ b/ash/public/cpp/projector/projector_controller.h
@@ -6,6 +6,7 @@ #define ASH_PUBLIC_CPP_PROJECTOR_PROJECTOR_CONTROLLER_H_ #include "ash/public/cpp/ash_public_export.h" +#include "base/files/safe_base_name.h" #include "base/time/time.h" #include "media/mojo/mojom/speech_recognition.mojom.h" @@ -32,7 +33,7 @@ // Starts a capture mode session for the projector workflow if no video // recording is currently in progress. `storage_dir` is the container // directory name for screencasts and will be used to create the storage path. - virtual void StartProjectorSession(const std::string& storage_dir) = 0; + virtual void StartProjectorSession(const base::SafeBaseName& storage_dir) = 0; // Make sure the client is set before attempting to use to the // ProjectorController.
diff --git a/ash/public/cpp/test/mock_projector_controller.h b/ash/public/cpp/test/mock_projector_controller.h index a17b694a..229e988 100644 --- a/ash/public/cpp/test/mock_projector_controller.h +++ b/ash/public/cpp/test/mock_projector_controller.h
@@ -19,7 +19,8 @@ ~MockProjectorController() override; // ProjectorController: - MOCK_METHOD1(StartProjectorSession, void(const std::string& storageDir)); + MOCK_METHOD1(StartProjectorSession, + void(const base::SafeBaseName& storageDir)); MOCK_METHOD1(SetClient, void(ash::ProjectorClient* client)); MOCK_METHOD0(OnSpeechRecognitionAvailabilityChanged, void()); MOCK_METHOD1(OnTranscription,
diff --git a/ash/style/system_textfield.cc b/ash/style/system_textfield.cc index f8eea49..b1b62b90 100644 --- a/ash/style/system_textfield.cc +++ b/ash/style/system_textfield.cc
@@ -86,8 +86,11 @@ const float halo_thickness = focus_ring->GetHaloThickness(); focus_ring->SetHaloInset(-kFocusRingGap - 0.5f * halo_thickness); focus_ring->SetColorId(cros_tokens::kCrosSysFocusRing); - focus_ring->SetHasFocusPredicate( - [&](views::View* view) -> bool { return show_focus_ring_; }); + focus_ring->SetHasFocusPredicate(base::BindRepeating( + [](const SystemTextfield* textfield, const views::View* view) { + return textfield->show_focus_ring_; + }, + base::Unretained(this))); enabled_changed_subscription_ = AddEnabledChangedCallback(base::BindRepeating( &SystemTextfield::OnEnabledStateChanged, base::Unretained(this)));
diff --git a/ash/style/system_toast_style.cc b/ash/style/system_toast_style.cc index f2676a5..e00d3b9d 100644 --- a/ash/style/system_toast_style.cc +++ b/ash/style/system_toast_style.cc
@@ -190,9 +190,11 @@ } auto* focus_ring = views::FocusRing::Get(button_); - focus_ring->SetHasFocusPredicate([&](views::View* view) -> bool { - return is_dismiss_button_highlighted_; - }); + focus_ring->SetHasFocusPredicate(base::BindRepeating( + [](const SystemToastStyle* style, const views::View* view) { + return style->is_dismiss_button_highlighted_; + }, + base::Unretained(this))); is_dismiss_button_highlighted_ = !is_dismiss_button_highlighted_; scoped_a11y_overrider_->MaybeUpdateA11yOverrideWindow(
diff --git a/ash/system/accessibility/accessibility_feature_pod_controller.cc b/ash/system/accessibility/accessibility_feature_pod_controller.cc index dac9c180..3ad7e70 100644 --- a/ash/system/accessibility/accessibility_feature_pod_controller.cc +++ b/ash/system/accessibility/accessibility_feature_pod_controller.cc
@@ -62,10 +62,9 @@ feature_tile->SetLabel( l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY)); feature_tile->SetSubLabelVisibility(false); - const std::u16string tooltip_text = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TOOLTIP); - feature_tile->SetTooltipText(tooltip_text); - feature_tile->CreateDecorativeDrillInButton(tooltip_text); + feature_tile->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TOOLTIP)); + feature_tile->CreateDecorativeDrillInArrow(); AccessibilityDelegate* delegate = Shell::Get()->accessibility_delegate(); LoginStatus login_status = Shell::Get()->session_controller()->login_status();
diff --git a/ash/system/bluetooth/bluetooth_feature_pod_controller.cc b/ash/system/bluetooth/bluetooth_feature_pod_controller.cc index d87b005..775d886 100644 --- a/ash/system/bluetooth/bluetooth_feature_pod_controller.cc +++ b/ash/system/bluetooth/bluetooth_feature_pod_controller.cc
@@ -74,13 +74,14 @@ bool compact) { DCHECK(features::IsQsRevampEnabled()); auto tile = std::make_unique<FeatureTile>( - base::BindRepeating(&BluetoothFeaturePodController::OnIconPressed, + base::BindRepeating(&BluetoothFeaturePodController::OnLabelPressed, weak_factory_.GetWeakPtr())); tile_ = tile.get(); - tile_->CreateDrillInButton( - base::BindRepeating(&BluetoothFeaturePodController::OnLabelPressed, - weak_factory_.GetWeakPtr()), - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH)); + tile_->SetIconClickable(true); + tile_->SetIconClickCallback( + base::BindRepeating(&BluetoothFeaturePodController::OnIconPressed, + weak_factory_.GetWeakPtr())); + tile_->CreateDecorativeDrillInArrow(); // UpdateTileStateIfExists() will update visibility. tile_->SetVisible(false); UpdateTileStateIfExists(); @@ -316,14 +317,14 @@ IDS_ASH_STATUS_TRAY_BLUETOOTH_TOGGLE_TOOLTIP, l10n_util::GetStringUTF16( IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED_TOOLTIP)); + tile_->SetIconButtonTooltipText(tooltip); tile_->SetTooltipText(tooltip); - tile_->SetDrillInButtonTooltipText(tooltip); return; } std::u16string tooltip_core = ComputeTooltip(); - tile_->SetTooltipText(l10n_util::GetStringFUTF16( + tile_->SetIconButtonTooltipText(l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_BLUETOOTH_TOGGLE_TOOLTIP, tooltip_core)); - tile_->SetDrillInButtonTooltipText(l10n_util::GetStringFUTF16( + tile_->SetTooltipText(l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_BLUETOOTH_SETTINGS_TOOLTIP, tooltip_core)); }
diff --git a/ash/system/bluetooth/bluetooth_feature_pod_controller_unittest.cc b/ash/system/bluetooth/bluetooth_feature_pod_controller_unittest.cc index fb587243..73c5b9a 100644 --- a/ash/system/bluetooth/bluetooth_feature_pod_controller_unittest.cc +++ b/ash/system/bluetooth/bluetooth_feature_pod_controller_unittest.cc
@@ -218,14 +218,13 @@ std::u16string GetButtonTooltipText() { return IsQsRevampEnabled() - ? feature_tile_->GetTooltipText() + ? feature_tile_->icon_button()->GetTooltipText() : feature_pod_button_->icon_button()->GetTooltipText(); } std::u16string GetDrillInTooltipText() { - return IsQsRevampEnabled() - ? feature_tile_->drill_in_button()->GetTooltipText() - : feature_pod_label_button()->GetTooltipText(); + return IsQsRevampEnabled() ? feature_tile_->GetTooltipText() + : feature_pod_label_button()->GetTooltipText(); } const char* GetButtonIconName() {
diff --git a/ash/system/cast/cast_feature_pod_controller.cc b/ash/system/cast/cast_feature_pod_controller.cc index a00f7ff..3a795d6 100644 --- a/ash/system/cast/cast_feature_pod_controller.cc +++ b/ash/system/cast/cast_feature_pod_controller.cc
@@ -118,9 +118,8 @@ } tile->SetVisible(target_visibility); - const std::u16string tooltip = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_TOOLTIP); - tile->SetTooltipText(tooltip); + tile->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_CAST_TOOLTIP)); auto* cast_config = CastConfigController::Get(); if (cast_config) { @@ -135,7 +134,7 @@ return tile; } - tile->CreateDecorativeDrillInButton(tooltip); + tile->CreateDecorativeDrillInArrow(); return tile; }
diff --git a/ash/system/cast/cast_feature_pod_controller_unittest.cc b/ash/system/cast/cast_feature_pod_controller_unittest.cc index f25af03..60bfb23 100644 --- a/ash/system/cast/cast_feature_pod_controller_unittest.cc +++ b/ash/system/cast/cast_feature_pod_controller_unittest.cc
@@ -50,8 +50,9 @@ EXPECT_FALSE(tile->IsToggled()); EXPECT_EQ(tile->label()->GetText(), u"Cast screen"); EXPECT_EQ(tile->GetTooltipText(), u"Show cast devices"); - EXPECT_TRUE(tile->drill_in_button()->GetVisible()); - EXPECT_EQ(tile->drill_in_button()->GetTooltipText(), u"Show cast devices"); + ASSERT_TRUE(tile->drill_in_arrow()); + EXPECT_TRUE(tile->drill_in_arrow()->GetVisible()); + ASSERT_TRUE(tile->sub_label()); EXPECT_FALSE(tile->sub_label()->GetVisible()); }
diff --git a/ash/system/hotspot/hotspot_feature_pod_controller.cc b/ash/system/hotspot/hotspot_feature_pod_controller.cc index 13d5078a..0136a96 100644 --- a/ash/system/hotspot/hotspot_feature_pod_controller.cc +++ b/ash/system/hotspot/hotspot_feature_pod_controller.cc
@@ -44,13 +44,13 @@ std::unique_ptr<FeatureTile> HotspotFeaturePodController::CreateTile( bool compact) { auto tile = std::make_unique<FeatureTile>( - base::BindRepeating(&HotspotFeaturePodController::OnIconPressed, + base::BindRepeating(&HotspotFeaturePodController::OnLabelPressed, weak_ptr_factory_.GetWeakPtr())); tile_ = tile.get(); - tile_->CreateDrillInButton( - base::BindRepeating(&HotspotFeaturePodController::OnLabelPressed, - weak_ptr_factory_.GetWeakPtr()), - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_HOTSPOT)); + tile_->SetIconClickable(true); + tile_->SetIconClickCallback( + base::BindRepeating(&HotspotFeaturePodController::OnIconPressed, + weak_ptr_factory_.GetWeakPtr())); tile_->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_HOTSPOT)); // Default the visibility to false and update it in `UpdateTileState()` since @@ -119,8 +119,8 @@ tile_->SetToggled(hotspot_info_->state != HotspotState::kDisabled); tile_->SetVectorIcon(ComputeIcon()); tile_->SetSubLabel(ComputeSublabel()); - tile_->SetTooltipText(ComputeTooltip()); - tile_->SetDrillInButtonTooltipText(ComputeDrillInTooltip()); + tile_->SetIconButtonTooltipText(ComputeIconTooltip()); + tile_->SetTooltipText(ComputeTileTooltip()); } void HotspotFeaturePodController::EnableHotspotIfAllowedAndDiveIn() { @@ -161,7 +161,7 @@ } } -std::u16string HotspotFeaturePodController::ComputeTooltip() const { +std::u16string HotspotFeaturePodController::ComputeIconTooltip() const { switch (hotspot_info_->state) { case HotspotState::kEnabled: { // Toggle hotspot. Hotspot is on, # devices connected. @@ -211,7 +211,7 @@ } } -std::u16string HotspotFeaturePodController::ComputeDrillInTooltip() const { +std::u16string HotspotFeaturePodController::ComputeTileTooltip() const { switch (hotspot_info_->state) { case HotspotState::kEnabled: // Show hotspot details. Hotspot is on.
diff --git a/ash/system/hotspot/hotspot_feature_pod_controller.h b/ash/system/hotspot/hotspot_feature_pod_controller.h index 74595ba..2ece4cdb 100644 --- a/ash/system/hotspot/hotspot_feature_pod_controller.h +++ b/ash/system/hotspot/hotspot_feature_pod_controller.h
@@ -58,8 +58,8 @@ hotspot_config::mojom::HotspotControlResult operation_result); const gfx::VectorIcon& ComputeIcon() const; std::u16string ComputeSublabel() const; - std::u16string ComputeTooltip() const; - std::u16string ComputeDrillInTooltip() const; + std::u16string ComputeIconTooltip() const; + std::u16string ComputeTileTooltip() const; mojo::Remote<hotspot_config::mojom::CrosHotspotConfig> remote_cros_hotspot_config_;
diff --git a/ash/system/hotspot/hotspot_feature_pod_controller_unittest.cc b/ash/system/hotspot/hotspot_feature_pod_controller_unittest.cc index 32cb2cc..da6aa280 100644 --- a/ash/system/hotspot/hotspot_feature_pod_controller_unittest.cc +++ b/ash/system/hotspot/hotspot_feature_pod_controller_unittest.cc
@@ -126,12 +126,12 @@ EXPECT_EQ(u"Hotspot", hotspot_feature_tile_->label()->GetText()); EXPECT_EQ(u"On", hotspot_feature_tile_->sub_label()->GetText()); EXPECT_EQ(u"Toggle Hotspot. Hotspot is on, no device connected.", - hotspot_feature_tile_->GetTooltipText()); + hotspot_feature_tile_->icon_button()->GetTooltipText()); EXPECT_EQ(u"Show hotspot details. Hotspot is on.", - hotspot_feature_tile_->drill_in_button()->GetTooltipText()); + hotspot_feature_tile_->GetTooltipText()); UpdateHotspotInfo(HotspotState::kEnabled, HotspotAllowStatus::kAllowed, 2); EXPECT_EQ(u"Toggle Hotspot. Hotspot is on, 2 devices connected.", - hotspot_feature_tile_->GetTooltipText()); + hotspot_feature_tile_->icon_button()->GetTooltipText()); PressIcon(); EXPECT_FALSE(hotspot_feature_tile_->IsToggled()); @@ -150,9 +150,9 @@ EXPECT_EQ(u"Hotspot", hotspot_feature_tile_->label()->GetText()); EXPECT_EQ(u"Enabling…", hotspot_feature_tile_->sub_label()->GetText()); EXPECT_EQ(u"Show hotspot details. Hotspot is enabling.", - hotspot_feature_tile_->GetTooltipText()); + hotspot_feature_tile_->icon_button()->GetTooltipText()); EXPECT_EQ(u"Show hotspot details. Hotspot is enabling.", - hotspot_feature_tile_->drill_in_button()->GetTooltipText()); + hotspot_feature_tile_->GetTooltipText()); PressIcon(); EXPECT_TRUE(hotspot_feature_tile_->IsToggled()); EXPECT_TRUE(hotspot_feature_tile_->GetVisible()); @@ -169,9 +169,9 @@ EXPECT_EQ(u"Hotspot", hotspot_feature_tile_->label()->GetText()); EXPECT_EQ(u"Disabling…", hotspot_feature_tile_->sub_label()->GetText()); EXPECT_EQ(u"Show hotspot details. Hotspot is disabling.", - hotspot_feature_tile_->GetTooltipText()); + hotspot_feature_tile_->icon_button()->GetTooltipText()); EXPECT_EQ(u"Show hotspot details. Hotspot is disabling.", - hotspot_feature_tile_->drill_in_button()->GetTooltipText()); + hotspot_feature_tile_->GetTooltipText()); PressIcon(); EXPECT_TRUE(hotspot_feature_tile_->IsToggled()); EXPECT_TRUE(hotspot_feature_tile_->GetVisible()); @@ -188,9 +188,9 @@ EXPECT_EQ(u"Hotspot", hotspot_feature_tile_->label()->GetText()); EXPECT_EQ(u"Off", hotspot_feature_tile_->sub_label()->GetText()); EXPECT_EQ(u"Toggle Hotspot. Hotspot is off.", - hotspot_feature_tile_->GetTooltipText()); + hotspot_feature_tile_->icon_button()->GetTooltipText()); EXPECT_EQ(u"Toggle Hotspot. Hotspot is off.", - hotspot_feature_tile_->drill_in_button()->GetTooltipText()); + hotspot_feature_tile_->GetTooltipText()); PressIcon(); EXPECT_TRUE(hotspot_feature_tile_->IsToggled()); EXPECT_TRUE(hotspot_feature_tile_->GetVisible()); @@ -208,9 +208,9 @@ EXPECT_EQ(u"Hotspot", hotspot_feature_tile_->label()->GetText()); EXPECT_EQ(u"Off", hotspot_feature_tile_->sub_label()->GetText()); EXPECT_EQ(u"Show hotspot details. Connect to mobile network to use hotspot.", - hotspot_feature_tile_->GetTooltipText()); + hotspot_feature_tile_->icon_button()->GetTooltipText()); EXPECT_EQ(u"Show hotspot details. Hotspot is off.", - hotspot_feature_tile_->drill_in_button()->GetTooltipText()); + hotspot_feature_tile_->GetTooltipText()); PressIcon(); EXPECT_FALSE(hotspot_feature_tile_->IsToggled()); EXPECT_TRUE(hotspot_feature_tile_->GetVisible()); @@ -230,9 +230,9 @@ EXPECT_EQ(u"Off", hotspot_feature_tile_->sub_label()->GetText()); EXPECT_EQ( u"Show hotspot details. Your mobile network doesn't support hotspot.", - hotspot_feature_tile_->GetTooltipText()); + hotspot_feature_tile_->icon_button()->GetTooltipText()); EXPECT_EQ(u"Show hotspot details. Hotspot is off.", - hotspot_feature_tile_->drill_in_button()->GetTooltipText()); + hotspot_feature_tile_->GetTooltipText()); PressIcon(); EXPECT_FALSE(hotspot_feature_tile_->IsToggled()); } @@ -248,9 +248,9 @@ EXPECT_EQ(u"Hotspot", hotspot_feature_tile_->label()->GetText()); EXPECT_EQ(u"Off", hotspot_feature_tile_->sub_label()->GetText()); EXPECT_EQ(u"Show hotspot details. Hotspot is blocked by your administrator.", - hotspot_feature_tile_->GetTooltipText()); + hotspot_feature_tile_->icon_button()->GetTooltipText()); EXPECT_EQ(u"Show hotspot details. Hotspot is off.", - hotspot_feature_tile_->drill_in_button()->GetTooltipText()); + hotspot_feature_tile_->GetTooltipText()); PressIcon(); EXPECT_FALSE(hotspot_feature_tile_->IsToggled()); EXPECT_TRUE(hotspot_feature_tile_->GetVisible()); @@ -268,9 +268,9 @@ EXPECT_EQ(u"Hotspot", hotspot_feature_tile_->label()->GetText()); EXPECT_EQ(u"Off", hotspot_feature_tile_->sub_label()->GetText()); EXPECT_EQ(u"Toggle Hotspot. Hotspot is off.", - hotspot_feature_tile_->GetTooltipText()); + hotspot_feature_tile_->icon_button()->GetTooltipText()); EXPECT_EQ(u"Toggle Hotspot. Hotspot is off.", - hotspot_feature_tile_->drill_in_button()->GetTooltipText()); + hotspot_feature_tile_->GetTooltipText()); PressIcon(); EXPECT_TRUE(hotspot_feature_tile_->IsToggled()); EXPECT_TRUE(hotspot_feature_tile_->GetVisible());
diff --git a/ash/system/ime/ime_feature_pod_controller.cc b/ash/system/ime/ime_feature_pod_controller.cc index e083d5d..8dbd008 100644 --- a/ash/system/ime/ime_feature_pod_controller.cc +++ b/ash/system/ime/ime_feature_pod_controller.cc
@@ -94,9 +94,8 @@ tile_ = tile.get(); tile_->SetVectorIcon(kUnifiedMenuKeyboardIcon); tile_->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_IME_SHORT)); - std::u16string tooltip = GetTooltipString(); - tile_->SetTooltipText(tooltip); - tile_->CreateDecorativeDrillInButton(tooltip); + tile_->SetTooltipText(GetTooltipString()); + tile_->CreateDecorativeDrillInArrow(); // `Update` will update the visibility. tile_->SetVisible(false); Update(); @@ -126,7 +125,6 @@ if (features::IsQsRevampEnabled()) { tile_->SetSubLabel(GetLabelString()); tile_->SetTooltipText(tooltip); - tile_->SetDrillInButtonTooltipText(tooltip); // If the tile's visibility changes from invisible to visible, log its // visibility. if (!tile_->GetVisible() && is_button_visible) {
diff --git a/ash/system/input_device_settings/input_device_settings_controller_impl.cc b/ash/system/input_device_settings/input_device_settings_controller_impl.cc index 346c3ae..a54033d0 100644 --- a/ash/system/input_device_settings/input_device_settings_controller_impl.cc +++ b/ash/system/input_device_settings/input_device_settings_controller_impl.cc
@@ -153,22 +153,22 @@ touchpad.settings->haptic_sensitivity == settings.haptic_sensitivity); } -void RecordSetKeyboardSetttingsValidMetric(bool is_valid) { +void RecordSetKeyboardSettingsValidMetric(bool is_valid) { base::UmaHistogramBoolean( "ChromeOS.Settings.Device.Keyboard.SetSettingsSucceeded", is_valid); } -void RecordSetTouchpadSetttingsValidMetric(bool is_valid) { +void RecordSetTouchpadSettingsValidMetric(bool is_valid) { base::UmaHistogramBoolean( "ChromeOS.Settings.Device.Touchpad.SetSettingsSucceeded", is_valid); } -void RecordSetPointingStickSetttingsValidMetric(bool is_valid) { +void RecordSetPointingStickSettingsValidMetric(bool is_valid) { base::UmaHistogramBoolean( "ChromeOS.Settings.Device.PointingStick.SetSettingsSucceeded", is_valid); } -void RecordSetMouseSetttingsValidMetric(bool is_valid) { +void RecordSetMouseSettingsValidMetric(bool is_valid) { base::UmaHistogramBoolean( "ChromeOS.Settings.Device.Mouse.SetSettingsSucceeded", is_valid); } @@ -590,17 +590,17 @@ // If a device with the given id does not exist, do nothing. auto found_keyboard_iter = keyboards_.find(id); if (found_keyboard_iter == keyboards_.end()) { - RecordSetKeyboardSetttingsValidMetric(/*is_valid=*/false); + RecordSetKeyboardSettingsValidMetric(/*is_valid=*/false); return; } auto& found_keyboard = *found_keyboard_iter->second; if (!KeyboardSettingsAreValid(found_keyboard, *settings, policy_handler_->keyboard_policies())) { - RecordSetKeyboardSetttingsValidMetric(/*is_valid=*/false); + RecordSetKeyboardSettingsValidMetric(/*is_valid=*/false); return; } - RecordSetKeyboardSetttingsValidMetric(/*is_valid=*/true); + RecordSetKeyboardSettingsValidMetric(/*is_valid=*/true); const auto old_settings = std::move(found_keyboard.settings); found_keyboard.settings = settings.Clone(); keyboard_pref_handler_->UpdateKeyboardSettings( @@ -629,16 +629,16 @@ // If a device with the given id does not exist, do nothing. auto found_touchpad_iter = touchpads_.find(id); if (found_touchpad_iter == touchpads_.end()) { - RecordSetTouchpadSetttingsValidMetric(/*is_valid=*/false); + RecordSetTouchpadSettingsValidMetric(/*is_valid=*/false); return; } auto& found_touchpad = *found_touchpad_iter->second; if (!TouchpadSettingsAreValid(found_touchpad, *settings)) { - RecordSetTouchpadSetttingsValidMetric(/*is_valid=*/false); + RecordSetTouchpadSettingsValidMetric(/*is_valid=*/false); return; } - RecordSetTouchpadSetttingsValidMetric(/*is_valid=*/true); + RecordSetTouchpadSettingsValidMetric(/*is_valid=*/true); const auto old_settings = std::move(found_touchpad.settings); found_touchpad.settings = settings.Clone(); touchpad_pref_handler_->UpdateTouchpadSettings(active_pref_service_, @@ -666,10 +666,10 @@ // If a device with the given id does not exist, do nothing. auto found_mouse_iter = mice_.find(id); if (found_mouse_iter == mice_.end()) { - RecordSetMouseSetttingsValidMetric(/*is_valid=*/false); + RecordSetMouseSettingsValidMetric(/*is_valid=*/false); return; } - RecordSetMouseSetttingsValidMetric(/*is_valid=*/true); + RecordSetMouseSettingsValidMetric(/*is_valid=*/true); auto& found_mouse = *found_mouse_iter->second; const auto old_settings = std::move(found_mouse.settings); @@ -698,10 +698,10 @@ // If a device with the given id does not exist, do nothing. auto found_pointing_stick_iter = pointing_sticks_.find(id); if (found_pointing_stick_iter == pointing_sticks_.end()) { - RecordSetPointingStickSetttingsValidMetric(/*is_valid=*/false); + RecordSetPointingStickSettingsValidMetric(/*is_valid=*/false); return; } - RecordSetPointingStickSetttingsValidMetric(/*is_valid=*/true); + RecordSetPointingStickSettingsValidMetric(/*is_valid=*/true); auto& found_pointing_stick = *found_pointing_stick_iter->second; const auto old_settings = std::move(found_pointing_stick.settings);
diff --git a/ash/system/input_device_settings/input_device_settings_controller_unittest.cc b/ash/system/input_device_settings/input_device_settings_controller_unittest.cc index 64b99b9..8160df0 100644 --- a/ash/system/input_device_settings/input_device_settings_controller_unittest.cc +++ b/ash/system/input_device_settings/input_device_settings_controller_unittest.cc
@@ -454,7 +454,7 @@ } TEST_F(InputDeviceSettingsControllerTest, - RecordSetKeyboardSetttingsValidMetric) { + RecordSetKeyboardSettingsValidMetric) { base::HistogramTester histogram_tester; ui::DeviceDataManagerTestApi().SetKeyboardDevices({kSampleKeyboardInternal}); controller_->SetKeyboardSettings((DeviceId)kSampleKeyboardInternal.id, @@ -474,7 +474,7 @@ } TEST_F(InputDeviceSettingsControllerTest, - RecordSetTouchpadSetttingsValidMetric) { + RecordSetTouchpadSettingsValidMetric) { base::HistogramTester histogram_tester; ui::DeviceDataManagerTestApi().SetTouchpadDevices({kSampleTouchpadInternal}); @@ -512,7 +512,7 @@ } TEST_F(InputDeviceSettingsControllerTest, - RecordSetPointingStickSetttingsValidMetric) { + RecordSetPointingStickSettingsValidMetric) { base::HistogramTester histogram_tester; ui::DeviceDataManagerTestApi().SetPointingStickDevices( {kSamplePointingStickInternal}); @@ -531,7 +531,7 @@ /*expected_count=*/1u); } -TEST_F(InputDeviceSettingsControllerTest, RecordSetMouseSetttingsValidMetric) { +TEST_F(InputDeviceSettingsControllerTest, RecordSetMouseSettingsValidMetric) { base::HistogramTester histogram_tester; ui::DeviceDataManagerTestApi().SetMouseDevices({kSampleMouseUsb}); controller_->SetMouseSettings((DeviceId)kSampleMouseUsb.id,
diff --git a/ash/system/locale/locale_feature_pod_controller.cc b/ash/system/locale/locale_feature_pod_controller.cc index 3d80a0b..9b7079bf 100644 --- a/ash/system/locale/locale_feature_pod_controller.cc +++ b/ash/system/locale/locale_feature_pod_controller.cc
@@ -71,10 +71,9 @@ if (visible) { TrackVisibilityUMA(); tile->SetVectorIcon(kUnifiedMenuLocaleIcon); - std::u16string tooltip = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LOCALE_TOOLTIP); - tile->SetTooltipText(tooltip); - tile->CreateDecorativeDrillInButton(tooltip); + tile->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LOCALE_TOOLTIP)); + tile->CreateDecorativeDrillInArrow(); tile->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LOCALE)); tile->SetSubLabel(GetSubLabelText()); }
diff --git a/ash/system/media/quick_settings_media_view.cc b/ash/system/media/quick_settings_media_view.cc index a771e4f..b2caaaa 100644 --- a/ash/system/media/quick_settings_media_view.cc +++ b/ash/system/media/quick_settings_media_view.cc
@@ -5,7 +5,6 @@ #include "ash/system/media/quick_settings_media_view.h" #include "ash/public/cpp/pagination/pagination_controller.h" -#include "ash/public/cpp/pagination/pagination_model.h" #include "ash/public/cpp/pagination/pagination_model_observer.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/pagination_view.h" @@ -87,20 +86,19 @@ QuickSettingsMediaView::QuickSettingsMediaView( QuickSettingsMediaViewController* controller) - : controller_(controller), - pagination_model_(std::make_unique<PaginationModel>(nullptr)) { + : controller_(controller) { // All the views need to paint to layer so that the pagination view can be // placed floating above the media scroll view. media_scroll_view_ = - AddChildView(std::make_unique<MediaScrollView>(pagination_model_.get())); + AddChildView(std::make_unique<MediaScrollView>(&pagination_model_)); pagination_view_ = - AddChildView(std::make_unique<PaginationView>(pagination_model_.get())); + AddChildView(std::make_unique<PaginationView>(&pagination_model_)); pagination_view_->SetPaintToLayer(); pagination_view_->layer()->SetFillsBoundsOpaquely(false); pagination_controller_ = std::make_unique<PaginationController>( - pagination_model_.get(), PaginationController::SCROLL_AXIS_HORIZONTAL, + &pagination_model_, PaginationController::SCROLL_AXIS_HORIZONTAL, base::BindRepeating([](ui::EventType) {})); SetAccessibleName(l10n_util::GetStringUTF16( @@ -154,7 +152,7 @@ item->SetPreferredSize(gfx::Size(kMediaViewWidth, kMediaViewHeight)); items_[id] = media_scroll_view_->contents()->AddChildView(std::move(item)); - pagination_model_->SetTotalPages(items_.size()); + pagination_model_.SetTotalPages(items_.size()); PreferredSizeChanged(); controller_->SetShowMediaView(true); } @@ -166,7 +164,7 @@ media_scroll_view_->contents()->RemoveChildViewT(items_[id]); items_.erase(id); - pagination_model_->SetTotalPages(items_.size()); + pagination_model_.SetTotalPages(items_.size()); PreferredSizeChanged(); controller_->SetShowMediaView(!items_.empty()); } @@ -193,4 +191,4 @@ } } -} // namespace ash \ No newline at end of file +} // namespace ash
diff --git a/ash/system/media/quick_settings_media_view.h b/ash/system/media/quick_settings_media_view.h index 821a1cc..8385988 100644 --- a/ash/system/media/quick_settings_media_view.h +++ b/ash/system/media/quick_settings_media_view.h
@@ -9,6 +9,7 @@ #include <map> #include "ash/ash_export.h" +#include "ash/public/cpp/pagination/pagination_model.h" #include "ui/views/view.h" namespace global_media_controls { @@ -22,7 +23,6 @@ } // namespace class PaginationController; -class PaginationModel; class PaginationView; class QuickSettingsMediaViewController; @@ -49,10 +49,17 @@ // Updates the media item order given the id order in the list. void UpdateItemOrder(std::list<std::string> ids); + // Helper functions for testing. + PaginationModel* pagination_model_for_testing() { return &pagination_model_; } + std::map<const std::string, global_media_controls::MediaItemUIView*> + items_for_testing() { + return items_; + } + private: raw_ptr<QuickSettingsMediaViewController> controller_ = nullptr; - std::unique_ptr<PaginationModel> pagination_model_; + PaginationModel pagination_model_{this}; std::unique_ptr<PaginationController> pagination_controller_;
diff --git a/ash/system/media/quick_settings_media_view_container_unittest.cc b/ash/system/media/quick_settings_media_view_container_unittest.cc new file mode 100644 index 0000000..9b361a5 --- /dev/null +++ b/ash/system/media/quick_settings_media_view_container_unittest.cc
@@ -0,0 +1,71 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/media/quick_settings_media_view_container.h" + +#include "ash/constants/ash_features.h" +#include "ash/system/media/media_tray.h" +#include "ash/system/unified/unified_system_tray.h" +#include "ash/system/unified/unified_system_tray_bubble.h" +#include "ash/test/ash_test_base.h" +#include "base/test/scoped_feature_list.h" +#include "media/base/media_switches.h" + +namespace ash { + +class QuickSettingsMediaViewContainerTest : public NoSessionAshTestBase { + public: + QuickSettingsMediaViewContainerTest() = default; + QuickSettingsMediaViewContainerTest( + const QuickSettingsMediaViewContainerTest&) = delete; + QuickSettingsMediaViewContainerTest& operator=( + const QuickSettingsMediaViewContainerTest&) = delete; + ~QuickSettingsMediaViewContainerTest() override = default; + + void SetUp() override { + feature_list_.InitWithFeatures( + {features::kQsRevamp, media::kGlobalMediaControlsCrOSUpdatedUI}, {}); + NoSessionAshTestBase::SetUp(); + + MediaTray::SetPinnedToShelf(false); + GetPrimaryUnifiedSystemTray()->ShowBubble(); + } + + QuickSettingsView* quick_settings_view() { + return GetPrimaryUnifiedSystemTray()->bubble()->quick_settings_view(); + } + + QuickSettingsMediaViewContainer* media_view_container() { + return quick_settings_view()->media_view_container_for_testing(); + } + + private: + base::test::ScopedFeatureList feature_list_; +}; + +TEST_F(QuickSettingsMediaViewContainerTest, ChangeMediaViewVisibility) { + EXPECT_FALSE(media_view_container()->GetVisible()); + + quick_settings_view()->SetShowMediaView(true); + EXPECT_TRUE(media_view_container()->GetVisible()); + + quick_settings_view()->SetShowMediaView(false); + EXPECT_FALSE(media_view_container()->GetVisible()); +} + +TEST_F(QuickSettingsMediaViewContainerTest, + SwitchBetweenMediaViewAndDetailedView) { + quick_settings_view()->SetShowMediaView(true); + EXPECT_TRUE(media_view_container()->GetVisible()); + + // Make the quick settings view navigate to a dummy detailed view. + quick_settings_view()->SetDetailedView(std::make_unique<views::View>()); + EXPECT_FALSE(media_view_container()->GetVisible()); + + // Make the quick settings view navigate back to the main view. + quick_settings_view()->ResetDetailedView(); + EXPECT_TRUE(media_view_container()->GetVisible()); +} + +} // namespace ash
diff --git a/ash/system/media/quick_settings_media_view_controller.cc b/ash/system/media/quick_settings_media_view_controller.cc index 5f09c8d..4334d128 100644 --- a/ash/system/media/quick_settings_media_view_controller.cc +++ b/ash/system/media/quick_settings_media_view_controller.cc
@@ -24,6 +24,11 @@ media_session::MediaSessionService* service = Shell::Get()->shell_delegate()->GetMediaSessionService(); + // Return if this is called from tests and there is no media service. + if (!service) { + return; + } + mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote; mojo::Remote<media_session::mojom::MediaControllerManager> controller_manager_remote; @@ -105,4 +110,4 @@ media_view_->UpdateItemOrder(media_item_manager_->GetActiveItemIds()); } -} // namespace ash \ No newline at end of file +} // namespace ash
diff --git a/ash/system/media/quick_settings_media_view_controller.h b/ash/system/media/quick_settings_media_view_controller.h index 4f481ff1..508bb8e 100644 --- a/ash/system/media/quick_settings_media_view_controller.h +++ b/ash/system/media/quick_settings_media_view_controller.h
@@ -68,6 +68,9 @@ // Updates the order of media items in the quick settings media view. void UpdateMediaItemOrder(); + // Helper functions for testing. + QuickSettingsMediaView* media_view_for_testing() { return media_view_; } + private: raw_ptr<UnifiedSystemTrayController> tray_controller_ = nullptr;
diff --git a/ash/system/media/quick_settings_media_view_controller_unittest.cc b/ash/system/media/quick_settings_media_view_controller_unittest.cc new file mode 100644 index 0000000..89cc2a1 --- /dev/null +++ b/ash/system/media/quick_settings_media_view_controller_unittest.cc
@@ -0,0 +1,71 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/media/quick_settings_media_view_controller.h" + +#include "ash/constants/ash_features.h" +#include "ash/system/media/media_tray.h" +#include "ash/system/media/quick_settings_media_view.h" +#include "ash/system/unified/unified_system_tray.h" +#include "ash/system/unified/unified_system_tray_bubble.h" +#include "ash/test/ash_test_base.h" +#include "base/test/scoped_feature_list.h" +#include "components/media_message_center/mock_media_notification_item.h" +#include "media/base/media_switches.h" + +namespace ash { + +class QuickSettingsMediaViewControllerTest : public NoSessionAshTestBase { + public: + QuickSettingsMediaViewControllerTest() = default; + QuickSettingsMediaViewControllerTest( + const QuickSettingsMediaViewControllerTest&) = delete; + QuickSettingsMediaViewControllerTest& operator=( + const QuickSettingsMediaViewControllerTest&) = delete; + ~QuickSettingsMediaViewControllerTest() override = default; + + void SetUp() override { + feature_list_.InitWithFeatures( + {features::kQsRevamp, media::kGlobalMediaControlsCrOSUpdatedUI}, {}); + NoSessionAshTestBase::SetUp(); + + MediaTray::SetPinnedToShelf(false); + GetPrimaryUnifiedSystemTray()->ShowBubble(); + item_ = std::make_unique<testing::NiceMock< + media_message_center::test::MockMediaNotificationItem>>(); + } + + QuickSettingsMediaViewController* controller() { + return GetPrimaryUnifiedSystemTray() + ->bubble() + ->unified_system_tray_controller() + ->media_view_controller(); + } + + QuickSettingsMediaView* view() { + return controller()->media_view_for_testing(); + } + + base::WeakPtr<media_message_center::test::MockMediaNotificationItem> item() { + return item_->GetWeakPtr(); + } + + private: + base::test::ScopedFeatureList feature_list_; + std::unique_ptr<media_message_center::test::MockMediaNotificationItem> item_; +}; + +TEST_F(QuickSettingsMediaViewControllerTest, ShowOrHideMediaItem) { + const std::string item_id = "item_id"; + EXPECT_EQ(0, static_cast<int>(view()->items_for_testing().size())); + + controller()->ShowMediaItem(item_id, item()); + EXPECT_EQ(1, static_cast<int>(view()->items_for_testing().size())); + EXPECT_TRUE(view()->items_for_testing().contains(item_id)); + + controller()->HideMediaItem(item_id); + EXPECT_EQ(0, static_cast<int>(view()->items_for_testing().size())); +} + +} // namespace ash
diff --git a/ash/system/media/quick_settings_media_view_unittest.cc b/ash/system/media/quick_settings_media_view_unittest.cc new file mode 100644 index 0000000..c4eb0183 --- /dev/null +++ b/ash/system/media/quick_settings_media_view_unittest.cc
@@ -0,0 +1,75 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/system/media/quick_settings_media_view.h" + +#include "ash/constants/ash_features.h" +#include "ash/system/media/media_tray.h" +#include "ash/system/media/quick_settings_media_view_controller.h" +#include "ash/system/unified/unified_system_tray.h" +#include "ash/system/unified/unified_system_tray_bubble.h" +#include "ash/test/ash_test_base.h" +#include "base/test/scoped_feature_list.h" +#include "components/global_media_controls/public/views/media_item_ui_view.h" +#include "components/media_message_center/mock_media_notification_item.h" +#include "media/base/media_switches.h" + +namespace ash { + +class QuickSettingsMediaViewTest : public NoSessionAshTestBase { + public: + QuickSettingsMediaViewTest() = default; + QuickSettingsMediaViewTest(const QuickSettingsMediaViewTest&) = delete; + QuickSettingsMediaViewTest& operator=(const QuickSettingsMediaViewTest&) = + delete; + ~QuickSettingsMediaViewTest() override = default; + + void SetUp() override { + feature_list_.InitWithFeatures( + {features::kQsRevamp, media::kGlobalMediaControlsCrOSUpdatedUI}, {}); + NoSessionAshTestBase::SetUp(); + + MediaTray::SetPinnedToShelf(false); + GetPrimaryUnifiedSystemTray()->ShowBubble(); + item_ = std::make_unique<testing::NiceMock< + media_message_center::test::MockMediaNotificationItem>>(); + } + + QuickSettingsMediaView* view() { + return GetPrimaryUnifiedSystemTray() + ->bubble() + ->unified_system_tray_controller() + ->media_view_controller() + ->media_view_for_testing(); + } + + base::WeakPtr<media_message_center::test::MockMediaNotificationItem> item() { + return item_->GetWeakPtr(); + } + + private: + base::test::ScopedFeatureList feature_list_; + std::unique_ptr<media_message_center::test::MockMediaNotificationItem> item_; +}; + +TEST_F(QuickSettingsMediaViewTest, ShowOrHideItem) { + const std::string item_id = "item_id"; + std::unique_ptr<global_media_controls::MediaItemUIView> item_ui = + std::make_unique<global_media_controls::MediaItemUIView>( + item_id, item(), nullptr, nullptr); + + EXPECT_EQ(0, static_cast<int>(view()->items_for_testing().size())); + EXPECT_EQ(-1, view()->pagination_model_for_testing()->total_pages()); + + view()->ShowItem(item_id, std::move(item_ui)); + EXPECT_EQ(1, static_cast<int>(view()->items_for_testing().size())); + EXPECT_TRUE(view()->items_for_testing().contains(item_id)); + EXPECT_EQ(1, view()->pagination_model_for_testing()->total_pages()); + + view()->HideItem(item_id); + EXPECT_EQ(0, static_cast<int>(view()->items_for_testing().size())); + EXPECT_EQ(0, view()->pagination_model_for_testing()->total_pages()); +} + +} // namespace ash
diff --git a/ash/system/network/network_feature_pod_controller.cc b/ash/system/network/network_feature_pod_controller.cc index a2d3834..28f4bbc 100644 --- a/ash/system/network/network_feature_pod_controller.cc +++ b/ash/system/network/network_feature_pod_controller.cc
@@ -188,14 +188,14 @@ DCHECK(features::IsQsRevampEnabled()); auto tile = std::make_unique<NetworkFeatureTile>( /*delegate=*/this, - base::BindRepeating(&FeaturePodControllerBase::OnIconPressed, + base::BindRepeating(&FeaturePodControllerBase::OnLabelPressed, weak_ptr_factory_.GetWeakPtr())); tile_ = tile.get(); - tile_->CreateDrillInButton( - base::BindRepeating(&FeaturePodControllerBase::OnLabelPressed, - weak_ptr_factory_.GetWeakPtr()), - l10n_util::GetStringFUTF16(IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP, - std::u16string())); + tile_->SetIconClickable(true); + tile_->SetIconClickCallback( + base::BindRepeating(&FeaturePodControllerBase::OnIconPressed, + weak_ptr_factory_.GetWeakPtr())); + tile_->CreateDecorativeDrillInArrow(); UpdateButtonStateIfExists(); TrackVisibilityUMA(); return tile; @@ -329,7 +329,7 @@ tile_->SetSubLabel(ComputeButtonSubLabel(default_network)); if (!tile_->GetEnabled()) { tile_->SetTooltipText(tooltip); - tile_->SetDrillInButtonTooltipText(tooltip); + tile_->SetIconButtonTooltipText(tooltip); return; } } else { @@ -348,7 +348,7 @@ const std::u16string tooltip_text = l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP, tooltip); tile_->SetTooltipText(tooltip_text); - tile_->SetDrillInButtonTooltipText(tooltip_text); + tile_->SetIconButtonTooltipText(tooltip_text); } else { button_->SetIconAndLabelTooltips(l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP, tooltip)); @@ -357,7 +357,7 @@ } if (is_qs_revamp_enabled) { - tile_->SetTooltipText(l10n_util::GetStringFUTF16( + tile_->SetIconButtonTooltipText(l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_NETWORK_TOGGLE_TOOLTIP, tooltip)); } else { button_->SetIconTooltip(l10n_util::GetStringFUTF16( @@ -367,7 +367,7 @@ // Make sure the tooltip indicates the network type will be toggled by // pressing the label if the network type is disabled. if (is_qs_revamp_enabled) { - tile_->SetDrillInButtonTooltipText(l10n_util::GetStringFUTF16( + tile_->SetTooltipText(l10n_util::GetStringFUTF16( toggled ? IDS_ASH_STATUS_TRAY_NETWORK_SETTINGS_TOOLTIP : IDS_ASH_STATUS_TRAY_NETWORK_TOGGLE_TOOLTIP, tooltip));
diff --git a/ash/system/network/network_feature_pod_controller_unittest.cc b/ash/system/network/network_feature_pod_controller_unittest.cc index 1563a830..a6c1888a 100644 --- a/ash/system/network/network_feature_pod_controller_unittest.cc +++ b/ash/system/network/network_feature_pod_controller_unittest.cc
@@ -304,8 +304,9 @@ } bool IsDiveInButtonEnabled() { + // QsRevamp doesn't have a separate "dive-in" button, just the tile itself. return IsQsRevampEnabled() - ? feature_tile_->drill_in_button()->GetEnabled() + ? feature_tile_->GetEnabled() : feature_pod_button_->label_button()->GetEnabled(); } @@ -333,14 +334,14 @@ } const std::u16string GetIconTooltipText() { - return IsQsRevampEnabled() ? feature_tile_->GetTooltipText() + return IsQsRevampEnabled() ? feature_tile_->icon_button()->GetTooltipText() : feature_pod_icon_button()->GetTooltipText(); } const std::u16string GetLabelTooltipText() { - return IsQsRevampEnabled() - ? feature_tile_->drill_in_button()->GetTooltipText() - : feature_pod_label_button()->GetTooltipText(); + // QsRevamp doesn't have a separate label button, just the tile itself. + return IsQsRevampEnabled() ? feature_tile_->GetTooltipText() + : feature_pod_label_button()->GetTooltipText(); } NetworkStateTestHelper* network_state_helper() { @@ -842,10 +843,11 @@ ActiveNetworkIcon* active_network_icon = Shell::Get()->system_tray_model()->active_network_icon(); - gfx::Image image; - image = IsQsRevampEnabled() ? gfx::Image(feature_tile()->icon()->GetImage()) - : gfx::Image(feature_pod_icon_button()->GetImage( - views::Button::STATE_NORMAL)); + views::ImageButton* icon_button = IsQsRevampEnabled() + ? feature_tile()->icon_button() + : feature_pod_icon_button(); + gfx::Image image = + gfx::Image(icon_button->GetImage(views::Button::STATE_NORMAL)); ui::ColorProvider* color_provider = IsQsRevampEnabled() ? quick_settings_view()->GetColorProvider() @@ -860,9 +862,7 @@ // Lock screen to get the button's disabled state. LockScreen(); - image = IsQsRevampEnabled() ? gfx::Image(feature_tile()->icon()->GetImage()) - : gfx::Image(feature_pod_icon_button()->GetImage( - views::Button::STATE_DISABLED)); + image = gfx::Image(icon_button->GetImage(views::Button::STATE_DISABLED)); EXPECT_TRUE(gfx::test::AreImagesEqual( gfx::Image(active_network_icon->GetImage( @@ -880,9 +880,7 @@ network_handler::ErrorCallback()); base::RunLoop().RunUntilIdle(); - image = IsQsRevampEnabled() ? gfx::Image(feature_tile()->icon()->GetImage()) - : gfx::Image(feature_pod_icon_button()->GetImage( - views::Button::STATE_NORMAL)); + image = gfx::Image(icon_button->GetImage(views::Button::STATE_NORMAL)); EXPECT_TRUE(gfx::test::AreImagesEqual( gfx::Image(active_network_icon->GetImage(
diff --git a/ash/system/network/network_feature_tile_pixeltest.cc b/ash/system/network/network_feature_tile_pixeltest.cc index 2003509..5448cdb3 100644 --- a/ash/system/network/network_feature_tile_pixeltest.cc +++ b/ash/system/network/network_feature_tile_pixeltest.cc
@@ -144,7 +144,7 @@ ASSERT_TRUE(tile_view); EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( "check_tile_view", - /*revision_number=*/0, tile_view)); + /*revision_number=*/1, tile_view)); } TEST_F(NetworkFeatureTilePixelTest, Ethernet) { @@ -156,7 +156,7 @@ ASSERT_TRUE(tile_view); EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( "check_tile_view", - /*revision_number=*/0, tile_view)); + /*revision_number=*/1, tile_view)); } TEST_F(NetworkFeatureTilePixelTest, Wifi) { @@ -168,7 +168,7 @@ ASSERT_TRUE(tile_view); EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( "check_tile_view", - /*revision_number=*/0, tile_view)); + /*revision_number=*/1, tile_view)); } TEST_F(NetworkFeatureTilePixelTest, Cellular) { @@ -180,7 +180,7 @@ ASSERT_TRUE(tile_view); EXPECT_TRUE(GetPixelDiffer()->CompareUiComponentsOnPrimaryScreen( "check_tile_view", - /*revision_number=*/0, tile_view)); + /*revision_number=*/1, tile_view)); } } // namespace ash
diff --git a/ash/system/network/vpn_feature_pod_controller.cc b/ash/system/network/vpn_feature_pod_controller.cc index 7e3ab3f..1a2e9fe0 100644 --- a/ash/system/network/vpn_feature_pod_controller.cc +++ b/ash/system/network/vpn_feature_pod_controller.cc
@@ -79,10 +79,9 @@ tile_ = tile.get(); tile_->SetVectorIcon(kUnifiedMenuVpnIcon); tile_->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_SHORT)); - const std::u16string tooltip = - l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_TOOLTIP); - tile_->SetTooltipText(tooltip); - tile_->CreateDecorativeDrillInButton(tooltip); + tile_->SetTooltipText( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_VPN_TOOLTIP)); + tile_->CreateDecorativeDrillInArrow(); // Init the tile with invisible state. `Update()` will update visibility. tile_->SetVisible(false); Update();
diff --git a/ash/system/network/vpn_feature_pod_controller_unittest.cc b/ash/system/network/vpn_feature_pod_controller_unittest.cc index 62508ce0..2584a02e 100644 --- a/ash/system/network/vpn_feature_pod_controller_unittest.cc +++ b/ash/system/network/vpn_feature_pod_controller_unittest.cc
@@ -82,9 +82,8 @@ CreateTile(); EXPECT_TRUE(feature_tile_->GetVisible()); EXPECT_EQ(feature_tile_->GetTooltipText(), u"Show VPN settings"); - EXPECT_TRUE(feature_tile_->drill_in_button()->GetVisible()); - EXPECT_EQ(feature_tile_->drill_in_button()->GetTooltipText(), - u"Show VPN settings"); + ASSERT_TRUE(feature_tile_->drill_in_arrow()); + EXPECT_TRUE(feature_tile_->drill_in_arrow()->GetVisible()); } } // namespace ash
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc index e198cd7..0a968e0 100644 --- a/ash/system/palette/palette_tray_unittest.cc +++ b/ash/system/palette/palette_tray_unittest.cc
@@ -24,6 +24,7 @@ #include "ash/test/ash_test_base.h" #include "ash/test_shell_delegate.h" #include "base/command_line.h" +#include "base/files/safe_base_name.h" #include "base/memory/ptr_util.h" #include "base/memory/raw_ptr.h" #include "base/run_loop.h" @@ -795,7 +796,8 @@ // Verify palette tray is hidden and the active tool is deactivated during // Projector session. - projector_session_->Start("projector_data"); + projector_session_->Start( + base::SafeBaseName::Create("projector_data").value()); EXPECT_FALSE(palette_tray_->GetVisible()); EXPECT_EQ( test_api_->palette_tool_manager()->GetActiveTool(PaletteGroup::MODE),
diff --git a/ash/system/unified/feature_tile.cc b/ash/system/unified/feature_tile.cc index 18c2fb2..afb2bfc 100644 --- a/ash/system/unified/feature_tile.cc +++ b/ash/system/unified/feature_tile.cc
@@ -13,14 +13,23 @@ #include "chromeos/constants/chromeos_features.h" #include "components/vector_icons/vector_icons.h" #include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/models/image_model.h" +#include "ui/chromeos/styles/cros_tokens_color_mappings.h" #include "ui/gfx/paint_vector_icon.h" +#include "ui/views/animation/ink_drop.h" +#include "ui/views/animation/ink_drop_highlight.h" #include "ui/views/background.h" +#include "ui/views/controls/button/image_button.h" +#include "ui/views/controls/focus_ring.h" #include "ui/views/controls/highlight_path_generator.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" #include "ui/views/layout/flex_layout.h" #include "ui/views/layout/flex_layout_view.h" using views::FlexLayout; using views::FlexLayoutView; +using views::InkDropHost; namespace ash { @@ -35,6 +44,8 @@ constexpr int kPrimarySubtitleLineHeight = 18; constexpr gfx::Size kDefaultSize(180, kFeatureTileHeight); constexpr gfx::Size kIconContainerSize(48, kFeatureTileHeight); +constexpr gfx::Size kIconButtonSize(36, 52); +constexpr int kIconButtonCornerRadius = 12; constexpr gfx::Size kTitlesContainerSize(92, kFeatureTileHeight); constexpr gfx::Size kDrillContainerSize(40, kFeatureTileHeight); @@ -43,12 +54,25 @@ constexpr int kCompactTitleLineHeight = 14; constexpr gfx::Size kCompactSize(kCompactWidth, kFeatureTileHeight); constexpr gfx::Size kCompactIconContainerSize(kCompactWidth, 30); +constexpr gfx::Size kCompactIconButtonSize(kIconSize, kIconSize); constexpr gfx::Size kCompactTitleContainerSize(kCompactWidth, 34); constexpr gfx::Size kCompactTitleLabelSize(kCompactWidth - 32, kCompactTitleLineHeight * 2); constexpr gfx::Insets kCompactIconContainerInteriorMargin( gfx::Insets::TLBR(0, 0, 4, 0)); +// Creates an ink drop hover highlight for `host` with `color_id`. +std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight( + views::View* host, + ui::ColorId color_id) { + SkColor color = host->GetColorProvider()->GetColor(color_id); + auto highlight = std::make_unique<views::InkDropHighlight>( + gfx::SizeF(host->size()), color); + // The color has the opacity baked in. + highlight->set_visible_opacity(1.0f); + return highlight; +} + } // namespace FeatureTile::FeatureTile(base::RepeatingCallback<void()> callback, @@ -63,11 +87,9 @@ enabled_changed_subscription_ = AddEnabledChangedCallback(base::BindRepeating( [](FeatureTile* feature_tile) { feature_tile->UpdateColors(); - if (!feature_tile->drill_in_button_) { - return; + if (feature_tile->is_icon_clickable_) { + feature_tile->icon_button_->SetEnabled(feature_tile->GetEnabled()); } - feature_tile->drill_in_button_->SetEnabled(feature_tile->GetEnabled()); - feature_tile->drill_in_arrow_->SetEnabled(feature_tile->GetEnabled()); }, base::Unretained(this))); } @@ -92,17 +114,27 @@ SetPreferredSize(is_compact ? kCompactSize : kDefaultSize); - auto* icon_container = AddChildView(std::make_unique<FlexLayoutView>()); - icon_container->SetCanProcessEventsWithinSubtree(false); - icon_container->SetMainAxisAlignment(views::LayoutAlignment::kCenter); - icon_container->SetCrossAxisAlignment(is_compact - ? views::LayoutAlignment::kEnd - : views::LayoutAlignment::kCenter); - icon_container->SetPreferredSize(is_compact ? kCompactIconContainerSize - : kIconContainerSize); - if (is_compact) - icon_container->SetInteriorMargin(kCompactIconContainerInteriorMargin); - icon_ = icon_container->AddChildView(std::make_unique<views::ImageView>()); + icon_container_ = AddChildView(std::make_unique<FlexLayoutView>()); + icon_container_->SetCanProcessEventsWithinSubtree(false); + icon_container_->SetMainAxisAlignment(views::LayoutAlignment::kCenter); + icon_container_->SetCrossAxisAlignment(is_compact + ? views::LayoutAlignment::kEnd + : views::LayoutAlignment::kCenter); + icon_container_->SetPreferredSize(is_compact ? kCompactIconContainerSize + : kIconContainerSize); + if (is_compact) { + icon_container_->SetInteriorMargin(kCompactIconContainerInteriorMargin); + } + + icon_button_ = + icon_container_->AddChildView(std::make_unique<views::ImageButton>()); + icon_button_->SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER); + icon_button_->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE); + icon_button_->SetPreferredSize(is_compact ? kCompactIconButtonSize + : kIconButtonSize); + // By default the icon button is not separately clickable. + icon_button_->SetEnabled(false); + icon_button_->SetCanProcessEventsWithinSubtree(false); auto* title_container = AddChildView(std::make_unique<FlexLayoutView>()); title_container->SetCanProcessEventsWithinSubtree(false); @@ -148,14 +180,44 @@ } } -void FeatureTile::CreateDrillInButton(base::RepeatingClosure callback, - const std::u16string& tooltip_text) { - CreateDrillInButtonView(callback, tooltip_text); +void FeatureTile::SetIconClickable(bool clickable) { + CHECK_EQ(type_, TileType::kPrimary); + is_icon_clickable_ = clickable; + // Allow `icon_button_` to receive hover and click events. This results in a + // tiny area inside `icon_container_` near the button's edge that does not + // have a tooltip, but it's unlikely users will notice. + icon_container_->SetCanProcessEventsWithinSubtree(clickable); + icon_button_->SetCanProcessEventsWithinSubtree(clickable); + icon_button_->SetEnabled(clickable); + + if (clickable) { + views::InstallRoundRectHighlightPathGenerator(icon_button_, gfx::Insets(), + kIconButtonCornerRadius); + UpdateIconButtonFocusRingColor(); + + views::InkDrop::Get(icon_button_)->SetMode(InkDropHost::InkDropMode::ON); + icon_button_->SetHasInkDropActionOnClick(true); + UpdateIconButtonRippleColors(); + } else { + views::HighlightPathGenerator::Install(icon_button_, nullptr); + views::InkDrop::Get(icon_button_)->SetMode(InkDropHost::InkDropMode::OFF); + } } -void FeatureTile::CreateDecorativeDrillInButton( - const std::u16string& tooltip_text) { - CreateDrillInButtonView(base::RepeatingClosure(), tooltip_text); +void FeatureTile::SetIconClickCallback( + base::RepeatingCallback<void()> callback) { + icon_button_->SetCallback(std::move(callback)); +} + +void FeatureTile::CreateDecorativeDrillInArrow() { + CHECK_EQ(type_, TileType::kPrimary); + + drill_in_arrow_ = AddChildView(std::make_unique<views::ImageView>()); + // The icon is set in UpdateDrillArrowColor(). + drill_in_arrow_->SetPreferredSize(kDrillContainerSize); + // Allow hover events to fall through to show tooltips from the main view. + drill_in_arrow_->SetCanProcessEventsWithinSubtree(false); + UpdateDrillInArrowColor(); } void FeatureTile::UpdateColors() { @@ -179,14 +241,22 @@ SetBackground(views::CreateThemedRoundedRectBackground(background_color, kButtonRadius)); - icon_->SetImage(ui::ImageModel::FromVectorIcon(*vector_icon_, - foreground_color, kIconSize)); + + auto icon_image_model = ui::ImageModel::FromVectorIcon( + *vector_icon_, foreground_color, kIconSize); + icon_button_->SetImageModel(views::Button::STATE_NORMAL, icon_image_model); + icon_button_->SetImageModel(views::Button::STATE_DISABLED, icon_image_model); + if (is_icon_clickable_) { + UpdateIconButtonRippleColors(); + UpdateIconButtonFocusRingColor(); + } + label_->SetEnabledColorId(foreground_color); if (sub_label_) { sub_label_->SetEnabledColorId(foreground_optional_color); } if (drill_in_arrow_) { - UpdateDrillInButtonFocusRingColor(); + UpdateDrillInArrowColor(); } } @@ -195,10 +265,6 @@ return; toggled_ = toggled; - if (drill_in_arrow_) { - drill_in_arrow_->SetToggled(toggled_); - } - UpdateColors(); } @@ -208,18 +274,21 @@ void FeatureTile::SetVectorIcon(const gfx::VectorIcon& icon) { vector_icon_ = &icon; - ui::ColorId color_id; - if (GetEnabled()) { - color_id = toggled_ ? cros_tokens::kCrosSysSystemOnPrimaryContainer - : cros_tokens::kCrosSysOnSurface; - } else { - color_id = cros_tokens::kCrosSysDisabled; - } - icon_->SetImage(ui::ImageModel::FromVectorIcon(icon, color_id, kIconSize)); + ui::ColorId color_id = GetIconColorId(); + auto image_model = ui::ImageModel::FromVectorIcon(icon, color_id, kIconSize); + icon_button_->SetImageModel(views::Button::STATE_NORMAL, image_model); + icon_button_->SetImageModel(views::Button::STATE_DISABLED, image_model); } void FeatureTile::SetImage(gfx::ImageSkia image) { - icon_->SetImage(ui::ImageModel::FromImageSkia(image)); + auto image_model = ui::ImageModel::FromImageSkia(image); + icon_button_->SetImageModel(views::Button::STATE_NORMAL, image_model); + icon_button_->SetImageModel(views::Button::STATE_DISABLED, image_model); +} + +void FeatureTile::SetIconButtonTooltipText(const std::u16string& tooltip_text) { + CHECK(is_icon_clickable_); + icon_button_->SetTooltipText(tooltip_text); } void FeatureTile::SetLabel(const std::u16string& label) { @@ -236,79 +305,41 @@ sub_label_->SetVisible(visible); } -void FeatureTile::SetDrillInButtonTooltipText(const std::u16string& text) { - // Only primary tiles have a drill-in button. - DCHECK(drill_in_button_); - drill_in_button_->SetTooltipText(text); -} - -void FeatureTile::OnThemeChanged() { - views::View::OnThemeChanged(); - if (drill_in_arrow_) { - UpdateDrillInButtonFocusRingColor(); +ui::ColorId FeatureTile::GetIconColorId() const { + if (!GetEnabled()) { + return cros_tokens::kCrosSysDisabled; } + return toggled_ ? cros_tokens::kCrosSysSystemOnPrimaryContainer + : cros_tokens::kCrosSysOnSurface; } -void FeatureTile::UpdateDrillInButtonFocusRingColor() { - views::FocusRing::Get(drill_in_arrow_) +void FeatureTile::UpdateIconButtonRippleColors() { + CHECK(is_icon_clickable_); + auto* ink_drop = views::InkDrop::Get(icon_button_); + // Set up the hover highlight. + ink_drop->SetCreateHighlightCallback( + base::BindRepeating(&CreateInkDropHighlight, icon_button_, + toggled_ ? cros_tokens::kCrosSysHighlightShape + : cros_tokens::kCrosSysHoverOnSubtle)); + // Set up the ripple color. + ink_drop->SetBaseColorId(toggled_ + ? cros_tokens::kCrosSysRipplePrimary + : cros_tokens::kCrosSysRippleNeutralOnSubtle); + // The ripple base color includes opacity. + ink_drop->SetVisibleOpacity(1.0f); +} + +void FeatureTile::UpdateIconButtonFocusRingColor() { + CHECK(is_icon_clickable_); + views::FocusRing::Get(icon_button_) ->SetColorId(toggled_ ? cros_tokens::kCrosSysFocusRingOnPrimaryContainer : cros_tokens::kCrosSysFocusRing); } -void FeatureTile::CreateDrillInButtonView( - base::RepeatingCallback<void()> callback, - const std::u16string& tooltip_text) { - DCHECK_EQ(type_, TileType::kPrimary); - - const bool has_callback = callback != base::RepeatingClosure(); - - auto drill_in_button = std::make_unique<views::LabelButton>(callback); - drill_in_button->SetLayoutManager(std::make_unique<FlexLayout>()) - ->SetMainAxisAlignment(views::LayoutAlignment::kCenter) - .SetCrossAxisAlignment(views::LayoutAlignment::kCenter); - drill_in_button->SetPreferredSize(kDrillContainerSize); - drill_in_button->SetFocusBehavior(FocusBehavior::NEVER); - drill_in_button->SetTooltipText(tooltip_text); - - auto drill_in_arrow = std::make_unique<IconButton>( - callback, - has_callback ? IconButton::Type::kXSmall - : IconButton::Type::kXSmallFloating, - &kQuickSettingsRightArrowIcon, tooltip_text, - /*togglable=*/is_togglable_, - /*has_border=*/true); - - // Focus behavior is set on this view, but we let its parent view - // `drill_in_button_` handle the button events. - drill_in_arrow->SetCanProcessEventsWithinSubtree(false); - - drill_in_arrow->SetIconColorId(cros_tokens::kCrosSysSecondary); - drill_in_arrow->SetIconToggledColorId( - cros_tokens::kCrosSysSystemOnPrimaryContainer); - - if (has_callback) { - // Buttons with a drill-in callback set a background color for the icon - // button. - drill_in_arrow->SetBackgroundColorId(cros_tokens::kCrosSysHoverOnSubtle); - drill_in_arrow->SetBackgroundToggledColorId( - cros_tokens::kCrosSysHighlightShape); - - // TODO(b/262615213): Delete when Jelly launches. - if (!chromeos::features::IsJellyEnabled()) { - drill_in_arrow->SetBackgroundColorId( - kColorAshControlBackgroundColorInactive); - drill_in_arrow->SetBackgroundToggledColorId( - static_cast<ui::ColorId>(kColorAshTileSmallCircle)); - } - } else { - // Decorative drill-in buttons do not focus the drill-in arrow nor process - // drill-in button events. - drill_in_button->SetCanProcessEventsWithinSubtree(false); - drill_in_arrow->SetFocusBehavior(FocusBehavior::NEVER); - } - - drill_in_button_ = AddChildView(std::move(drill_in_button)); - drill_in_arrow_ = drill_in_button_->AddChildView(std::move(drill_in_arrow)); +void FeatureTile::UpdateDrillInArrowColor() { + CHECK(drill_in_arrow_); + drill_in_arrow_->SetImage(ui::ImageModel::FromVectorIcon( + kQuickSettingsRightArrowIcon, GetIconColorId())); } BEGIN_METADATA(FeatureTile, views::Button)
diff --git a/ash/system/unified/feature_tile.h b/ash/system/unified/feature_tile.h index 95e105e1..3991b1f 100644 --- a/ash/system/unified/feature_tile.h +++ b/ash/system/unified/feature_tile.h
@@ -6,12 +6,22 @@ #define ASH_SYSTEM_UNIFIED_FEATURE_TILE_H_ #include "ash/ash_export.h" -#include "ash/style/icon_button.h" +#include "base/functional/callback_forward.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/label_button.h" + +namespace gfx { +struct VectorIcon; +} // namespace gfx + +namespace views { +class FlexLayoutView; +class ImageButton; +class ImageView; +class Label; +} // namespace views namespace ash { @@ -20,12 +30,13 @@ // There are two TileTypes: Primary and Compact. -// The primary tile has an icon and title, and may have a subtitle and a -// drill-in button. It presents one of the following behaviors: +// The primary tile has an icon and title, and may have a subtitle. The icon may +// or may not be separately clickable. The tile has one of the following +// behaviors: // 1. Launch surface (e.g. Screen Capture) // 2. Toggle (e.g. Toggle Dark Theme) // 3. Drill-in (e.g. Go to Accessibility detailed view) -// 4. Toggle with drill-in (e.g. Toggle Wi-Fi | Go to Network detailed view) +// 4. Toggle with drill-in (e.g. Toggle Wi-Fi | Go to Network details) // 5. Togglable tile with decorative drill-in (e.g. Selecting a VPN network) // The compact tile has an icon and a single title, which may be @@ -49,9 +60,8 @@ // Constructor for FeatureTiles. `callback` will be called when interacting // with the main part of the button, which accounts for the whole tile. - // For primary tiles with drill-in, `callback` is called when interacting with - // the left side of the button, since the right side holds the drill-in - // button. + // If the icon is not separately clickable (the default), `callback` will + // also be called when clicking on the icon. explicit FeatureTile(base::RepeatingCallback<void()> callback, bool is_togglable = true, TileType type = TileType::kPrimary); @@ -63,24 +73,27 @@ // depending on the button's `type_`. void CreateChildViews(); - // Creates `drill_in_button_` which holds `the drill_in_arrow_` icon button, - // and is positioned in the right area of the feature tile. - // `callback` is triggered when interacting with the drill-in button, but - // focus is set on its child `drill_in_arrow_`. - void CreateDrillInButton(base::RepeatingCallback<void()> callback, - const std::u16string& tooltip_text); + // Sets whether the icon on the left is clickable, separate from clicking on + // the tile itself. Use SetIconClickCallback() to set the callback. This + // function is separate from SetIconClickCallback() because it's likely that + // FeatureTile users will want to set the callback once but may want to switch + // the icon between being clickable or not (e.g. the network icon based on + // Ethernet vs. Wi-Fi). + void SetIconClickable(bool clickable); - // Creates a `drill_in_button_` that is not clickable but exists to indicate - // the button shows a detailed view when pressed. Events will be processed by - // its parent `FeatureTile`. - void CreateDecorativeDrillInButton(const std::u16string& tooltip_text); + // Sets the `callback` for clicks on `icon_button_`. + void SetIconClickCallback(base::RepeatingCallback<void()> callback); + + // Creates a decorative `drill_in_arrow_` on the right side of the tile. This + // indicates to the user that the tile shows a detailed view when pressed. + void CreateDecorativeDrillInArrow(); TileType tile_type() { return type_; } // Updates the colors of the background and elements of the button. void UpdateColors(); - // Updates the `toggled_` state of the button. If button is not togglable, + // Updates the `toggled_` state of the tile. If the tile is not togglable, // `toggled_` will always be false. void SetToggled(bool toggled); bool IsToggled() const; @@ -91,6 +104,9 @@ // Sets the tile icon from an ImageSkia. void SetImage(gfx::ImageSkia image); + // Sets the tooltip text of `icon_button_`. + void SetIconButtonTooltipText(const std::u16string& text); + // Sets the text of `label_`. void SetLabel(const std::u16string& label); @@ -100,40 +116,41 @@ // Sets visibility of `sub_label_`. void SetSubLabelVisibility(bool visible); - // Sets the tooltip text of `drill_in_button_`. - void SetDrillInButtonTooltipText(const std::u16string& text); - - // views::View: - void OnThemeChanged() override; - - views::ImageView* icon() { return icon_; } + bool is_icon_clickable() const { return is_icon_clickable_; } + views::ImageButton* icon_button() { return icon_button_; } views::Label* label() { return label_; } views::Label* sub_label() { return sub_label_; } - views::LabelButton* drill_in_button() { return drill_in_button_; } - IconButton* drill_in_arrow() { return drill_in_arrow_; } + views::ImageView* drill_in_arrow() { return drill_in_arrow_; } private: friend class BluetoothFeaturePodControllerTest; friend class NotificationCounterViewTest; - // Updates `drill_in_arrow_` since it uses a different focus ring color when - // the tile is toggled to provide contrast with the background color. - void UpdateDrillInButtonFocusRingColor(); + // Returns the color id to use for the `icon_button_` and `drill_in_arrow_` + // based on the tile's enabled and toggled state. + ui::ColorId GetIconColorId() const; - // Creates the drill-in button related views. Will style the button as - // decorative if an empty callback is provided. - void CreateDrillInButtonView(base::RepeatingClosure callback, - const std::u16string& tooltip_text); + // Updates the ink drop hover color and ripple color for `icon_button_`. + void UpdateIconButtonRippleColors(); + + // Updates the focus ring color for `icon_button_` for better visibility. + void UpdateIconButtonFocusRingColor(); + + // Updates the color of `drill_in_arrow_` for better visibility. + void UpdateDrillInArrowColor(); // The vector icon for the tile, if one is set. raw_ptr<const gfx::VectorIcon, ExperimentalAsh> vector_icon_ = nullptr; // Owned by views hierarchy. - raw_ptr<views::ImageView, ExperimentalAsh> icon_ = nullptr; + raw_ptr<views::FlexLayoutView, ExperimentalAsh> icon_container_ = nullptr; + raw_ptr<views::ImageButton, ExperimentalAsh> icon_button_ = nullptr; raw_ptr<views::Label, ExperimentalAsh> label_ = nullptr; raw_ptr<views::Label, ExperimentalAsh> sub_label_ = nullptr; - raw_ptr<views::LabelButton, ExperimentalAsh> drill_in_button_ = nullptr; - raw_ptr<IconButton, ExperimentalAsh> drill_in_arrow_ = nullptr; + raw_ptr<views::ImageView, ExperimentalAsh> drill_in_arrow_ = nullptr; + + // Whether the icon is separately clickable. + bool is_icon_clickable_ = false; // Whether this button is togglable. bool is_togglable_ = false;
diff --git a/ash/system/unified/feature_tile_unittest.cc b/ash/system/unified/feature_tile_unittest.cc index 949262c3..a35e18e1 100644 --- a/ash/system/unified/feature_tile_unittest.cc +++ b/ash/system/unified/feature_tile_unittest.cc
@@ -16,6 +16,8 @@ #include "base/memory/weak_ptr.h" #include "base/test/scoped_feature_list.h" #include "components/vector_icons/vector_icons.h" +#include "ui/views/animation/ink_drop.h" +#include "ui/views/controls/image_view.h" #include "ui/views/test/views_test_utils.h" namespace ash { @@ -38,12 +40,15 @@ std::unique_ptr<FeatureTile> CreateTile(bool compact = false) override { auto tile = std::make_unique<FeatureTile>( - base::BindRepeating(&FeaturePodControllerBase::OnIconPressed, + base::BindRepeating(&FeaturePodControllerBase::OnLabelPressed, weak_ptr_factory_.GetWeakPtr()), togglable_, compact ? FeatureTile::TileType::kCompact : FeatureTile::TileType::kPrimary); tile->SetVectorIcon(vector_icons::kDogfoodIcon); + tile->SetIconClickCallback( + base::BindRepeating(&MockFeaturePodController::OnIconPressed, + weak_ptr_factory_.GetWeakPtr())); tile_ = tile.get(); return tile; } @@ -55,34 +60,25 @@ void OnIconPressed() override { was_icon_pressed_ = true; // FeaturePodController elements in production know if they are togglable, - // but in this mock we need to check before changing the toggled state. - if (togglable_) { + // but in this mock we need to check before changing the toggled state. This + // attempts to match UX specs: tiles with clickable icons should toggle when + // their icon is clicked rather than their label. + if (togglable_ && tile_->is_icon_clickable()) { toggled_ = !toggled_; tile_->SetToggled(toggled_); } } void OnLabelPressed() override { - // If button is not of type: Toggle + Drill-in, `OnLabelPressed` resolves to - // `OnIconPressed`. - if (!togglable_) { - was_icon_pressed_ = true; - return; - } was_label_pressed_ = true; - } - - // FeaturePodController elements in production know if they need to create a - // drill-in button, but here we create it after creating the base button. - void CreateDrillInButton() { - tile_->CreateDrillInButton( - base::BindRepeating(&FeaturePodControllerBase::OnLabelPressed, - weak_ptr_factory_.GetWeakPtr()), - u"Tooltip text"); - } - - void CreateDecorativeDrillInButton() { - tile_->CreateDecorativeDrillInButton(u"Tooltip text"); + // FeaturePodController elements in production know if they are togglable, + // but in this mock we need to check before changing the toggled state. This + // attempts to match UX specs: tiles with clickable icons should toggle when + // their icon is clicked rather than their label. + if (togglable_ && !tile_->is_icon_clickable()) { + toggled_ = !toggled_; + tile_->SetToggled(toggled_); + } } bool WasIconPressed() { return was_icon_pressed_; } @@ -136,16 +132,17 @@ std::make_unique<MockFeaturePodController>(/*togglable=*/false); auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); - EXPECT_FALSE(tile->drill_in_button()); + EXPECT_FALSE(tile->is_icon_clickable()); + EXPECT_FALSE(tile->drill_in_arrow()); - // Ensure icon hasn't been pressed. + // Ensure label hasn't been pressed. EXPECT_FALSE(tile->IsToggled()); - EXPECT_FALSE(mock_controller->WasIconPressed()); + EXPECT_FALSE(mock_controller->WasLabelPressed()); LeftClickOn(tile); - // Ensure icon was pressed and button does not toggle after clicking it. - EXPECT_TRUE(mock_controller->WasIconPressed()); + // Ensure label was pressed and button does not toggle after clicking it. + EXPECT_TRUE(mock_controller->WasLabelPressed()); EXPECT_FALSE(tile->IsToggled()); } @@ -154,16 +151,17 @@ std::make_unique<MockFeaturePodController>(/*togglable=*/true); auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); - EXPECT_FALSE(tile->drill_in_button()); + EXPECT_FALSE(tile->is_icon_clickable()); + EXPECT_FALSE(tile->drill_in_arrow()); - // Ensure icon hasn't been pressed. + // Ensure label hasn't been pressed. EXPECT_FALSE(tile->IsToggled()); - EXPECT_FALSE(mock_controller->WasIconPressed()); + EXPECT_FALSE(mock_controller->WasLabelPressed()); LeftClickOn(tile); - // Ensure icon was pressed and button toggles after clicking it. - EXPECT_TRUE(mock_controller->WasIconPressed()); + // Ensure label was pressed and button toggles after clicking it. + EXPECT_TRUE(mock_controller->WasLabelPressed()); EXPECT_TRUE(tile->IsToggled()); LeftClickOn(tile); @@ -172,24 +170,87 @@ EXPECT_FALSE(tile->IsToggled()); } +TEST_F(FeatureTileTest, PrimaryTile_ToggleWithDrillIn) { + auto mock_controller = + std::make_unique<MockFeaturePodController>(/*togglable=*/true); + auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); + + tile->SetIconClickable(true); + views::test::RunScheduledLayout(tile); + EXPECT_TRUE(tile->is_icon_clickable()); + ASSERT_TRUE(tile->icon_button()); + EXPECT_TRUE(tile->icon_button()->GetEnabled()); + + // Ensure tile is not toggled and icon is not pressed. + EXPECT_FALSE(tile->IsToggled()); + EXPECT_FALSE(mock_controller->WasIconPressed()); + + LeftClickOn(tile); + + // Clicking the tile does not press the icon. + EXPECT_FALSE(mock_controller->WasIconPressed()); + EXPECT_TRUE(mock_controller->WasLabelPressed()); + EXPECT_FALSE(tile->IsToggled()); + + LeftClickOn(tile->icon_button()); + + // Clicking the icon presses it and toggles the tile. + EXPECT_TRUE(mock_controller->WasIconPressed()); + EXPECT_TRUE(tile->IsToggled()); +} + +TEST_F(FeatureTileTest, PrimaryTile_SetIconClickable) { + auto mock_controller = + std::make_unique<MockFeaturePodController>(/*togglable=*/true); + auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); + + // Ensure clickable state is correct. + tile->SetIconClickable(true); + EXPECT_TRUE(tile->is_icon_clickable()); + EXPECT_TRUE(tile->icon_button()->GetEnabled()); + auto* ink_drop = views::InkDrop::Get(tile->icon_button()); + ASSERT_TRUE(ink_drop); + EXPECT_EQ(ink_drop->GetMode(), views::InkDropHost::InkDropMode::ON); + + // Ensure icon button can take focus. + auto* focus_manager = widget_->GetFocusManager(); + PressTab(); + EXPECT_EQ(tile, focus_manager->GetFocusedView()); + PressTab(); + EXPECT_EQ(tile->icon_button(), focus_manager->GetFocusedView()); + + // Ensure button state changes when set to not clickable. + tile->SetIconClickable(false); + EXPECT_FALSE(tile->is_icon_clickable()); + EXPECT_FALSE(tile->icon_button()->GetEnabled()); + EXPECT_EQ(ink_drop->GetMode(), views::InkDropHost::InkDropMode::OFF); + + // Ensure icon button doesn't focus. + PressTab(); + EXPECT_EQ(tile, focus_manager->GetFocusedView()); + PressTab(); + EXPECT_EQ(tile, focus_manager->GetFocusedView()); +} + TEST_F(FeatureTileTest, PrimaryTile_DecorativeDrillIn) { auto mock_controller = std::make_unique<MockFeaturePodController>(/*togglable=*/false); auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); - mock_controller->CreateDecorativeDrillInButton(); + tile->CreateDecorativeDrillInArrow(); views::test::RunScheduledLayout(tile); - ASSERT_TRUE(tile->drill_in_button()); - EXPECT_TRUE(tile->drill_in_button()->GetVisible()); + EXPECT_FALSE(tile->is_icon_clickable()); + ASSERT_TRUE(tile->drill_in_arrow()); + EXPECT_TRUE(tile->drill_in_arrow()->GetVisible()); - // Ensure icon hasn't been pressed. + // Ensure label hasn't been pressed. EXPECT_FALSE(tile->IsToggled()); - EXPECT_FALSE(mock_controller->WasIconPressed()); + EXPECT_FALSE(mock_controller->WasLabelPressed()); - LeftClickOn(tile->drill_in_button()); + LeftClickOn(tile->drill_in_arrow()); - // Ensure icon was pressed and button does not toggle after clicking it. - EXPECT_TRUE(mock_controller->WasIconPressed()); + // Ensure label was pressed and button does not toggle after clicking it. + EXPECT_TRUE(mock_controller->WasLabelPressed()); EXPECT_FALSE(tile->IsToggled()); // Ensure drill-in button doesn't focus. @@ -200,41 +261,6 @@ EXPECT_EQ(tile, focus_manager->GetFocusedView()); } -TEST_F(FeatureTileTest, PrimaryTile_ToggleWithDrillIn) { - auto mock_controller = - std::make_unique<MockFeaturePodController>(/*togglable=*/true); - auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); - - mock_controller->CreateDrillInButton(); - views::test::RunScheduledLayout(tile); - ASSERT_TRUE(tile->drill_in_button()); - EXPECT_TRUE(tile->drill_in_button()->GetVisible()); - - // Ensure icon is not pressed or toggled. - EXPECT_FALSE(tile->IsToggled()); - EXPECT_FALSE(mock_controller->WasIconPressed()); - - LeftClickOn(tile); - - // Ensure icon was pressed and button toggles after clicking it. - EXPECT_TRUE(mock_controller->WasIconPressed()); - EXPECT_TRUE(tile->IsToggled()); - - EXPECT_FALSE(mock_controller->WasLabelPressed()); - - LeftClickOn(tile->drill_in_button()); - - // Ensure `WasLabelPressed` after clicking drill-in button. - EXPECT_TRUE(mock_controller->WasLabelPressed()); - - // Ensure drill-in button has focus. - auto* focus_manager = widget_->GetFocusManager(); - PressTab(); - EXPECT_EQ(tile, focus_manager->GetFocusedView()); - PressTab(); - EXPECT_EQ(tile->drill_in_arrow(), focus_manager->GetFocusedView()); -} - // Togglable tiles with a decorative drill-in button do not toggle when // clicked, but show a detailed view from where the user can trigger an action // which toggles the button state (e.g. selecting a VPN network). @@ -245,24 +271,25 @@ std::make_unique<MockFeaturePodController>(/*togglable=*/true); auto* tile = widget_->SetContentsView(mock_controller->CreateTile()); - mock_controller->CreateDecorativeDrillInButton(); + tile->CreateDecorativeDrillInArrow(); views::test::RunScheduledLayout(tile); - ASSERT_TRUE(tile->drill_in_button()); - EXPECT_TRUE(tile->drill_in_button()->GetVisible()); + EXPECT_FALSE(tile->is_icon_clickable()); + ASSERT_TRUE(tile->drill_in_arrow()); + EXPECT_TRUE(tile->drill_in_arrow()->GetVisible()); - // Ensure icon is not pressed. - EXPECT_FALSE(mock_controller->WasIconPressed()); + // Ensure label is not pressed. + EXPECT_FALSE(mock_controller->WasLabelPressed()); LeftClickOn(tile); - // Ensure icon was pressed after clicking it. - EXPECT_TRUE(mock_controller->WasIconPressed()); - EXPECT_FALSE(mock_controller->WasLabelPressed()); + // Ensure label was pressed after clicking it. + EXPECT_FALSE(mock_controller->WasIconPressed()); + EXPECT_TRUE(mock_controller->WasLabelPressed()); - LeftClickOn(tile->drill_in_button()); + LeftClickOn(tile->drill_in_arrow()); - // Ensure `WasLabelPressed` not pressed after clicking drill-in button. - EXPECT_FALSE(mock_controller->WasLabelPressed()); + // Ensure `WasIconPressed` not pressed after clicking drill-in button. + EXPECT_FALSE(mock_controller->WasIconPressed()); // Ensure drill-in button doesn't focus. auto* focus_manager = widget_->GetFocusManager(); @@ -277,15 +304,16 @@ /*togglable=*/false); auto* tile = widget_->SetContentsView(mock_controller->CreateTile(/*compact=*/true)); + EXPECT_FALSE(tile->is_icon_clickable()); - // Ensure icon hasn't been pressed. + // Ensure label hasn't been pressed. EXPECT_FALSE(tile->IsToggled()); - EXPECT_FALSE(mock_controller->WasIconPressed()); + EXPECT_FALSE(mock_controller->WasLabelPressed()); LeftClickOn(tile); - // Ensure icon was pressed and button does not toggle after clicking it. - EXPECT_TRUE(mock_controller->WasIconPressed()); + // Ensure label was pressed and button does not toggle after clicking it. + EXPECT_TRUE(mock_controller->WasLabelPressed()); EXPECT_FALSE(tile->IsToggled()); } @@ -294,15 +322,16 @@ /*togglable=*/true); auto* tile = widget_->SetContentsView(mock_controller->CreateTile(/*compact=*/true)); + EXPECT_FALSE(tile->is_icon_clickable()); - // Ensure icon hasn't been pressed. + // Ensure label hasn't been pressed. EXPECT_FALSE(tile->IsToggled()); - EXPECT_FALSE(mock_controller->WasIconPressed()); + EXPECT_FALSE(mock_controller->WasLabelPressed()); LeftClickOn(tile); - // Ensure icon was pressed and button toggles after clicking it. - EXPECT_TRUE(mock_controller->WasIconPressed()); + // Ensure label was pressed and button toggles after clicking it. + EXPECT_TRUE(mock_controller->WasLabelPressed()); EXPECT_TRUE(tile->IsToggled()); // Ensure button toggles after clicking it again.
diff --git a/ash/system/unified/quick_settings_view.h b/ash/system/unified/quick_settings_view.h index bccb03c1d..7647c5c 100644 --- a/ash/system/unified/quick_settings_view.h +++ b/ash/system/unified/quick_settings_view.h
@@ -116,6 +116,9 @@ UnifiedMediaControlsContainer* media_controls_container_for_testing() { return media_controls_container_; } + QuickSettingsMediaViewContainer* media_view_container_for_testing() { + return media_view_container_; + } QuickSettingsFooter* footer_for_testing() { return footer_; } private:
diff --git a/ash/user_education/user_education_controller.h b/ash/user_education/user_education_controller.h index a204fd8a..9b6fd46 100644 --- a/ash/user_education/user_education_controller.h +++ b/ash/user_education/user_education_controller.h
@@ -10,6 +10,7 @@ #include "ash/ash_export.h" #include "ash/public/cpp/session/session_observer.h" +#include "ash/user_education/user_education_help_bubble_controller.h" #include "ash/user_education/user_education_ping_controller.h" #include "ash/user_education/user_education_private_api_key.h" #include "base/functional/callback_forward.h" @@ -58,6 +59,9 @@ // education services in the browser. std::unique_ptr<UserEducationDelegate> delegate_; + // The controller responsible for creation/management of help bubbles. + UserEducationHelpBubbleController help_bubble_controller_; + // The controller responsible for creation/management of pings. UserEducationPingController ping_controller_;
diff --git a/ash/user_education/user_education_controller_unittest.cc b/ash/user_education/user_education_controller_unittest.cc index 66b0675..bfd5836 100644 --- a/ash/user_education/user_education_controller_unittest.cc +++ b/ash/user_education/user_education_controller_unittest.cc
@@ -14,6 +14,7 @@ #include "ash/user_education/mock_user_education_delegate.h" #include "ash/user_education/user_education_ash_test_base.h" #include "ash/user_education/user_education_feature_controller.h" +#include "ash/user_education/user_education_help_bubble_controller.h" #include "ash/user_education/user_education_ping_controller.h" #include "ash/user_education/welcome_tour/welcome_tour_controller.h" #include "base/test/bind.h" @@ -101,6 +102,13 @@ EXPECT_EQ(!!HoldingSpaceTourController::Get(), IsHoldingSpaceTourEnabled()); } +// Verifies that the user education help bubble controller exists iff user +// education features are enabled. +TEST_P(UserEducationControllerTest, UserEducationHelpBubbleControllerExists) { + EXPECT_EQ(!!UserEducationHelpBubbleController::Get(), + !!UserEducationController::Get()); +} + // Verifies that the user education ping controller exists iff user education // features are enabled. TEST_P(UserEducationControllerTest, UserEducationPingControllerExists) {
diff --git a/ash/user_education/user_education_help_bubble_controller.cc b/ash/user_education/user_education_help_bubble_controller.cc new file mode 100644 index 0000000..3629c0b --- /dev/null +++ b/ash/user_education/user_education_help_bubble_controller.cc
@@ -0,0 +1,45 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/user_education/user_education_help_bubble_controller.h" + +#include "ash/user_education/user_education_types.h" +#include "base/check_op.h" +#include "base/notreached.h" +#include "components/user_education/common/help_bubble_params.h" +#include "ui/base/interaction/element_identifier.h" + +namespace ash { +namespace { + +// The singleton instance owned by the `UserEducationController`. +UserEducationHelpBubbleController* g_instance = nullptr; + +} // namespace + +UserEducationHelpBubbleController::UserEducationHelpBubbleController() { + CHECK_EQ(g_instance, nullptr); + g_instance = this; +} + +UserEducationHelpBubbleController::~UserEducationHelpBubbleController() { + CHECK_EQ(g_instance, this); + g_instance = nullptr; +} + +// static +UserEducationHelpBubbleController* UserEducationHelpBubbleController::Get() { + return g_instance; +} + +bool UserEducationHelpBubbleController::CreateHelpBubble( + HelpBubbleId help_bubble_id, + user_education::HelpBubbleParams help_bubble_params, + ui::ElementIdentifier element_id, + ui::ElementContext element_context) { + NOTIMPLEMENTED(); + return false; +} + +} // namespace ash
diff --git a/ash/user_education/user_education_help_bubble_controller.h b/ash/user_education/user_education_help_bubble_controller.h new file mode 100644 index 0000000..4e2b0caf --- /dev/null +++ b/ash/user_education/user_education_help_bubble_controller.h
@@ -0,0 +1,51 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_USER_EDUCATION_USER_EDUCATION_HELP_BUBBLE_CONTROLLER_H_ +#define ASH_USER_EDUCATION_USER_EDUCATION_HELP_BUBBLE_CONTROLLER_H_ + +#include "ash/ash_export.h" + +namespace ui { +class ElementContext; +class ElementIdentifier; +} // namespace ui + +namespace user_education { +struct HelpBubbleParams; +} // namespace user_education + +namespace ash { + +enum class HelpBubbleId; + +// The singleton controller, owned by the `UserEducationController`, responsible +// for creation/management of help bubbles. +class ASH_EXPORT UserEducationHelpBubbleController { + public: + UserEducationHelpBubbleController(); + UserEducationHelpBubbleController(const UserEducationHelpBubbleController&) = + delete; + UserEducationHelpBubbleController& operator=( + const UserEducationHelpBubbleController&) = delete; + ~UserEducationHelpBubbleController(); + + // Returns the singleton instance owned by the `UserEducationController`. + // NOTE: Exists if and only if user education features are enabled. + static UserEducationHelpBubbleController* Get(); + + // TODO(http://b/279040829): Implement. + // Attempts to create a help bubble, identified by `help_bubble_id`, with the + // specified `help_bubble_params` for the tracked element associated with the + // specified `element_id` in the specified `element_context`. + // NOTE: Currently hardcoded to no-op and return `false`. + bool CreateHelpBubble(HelpBubbleId help_bubble_id, + user_education::HelpBubbleParams help_bubble_params, + ui::ElementIdentifier element_id, + ui::ElementContext element_context); +}; + +} // namespace ash + +#endif // ASH_USER_EDUCATION_USER_EDUCATION_HELP_BUBBLE_CONTROLLER_H_
diff --git a/ash/user_education/user_education_help_bubble_controller_unittest.cc b/ash/user_education/user_education_help_bubble_controller_unittest.cc new file mode 100644 index 0000000..96e8ac3 --- /dev/null +++ b/ash/user_education/user_education_help_bubble_controller_unittest.cc
@@ -0,0 +1,53 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/user_education/user_education_help_bubble_controller.h" + +#include "ash/constants/ash_features.h" +#include "ash/user_education/user_education_ash_test_base.h" +#include "ash/user_education/user_education_types.h" +#include "base/test/scoped_feature_list.h" +#include "components/user_education/common/help_bubble_params.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/interaction/element_identifier.h" + +namespace ash { + +// UserEducationHelpBubbleControllerTest --------------------------------------- + +// Base class for tests of the `UserEducationHelpBubbleController`. +class UserEducationHelpBubbleControllerTest : public UserEducationAshTestBase { + public: + UserEducationHelpBubbleControllerTest() { + // NOTE: The `UserEducationHelpBubbleController` exists only when a user + // education feature is enabled. Controller existence is verified in test + // coverage for the controller's owner. + std::vector<base::test::FeatureRef> enabled_features; + enabled_features.emplace_back(features::kCaptureModeTour); + enabled_features.emplace_back(features::kHoldingSpaceTour); + enabled_features.emplace_back(features::kWelcomeTour); + scoped_feature_list_.InitWithFeatures(enabled_features, {}); + } + + // Returns the singleton instance owned by the `UserEducationController`. + UserEducationHelpBubbleController* controller() { + return UserEducationHelpBubbleController::Get(); + } + + private: + // Used to enable user education features which are required for existence of + // the `controller()` under test. + base::test::ScopedFeatureList scoped_feature_list_; +}; + +// Tests ----------------------------------------------------------------------- + +// Verifies that `CreateHelpBubble()` is currently hardcoded to return `false`. +TEST_F(UserEducationHelpBubbleControllerTest, CreateHelpBubble) { + EXPECT_FALSE(controller()->CreateHelpBubble( + HelpBubbleId::kTest, user_education::HelpBubbleParams(), + ui::ElementIdentifier(), ui::ElementContext())); +} + +} // namespace ash
diff --git a/ash/webui/personalization_app/search/search_concept.h b/ash/webui/personalization_app/search/search_concept.h index 0067db73..d030d7b 100644 --- a/ash/webui/personalization_app/search/search_concept.h +++ b/ash/webui/personalization_app/search/search_concept.h
@@ -18,10 +18,11 @@ // The identifier for the string displayed to the user. int message_id; - // Alternate message ids that map to this concept. There is a maximum of 5 + + // Alternate message ids that map to this concept. There is a maximum of 20 // alternate message ids, but there may be fewer. Stop reading alternate // message ids upon encountering a default-initialized (ie 0) value. - std::array<int, 5> alternate_message_ids; + std::array<int, 20> alternate_message_ids; // The relative url, including query parameters, to open in Personalization // App. std::string relative_url;
diff --git a/ash/webui/personalization_app/search/search_tag_registry.cc b/ash/webui/personalization_app/search/search_tag_registry.cc index ef7b798..7caf916 100644 --- a/ash/webui/personalization_app/search/search_tag_registry.cc +++ b/ash/webui/personalization_app/search/search_tag_registry.cc
@@ -273,6 +273,21 @@ IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT3, IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT4, IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT5, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT6, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT7, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT8, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT9, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT10, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT11, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT12, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT13, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT14, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT15, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT16, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT17, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT18, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT19, + IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT20, }, .relative_url = "", });
diff --git a/ash/webui/projector_app/BUILD.gn b/ash/webui/projector_app/BUILD.gn index 1c98d24d..b61f30583 100644 --- a/ash/webui/projector_app/BUILD.gn +++ b/ash/webui/projector_app/BUILD.gn
@@ -53,7 +53,6 @@ "//components/signin/public/identity_manager", "//content/public/browser", "//mojo/public/cpp/bindings", - "//third_party/re2:re2", "//ui/resources", "//ui/webui", ]
diff --git a/ash/webui/projector_app/mojom/untrusted_projector.mojom b/ash/webui/projector_app/mojom/untrusted_projector.mojom index bc46f083..397b4a9c 100644 --- a/ash/webui/projector_app/mojom/untrusted_projector.mojom +++ b/ash/webui/projector_app/mojom/untrusted_projector.mojom
@@ -5,6 +5,7 @@ import "ash/webui/projector_app/public/mojom/projector_types.mojom"; import "mojo/public/mojom/base/values.mojom"; +import "mojo/public/mojom/base/safe_base_name.mojom"; // UntrustedProjectorPageHandler handles requests that come from the // javascript to the browser process. @@ -37,6 +38,11 @@ // Requested by the Projector SWA to open the Chrome feedback dialog. OpenFeedbackDialog() => (); + + // Requests the handler to start a new projector session. The request will + // fail if the new screencast preconditions are not met. + StartProjectorSession( + mojo_base.mojom.SafeBaseName storage_dir_name) => (bool success); }; // Implemented in Javascript to handle requests from the browser process.
diff --git a/ash/webui/projector_app/projector_message_handler.cc b/ash/webui/projector_app/projector_message_handler.cc index 1d199e75..9142402 100644 --- a/ash/webui/projector_app/projector_message_handler.cc +++ b/ash/webui/projector_app/projector_message_handler.cc
@@ -19,7 +19,6 @@ #include "base/time/time.h" #include "components/signin/public/identity_manager/access_token_info.h" #include "content/public/browser/web_ui.h" -#include "third_party/re2/src/re2/re2.h" #include "url/gurl.h" namespace ash { @@ -43,9 +42,6 @@ constexpr char kNoneStr[] = "NONE"; constexpr char kOtherStr[] = "OTHER"; constexpr char kTokenFetchFailureStr[] = "TOKEN_FETCH_FAILURE"; -// Disallow special chars that potentially allow redirecting writes to -// arbitrary file system locations. -constexpr char kInvalidStorageDirNameRegex[] = "\\.\\.|/|\\\\"; // Struct used to describe args to set user's preference. struct SetUserPrefArgs { @@ -89,11 +85,6 @@ base::Unretained(this))); web_ui()->RegisterMessageCallback( - "startProjectorSession", - base::BindRepeating(&ProjectorMessageHandler::StartProjectorSession, - base::Unretained(this))); - - web_ui()->RegisterMessageCallback( "getOAuthTokenForAccount", base::BindRepeating(&ProjectorMessageHandler::GetOAuthTokenForAccount, base::Unretained(this))); @@ -135,37 +126,6 @@ ResolveJavascriptCallback(args[0], response); } -void ProjectorMessageHandler::StartProjectorSession( - const base::Value::List& args) { - AllowJavascript(); - - // There are two arguments. The first is the callback and the second is a list - // containing the account which we need to start the recording with. - DCHECK_EQ(args.size(), 2u); - - const auto& func_args = args[1]; - DCHECK(func_args.is_list()); - - // The first entry is the drive directory to save the screen cast to. - DCHECK_EQ(func_args.GetList().size(), 1u); - auto storage_dir_name = func_args.GetList()[0].GetString(); - if (RE2::PartialMatch(storage_dir_name, kInvalidStorageDirNameRegex)) { - ResolveJavascriptCallback(args[0], base::Value(false)); - return; - } - - auto* controller = ProjectorController::Get(); - - if (controller->GetNewScreencastPrecondition().state != - NewScreencastPreconditionState::kEnabled) { - ResolveJavascriptCallback(args[0], base::Value(false)); - return; - } - - controller->StartProjectorSession(storage_dir_name); - ResolveJavascriptCallback(args[0], base::Value(true)); -} - void ProjectorMessageHandler::GetOAuthTokenForAccount( const base::Value::List& args) { // Two arguments. The first is callback id, and the second is the list
diff --git a/ash/webui/projector_app/projector_message_handler.h b/ash/webui/projector_app/projector_message_handler.h index 5e7faf9..162ec7c 100644 --- a/ash/webui/projector_app/projector_message_handler.h +++ b/ash/webui/projector_app/projector_message_handler.h
@@ -60,10 +60,6 @@ // used in the account picker in the SWA. void GetAccounts(const base::Value::List& args); - // Requested by the Projector SWA to start a new Projector session if it is - // possible. - void StartProjectorSession(const base::Value::List& args); - // Requested by the Projector SWA to get access to the OAuth token for the // account email provided in the `args`. void GetOAuthTokenForAccount(const base::Value::List& args);
diff --git a/ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js b/ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js index 6859918f..b48578a8 100644 --- a/ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js +++ b/ash/webui/projector_app/resources/app/trusted/projector_browser_proxy.js
@@ -19,15 +19,6 @@ getAccounts() {} /** - * Launches the Projector recording session. Returns true if a projector - * recording session was successfully launched. - * @param {string} storageDir, the directory name in which the screen cast - * will be saved in. - * @return {Promise<boolean>} - */ - startProjectorSession(storageDir) {} - - /** * Gets the oauth token with the required scopes for the specified account. * @param {string} email, user's email. * @return {!Promise<!projectorApp.OAuthToken>} @@ -93,11 +84,6 @@ } /** @override */ - startProjectorSession(storageDir) { - return sendWithPromise('startProjectorSession', [storageDir]); - } - - /** @override */ getOAuthTokenForAccount(email) { return sendWithPromise('getOAuthTokenForAccount', [email]); }
diff --git a/ash/webui/projector_app/resources/app/trusted/trusted_app_comm_factory.js b/ash/webui/projector_app/resources/app/trusted/trusted_app_comm_factory.js index dc0dd2a..6584785 100644 --- a/ash/webui/projector_app/resources/app/trusted/trusted_app_comm_factory.js +++ b/ash/webui/projector_app/resources/app/trusted/trusted_app_comm_factory.js
@@ -48,12 +48,6 @@ this.registerMethod('getAccounts', (args) => { return this.browserProxy_.getAccounts(); }); - this.registerMethod('startProjectorSession', (storageDir) => { - if (!storageDir || storageDir.length != 1) { - return false; - } - return this.browserProxy_.startProjectorSession(storageDir[0]); - }); this.registerMethod('getOAuthTokenForAccount', (args) => { if (!args || args.length != 1) { return Promise.reject('Incorrect args for getOAuthTokenForAccount');
diff --git a/ash/webui/projector_app/resources/app/untrusted/untrusted_app_comm_factory.js b/ash/webui/projector_app/resources/app/untrusted/untrusted_app_comm_factory.js index e55d7575..0c6ffce 100644 --- a/ash/webui/projector_app/resources/app/untrusted/untrusted_app_comm_factory.js +++ b/ash/webui/projector_app/resources/app/untrusted/untrusted_app_comm_factory.js
@@ -83,8 +83,7 @@ * @return {Promise<boolean>} */ startProjectorSession(storageDir) { - return AppUntrustedCommFactory.getPostMessageAPIClient().callApiFn( - 'startProjectorSession', [storageDir]); + return browserProxy.startProjectorSession(storageDir); }, /**
diff --git a/ash/webui/projector_app/resources/app/untrusted/untrusted_projector_browser_proxy.js b/ash/webui/projector_app/resources/app/untrusted/untrusted_projector_browser_proxy.js index 63a5353..9f621a63 100644 --- a/ash/webui/projector_app/resources/app/untrusted/untrusted_projector_browser_proxy.js +++ b/ash/webui/projector_app/resources/app/untrusted/untrusted_projector_browser_proxy.js
@@ -1,7 +1,6 @@ // Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {Value} from '//resources/mojo/mojo/public/mojom/base/values.mojom-webui.js'; import {UntrustedProjectorPageCallbackRouter, UntrustedProjectorPageHandlerFactory, UntrustedProjectorPageHandlerRemote, UntrustedProjectorPageRemote} from './ash/webui/projector_app/mojom/untrusted_projector.mojom-webui.js'; import {PrefsThatProjectorCanAskFor} from './ash/webui/projector_app/public/mojom/projector_types.mojom-webui.js'; @@ -120,6 +119,15 @@ await this.pageHandlerRemote.openFeedbackDialog(); return; } + + async startProjectorSession(storageDir) { + const {success} = await this.pageHandlerRemote.startProjectorSession({ + path: { + path: storageDir, + }, + }); + return success; + } } /**
diff --git a/ash/webui/projector_app/test/projector_message_handler_unittest.cc b/ash/webui/projector_app/test/projector_message_handler_unittest.cc index 13203b70..bf7bb223 100644 --- a/ash/webui/projector_app/test/projector_message_handler_unittest.cc +++ b/ash/webui/projector_app/test/projector_message_handler_unittest.cc
@@ -40,7 +40,6 @@ const char kWebUIResponse[] = "cr.webUIResponse"; const char kGetAccountsCallback[] = "getAccountsCallback"; -const char kStartProjectorSessionCallback[] = "startProjectorSessionCallback"; const char kGetOAuthTokenCallback[] = "getOAuthTokenCallback"; const char kSendXhrCallback[] = "sendXhrCallback"; const char kGetVideoCallback[] = "getVideoCallback"; @@ -434,102 +433,4 @@ EXPECT_EQ(call_data.arg3()->GetString(), "error1"); } -class ProjectorStorageDirNameValidationTest - : public ::testing::WithParamInterface< - ::testing::tuple<::std::string, bool>>, - public ProjectorMessageHandlerUnitTest { - public: - ProjectorStorageDirNameValidationTest() = default; - ProjectorStorageDirNameValidationTest( - const ProjectorStorageDirNameValidationTest&) = delete; - ProjectorStorageDirNameValidationTest& operator=( - const ProjectorStorageDirNameValidationTest&) = delete; - ~ProjectorStorageDirNameValidationTest() override = default; -}; - -TEST_P(ProjectorStorageDirNameValidationTest, StorageDirNameBackSlash) { - bool success = std::get<1>(GetParam()); - if (success) { - EXPECT_CALL(controller(), GetNewScreencastPrecondition()); - ON_CALL(controller(), GetNewScreencastPrecondition) - .WillByDefault(testing::Return(NewScreencastPrecondition( - NewScreencastPreconditionState::kEnabled, {}))); - } - - base::Value::List list_args; - list_args.Append(kStartProjectorSessionCallback); - base::Value::List args; - args.Append(std::get<0>(GetParam())); - list_args.Append(std::move(args)); - - web_ui().HandleReceivedMessage("startProjectorSession", list_args); - - // We expect that there was only one callback to the WebUI. - EXPECT_EQ(web_ui().call_data().size(), 1u); - const content::TestWebUI::CallData& call_data = FetchCallData(0); - - EXPECT_EQ(call_data.function_name(), kWebUIResponse); - EXPECT_EQ(call_data.arg1()->GetString(), kStartProjectorSessionCallback); - EXPECT_TRUE(call_data.arg2()->GetBool()); - - EXPECT_EQ(success, call_data.arg3()->GetBool()); -} - -INSTANTIATE_TEST_SUITE_P( - StorageDirNameBackSlash, - ProjectorStorageDirNameValidationTest, - ::testing::Values(std::make_tuple("Projector recordings", true), - std::make_tuple("..\folderId", false), - std::make_tuple("../folderId", false))); - -class ProjectorSessionStartUnitTest - : public ::testing::WithParamInterface<NewScreencastPrecondition>, - public ProjectorMessageHandlerUnitTest { - public: - ProjectorSessionStartUnitTest() = default; - ProjectorSessionStartUnitTest(const ProjectorSessionStartUnitTest&) = delete; - ProjectorSessionStartUnitTest& operator=( - const ProjectorSessionStartUnitTest&) = delete; - ~ProjectorSessionStartUnitTest() override = default; -}; - -TEST_P(ProjectorSessionStartUnitTest, ProjectorSessionTest) { - const auto& precondition = GetParam(); - EXPECT_CALL(controller(), GetNewScreencastPrecondition()); - ON_CALL(controller(), GetNewScreencastPrecondition) - .WillByDefault(testing::Return(precondition)); - - bool success = precondition.state == NewScreencastPreconditionState::kEnabled; - - EXPECT_CALL(controller(), StartProjectorSession("folderId")) - .Times(success ? 1 : 0); - - base::Value::List list_args; - list_args.Append(kStartProjectorSessionCallback); - base::Value::List args; - args.Append("folderId"); - list_args.Append(std::move(args)); - - web_ui().HandleReceivedMessage("startProjectorSession", list_args); - - // We expect that there was only one callback to the WebUI. - EXPECT_EQ(web_ui().call_data().size(), 1u); - const content::TestWebUI::CallData& call_data = FetchCallData(0); - - EXPECT_EQ(call_data.function_name(), kWebUIResponse); - EXPECT_EQ(call_data.arg1()->GetString(), kStartProjectorSessionCallback); - EXPECT_TRUE(call_data.arg2()->GetBool()); - - EXPECT_EQ(call_data.arg3()->GetBool(), success); -} - -INSTANTIATE_TEST_SUITE_P( - SessionStartSuccessFailTest, - ProjectorSessionStartUnitTest, - ::testing::Values( - NewScreencastPrecondition(NewScreencastPreconditionState::kEnabled, {}), - NewScreencastPrecondition( - NewScreencastPreconditionState::kDisabled, - {NewScreencastPreconditionReason::kInProjectorSession}))); - } // namespace ash
diff --git a/ash/webui/projector_app/test/untrusted_projector_page_handler_impl_unittest.cc b/ash/webui/projector_app/test/untrusted_projector_page_handler_impl_unittest.cc index d18816d1..edaae5e7 100644 --- a/ash/webui/projector_app/test/untrusted_projector_page_handler_impl_unittest.cc +++ b/ash/webui/projector_app/test/untrusted_projector_page_handler_impl_unittest.cc
@@ -10,6 +10,7 @@ #include "ash/webui/projector_app/mojom/untrusted_projector.mojom.h" #include "ash/webui/projector_app/public/mojom/projector_types.mojom.h" #include "ash/webui/projector_app/test/mock_app_client.h" +#include "base/files/safe_base_name.h" #include "base/run_loop.h" #include "base/test/bind.h" #include "base/test/task_environment.h" @@ -247,4 +248,60 @@ EXPECT_TRUE(open_feedback_future.Wait()); } +class ProjectorSessionStartUnitTest + : public ::testing::WithParamInterface<NewScreencastPrecondition>, + public UntrustedProjectorPageHandlerImplUnitTest { + public: + ProjectorSessionStartUnitTest() = default; + ProjectorSessionStartUnitTest(const ProjectorSessionStartUnitTest&) = delete; + ProjectorSessionStartUnitTest& operator=( + const ProjectorSessionStartUnitTest&) = delete; + ~ProjectorSessionStartUnitTest() override = default; +}; + +TEST_P(ProjectorSessionStartUnitTest, ProjectorSessionTest) { + const auto& precondition = GetParam(); + EXPECT_CALL(controller(), GetNewScreencastPrecondition()); + ON_CALL(controller(), GetNewScreencastPrecondition) + .WillByDefault(testing::Return(precondition)); + + bool expected_success = + precondition.state == NewScreencastPreconditionState::kEnabled; + + const auto kFolderId = base::SafeBaseName::Create("folderId").value(); + + EXPECT_CALL(controller(), StartProjectorSession(kFolderId)) + .Times(expected_success ? 1 : 0); + + base::test::TestFuture<bool> start_projector_session_future; + page().page_handler()->StartProjectorSession( + kFolderId, start_projector_session_future.GetCallback()); + EXPECT_EQ(start_projector_session_future.Get(), expected_success); +} + +INSTANTIATE_TEST_SUITE_P( + SessionStartSuccessFailTest, + ProjectorSessionStartUnitTest, + ::testing::Values( + NewScreencastPrecondition(NewScreencastPreconditionState::kEnabled, {}), + NewScreencastPrecondition( + NewScreencastPreconditionState::kDisabled, + {NewScreencastPreconditionReason::kInProjectorSession}))); + +TEST_F(UntrustedProjectorPageHandlerImplUnitTest, SafeBaseNameTest) { + const auto valid_path = base::FilePath("folderName"); + const auto failing_path_1 = base::FilePath("parent1/folderName"); + const auto failing_path_2 = base::FilePath("../folderId"); + const auto failing_path_3 = base::FilePath("../"); + const auto failing_path_4 = base::FilePath("parent1/../../folderName"); + + EXPECT_EQ(base::SafeBaseName::Create(valid_path)->path(), valid_path); + EXPECT_NE(base::SafeBaseName::Create(failing_path_1)->path(), failing_path_1); + EXPECT_NE(base::SafeBaseName::Create(failing_path_2)->path(), failing_path_2); + EXPECT_NE(base::SafeBaseName::Create(failing_path_4)->path(), failing_path_4); + + // The safe base name would not even be created in this instance. + EXPECT_FALSE(base::SafeBaseName::Create(failing_path_3)); +} + } // namespace ash
diff --git a/ash/webui/projector_app/untrusted_projector_page_handler_impl.cc b/ash/webui/projector_app/untrusted_projector_page_handler_impl.cc index 3a5c6e7..7ca2f7b 100644 --- a/ash/webui/projector_app/untrusted_projector_page_handler_impl.cc +++ b/ash/webui/projector_app/untrusted_projector_page_handler_impl.cc
@@ -11,6 +11,7 @@ #include "ash/webui/projector_app/mojom/untrusted_projector.mojom.h" #include "ash/webui/projector_app/projector_app_client.h" #include "ash/webui/projector_app/public/mojom/projector_types.mojom.h" +#include "base/files/safe_base_name.h" #include "components/prefs/pref_service.h" namespace ash { @@ -171,4 +172,20 @@ std::move(callback).Run(); } +void UntrustedProjectorPageHandlerImpl::StartProjectorSession( + const base::SafeBaseName& storage_dir_name, + projector::mojom::UntrustedProjectorPageHandler:: + StartProjectorSessionCallback callback) { + auto* controller = ProjectorController::Get(); + + if (controller->GetNewScreencastPrecondition().state != + NewScreencastPreconditionState::kEnabled) { + std::move(callback).Run(/*success=*/false); + return; + } + + controller->StartProjectorSession(storage_dir_name); + std::move(callback).Run(/*success=*/true); +} + } // namespace ash
diff --git a/ash/webui/projector_app/untrusted_projector_page_handler_impl.h b/ash/webui/projector_app/untrusted_projector_page_handler_impl.h index bae6ed6..2d9438f 100644 --- a/ash/webui/projector_app/untrusted_projector_page_handler_impl.h +++ b/ash/webui/projector_app/untrusted_projector_page_handler_impl.h
@@ -7,6 +7,7 @@ #include "ash/webui/projector_app/mojom/untrusted_projector.mojom.h" #include "ash/webui/projector_app/projector_app_client.h" +#include "base/files/safe_base_name.h" #include "base/memory/raw_ptr.h" #include "components/prefs/pref_service.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -55,6 +56,8 @@ base::Value value, SetUserPrefCallback callback) override; void OpenFeedbackDialog(OpenFeedbackDialogCallback callback) override; + void StartProjectorSession(const base::SafeBaseName& storage_dir_name, + StartProjectorSessionCallback callback) override; private: mojo::Receiver<projector::mojom::UntrustedProjectorPageHandler> receiver_;
diff --git a/ash/wm/desks/cros_next_desk_button_base.cc b/ash/wm/desks/cros_next_desk_button_base.cc index 84b928b..73d7d2a 100644 --- a/ash/wm/desks/cros_next_desk_button_base.cc +++ b/ash/wm/desks/cros_next_desk_button_base.cc
@@ -12,6 +12,7 @@ #include "ui/views/border.h" #include "ui/views/controls/focus_ring.h" #include "ui/views/controls/highlight_path_generator.h" +#include "ui/views/view_utils.h" namespace ash { @@ -53,7 +54,11 @@ views::FocusRing* focus_ring = views::FocusRing::Get(this); focus_ring->SetColorId(ui::kColorAshFocusRing); focus_ring->SetHasFocusPredicate( - [&](views::View* view) { return IsViewHighlighted(); }); + base::BindRepeating([](const views::View* view) { + const auto* v = views::AsViewClass<CrOSNextDeskButtonBase>(view); + CHECK(v); + return v->IsViewHighlighted(); + })); } CrOSNextDeskButtonBase::~CrOSNextDeskButtonBase() = default;
diff --git a/ash/wm/desks/cros_next_desk_icon_button.cc b/ash/wm/desks/cros_next_desk_icon_button.cc index 09719c10..47db15e 100644 --- a/ash/wm/desks/cros_next_desk_icon_button.cc +++ b/ash/wm/desks/cros_next_desk_icon_button.cc
@@ -18,6 +18,7 @@ #include "ash/wm/overview/overview_constants.h" #include "base/check_op.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/metadata/metadata_impl_macros.h" #include "ui/chromeos/styles/cros_tokens_color_mappings.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/insets.h" @@ -25,6 +26,7 @@ #include "ui/views/accessibility/view_accessibility.h" #include "ui/views/background.h" #include "ui/views/controls/highlight_path_generator.h" +#include "ui/views/view_utils.h" namespace ash { @@ -75,13 +77,21 @@ views::InstallRoundRectHighlightPathGenerator( this, gfx::Insets(kFocusRingHaloInset), GetFocusRingRadiusForState(state_)); - views::FocusRing::Get(this)->SetHasFocusPredicate([&](views::View* view) { - if (IsViewHighlighted() || (state_ == State::kActive && paint_as_active_)) { - return true; - } - return state_ == State::kActive && bar_view_->dragged_item_over_bar() && - IsPointOnButton(bar_view_->last_dragged_item_screen_location()); - }); + views::FocusRing::Get(this)->SetHasFocusPredicate( + base::BindRepeating([](const views::View* view) { + const auto* v = views::AsViewClass<CrOSNextDeskIconButton>(view); + CHECK(v); + if (v->IsViewHighlighted()) { + return true; + } + if (v->state_ != State::kActive) { + return false; + } + return v->paint_as_active_ || + (v->bar_view_->dragged_item_over_bar() && + v->IsPointOnButton( + v->bar_view_->last_dragged_item_screen_location())); + })); } CrOSNextDeskIconButton::~CrOSNextDeskIconButton() = default;
diff --git a/ash/wm/desks/cros_next_desk_icon_button.h b/ash/wm/desks/cros_next_desk_icon_button.h index 30f452f..33ec648 100644 --- a/ash/wm/desks/cros_next_desk_icon_button.h +++ b/ash/wm/desks/cros_next_desk_icon_button.h
@@ -8,7 +8,7 @@ #include "ash/ash_export.h" #include "ash/wm/desks/cros_next_desk_button_base.h" #include "base/memory/raw_ptr.h" -#include "ui/base/metadata/metadata_impl_macros.h" +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/color/color_id.h" namespace gfx {
diff --git a/ash/wm/desks/desk_button_base.cc b/ash/wm/desks/desk_button_base.cc index f32ec2e..8427a63 100644 --- a/ash/wm/desks/desk_button_base.cc +++ b/ash/wm/desks/desk_button_base.cc
@@ -16,6 +16,7 @@ #include "ui/views/controls/focus_ring.h" #include "ui/views/controls/highlight_path_generator.h" #include "ui/views/view.h" +#include "ui/views/view_utils.h" namespace ash { @@ -57,7 +58,11 @@ views::FocusRing* focus_ring = views::FocusRing::Get(this); focus_ring->SetColorId(ui::kColorAshFocusRing); focus_ring->SetHasFocusPredicate( - [&](views::View* view) { return IsViewHighlighted(); }); + base::BindRepeating([](const views::View* view) { + const auto* v = views::AsViewClass<DeskButtonBase>(view); + CHECK(v); + return v->IsViewHighlighted(); + })); } DeskButtonBase::~DeskButtonBase() = default;
diff --git a/ash/wm/desks/desk_mini_view.cc b/ash/wm/desks/desk_mini_view.cc index 8839fa5..454bba7 100644 --- a/ash/wm/desks/desk_mini_view.cc +++ b/ash/wm/desks/desk_mini_view.cc
@@ -36,6 +36,7 @@ #include "ui/gfx/geometry/insets.h" #include "ui/views/controls/focus_ring.h" #include "ui/views/controls/highlight_path_generator.h" +#include "ui/views/view_utils.h" #include "ui/views/widget/widget.h" namespace ash { @@ -126,14 +127,21 @@ chromeos::features::IsJellyrollEnabled() ? kPreviewFocusRingRadius : kPreviewFocusRingRadiusOld); - preview_focus_ring->SetHasFocusPredicate([&](views::View* view) { - return (owner_bar_->dragged_item_over_bar() && - IsPointOnMiniView( - owner_bar_->last_dragged_item_screen_location())) || - desk_preview_->IsViewHighlighted() || - (desk_ && desk_->is_active() && owner_bar_->overview_grid() && - !owner_bar_->overview_grid()->IsShowingSavedDeskLibrary()); - }); + preview_focus_ring->SetHasFocusPredicate(base::BindRepeating( + [](const DeskMiniView* mini_view, const views::View* view) { + const auto* desk_preview = views::AsViewClass<DeskPreviewView>(view); + CHECK(desk_preview); + return desk_preview->IsViewHighlighted() || + (mini_view->owner_bar_->dragged_item_over_bar() && + mini_view->IsPointOnMiniView( + mini_view->owner_bar_ + ->last_dragged_item_screen_location())) || + (mini_view->desk_ && mini_view->desk_->is_active() && + mini_view->owner_bar_->overview_grid() && + !mini_view->owner_bar_->overview_grid() + ->IsShowingSavedDeskLibrary()); + }, + base::Unretained(this))); desk_name_view_ = AddChildView(std::move(desk_name_view));
diff --git a/ash/wm/desks/desk_preview_view.cc b/ash/wm/desks/desk_preview_view.cc index 37d9431c..20ef2f4 100644 --- a/ash/wm/desks/desk_preview_view.cc +++ b/ash/wm/desks/desk_preview_view.cc
@@ -36,6 +36,7 @@ #include "chromeos/ui/wm/features.h" #include "ui/accessibility/ax_node_data.h" #include "ui/aura/client/aura_constants.h" +#include "ui/base/metadata/metadata_impl_macros.h" #include "ui/color/color_provider.h" #include "ui/compositor/layer_tree_owner.h" #include "ui/compositor/layer_type.h" @@ -463,10 +464,6 @@ Layout(); } -const char* DeskPreviewView::GetClassName() const { - return "DeskPreviewView"; -} - void DeskPreviewView::GetAccessibleNodeData(ui::AXNodeData* node_data) { // Avoid failing accessibility checks if we don't have a name. views::Button::GetAccessibleNodeData(node_data); @@ -619,4 +616,7 @@ mini_view_->UpdateFocusColor(); } +BEGIN_METADATA(DeskPreviewView, views::Button) +END_METADATA + } // namespace ash
diff --git a/ash/wm/desks/desk_preview_view.h b/ash/wm/desks/desk_preview_view.h index cc007ca..48358f1a0 100644 --- a/ash/wm/desks/desk_preview_view.h +++ b/ash/wm/desks/desk_preview_view.h
@@ -12,6 +12,7 @@ #include "ash/wm/overview/overview_highlightable_view.h" #include "base/memory/raw_ptr.h" #include "ui/aura/window_occlusion_tracker.h" +#include "ui/base/metadata/metadata_header_macros.h" #include "ui/compositor/layer.h" #include "ui/views/controls/button/button.h" @@ -71,6 +72,8 @@ class ASH_EXPORT DeskPreviewView : public views::Button, public OverviewHighlightableView { public: + METADATA_HEADER(DeskPreviewView); + DeskPreviewView(PressedCallback callback, DeskMiniView* mini_view); DeskPreviewView(const DeskPreviewView&) = delete; @@ -103,7 +106,6 @@ void RecreateDeskContentsMirrorLayers(); // views::View: - const char* GetClassName() const override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; void Layout() override; bool OnMousePressed(const ui::MouseEvent& event) override;
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc index a52a762..740dcaa 100644 --- a/ash/wm/desks/desks_unittests.cc +++ b/ash/wm/desks/desks_unittests.cc
@@ -8610,9 +8610,6 @@ // Enter overview and close the desk. EnterOverview(); - // Wait for shelf animation, i.e. the desk button disappears and the - // scrollable shelf view expands to take more space. - WaitForShelfAnimation(); ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); ClickOnCloseAllButtonForDesk(0);
diff --git a/ash/wm/desks/expanded_desks_bar_button.cc b/ash/wm/desks/expanded_desks_bar_button.cc index 05cd3c44..adc9dc9 100644 --- a/ash/wm/desks/expanded_desks_bar_button.cc +++ b/ash/wm/desks/expanded_desks_bar_button.cc
@@ -24,6 +24,7 @@ #include "ui/views/controls/focus_ring.h" #include "ui/views/controls/highlight_path_generator.h" #include "ui/views/controls/label.h" +#include "ui/views/view_utils.h" namespace ash { @@ -135,12 +136,20 @@ views::InstallRoundRectHighlightPathGenerator( inner_button_, gfx::Insets(kFocusRingHaloInset), kBorderCornerRadius); auto* focus_ring = views::FocusRing::Get(inner_button_); - focus_ring->SetHasFocusPredicate([&](views::View* view) { - return inner_button_->IsViewHighlighted() || - ((bar_view_->dragged_item_over_bar() && - IsPointOnButton(bar_view_->last_dragged_item_screen_location())) || - active_); - }); + focus_ring->SetHasFocusPredicate(base::BindRepeating( + [](const ExpandedDesksBarButton* desks_bar_button, + const views::View* view) { + const auto* inner_button = + views::AsViewClass<InnerExpandedDesksBarButton>(view); + CHECK(inner_button); + return inner_button->IsViewHighlighted() || + ((desks_bar_button->bar_view_->dragged_item_over_bar() && + desks_bar_button->IsPointOnButton( + desks_bar_button->bar_view_ + ->last_dragged_item_screen_location())) || + desks_bar_button->active_); + }, + base::Unretained(this))); } DeskButtonBase* ExpandedDesksBarButton::GetInnerButton() {
diff --git a/ash/wm/desks/templates/saved_desk_item_view.cc b/ash/wm/desks/templates/saved_desk_item_view.cc index 02096c7..f025f7b 100644 --- a/ash/wm/desks/templates/saved_desk_item_view.cc +++ b/ash/wm/desks/templates/saved_desk_item_view.cc
@@ -55,6 +55,7 @@ #include "ui/views/metadata/view_factory_internal.h" #include "ui/views/view.h" #include "ui/views/view_class_properties.h" +#include "ui/views/view_utils.h" namespace ash { namespace { @@ -287,9 +288,12 @@ views::FocusRing* focus_ring = StyleUtil::SetUpFocusRingForView(this, kFocusRingHaloInset); - focus_ring->SetHasFocusPredicate([](views::View* view) { - return static_cast<SavedDeskItemView*>(view)->IsViewHighlighted(); - }); + focus_ring->SetHasFocusPredicate( + base::BindRepeating([](const views::View* view) { + const auto* v = views::AsViewClass<SavedDeskItemView>(view); + CHECK(v); + return v->IsViewHighlighted(); + })); focus_ring->SetColorId(cros_tokens::kCrosSysFocusRing); SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
diff --git a/ash/wm/desks/templates/saved_desk_save_desk_button.cc b/ash/wm/desks/templates/saved_desk_save_desk_button.cc index 2d71ae1..65a7c52 100644 --- a/ash/wm/desks/templates/saved_desk_save_desk_button.cc +++ b/ash/wm/desks/templates/saved_desk_save_desk_button.cc
@@ -15,6 +15,7 @@ #include "ui/gfx/vector_icon_types.h" #include "ui/views/controls/focus_ring.h" #include "ui/views/highlight_border.h" +#include "ui/views/view_utils.h" namespace ash { @@ -31,9 +32,12 @@ button_type_(button_type) { views::FocusRing* focus_ring = StyleUtil::SetUpFocusRingForView(this, kFocusRingHaloInset); - focus_ring->SetHasFocusPredicate([](views::View* view) { - return static_cast<SavedDeskSaveDeskButton*>(view)->IsViewHighlighted(); - }); + focus_ring->SetHasFocusPredicate( + base::BindRepeating([](const views::View* view) { + const auto* v = views::AsViewClass<SavedDeskSaveDeskButton>(view); + CHECK(v); + return v->IsViewHighlighted(); + })); focus_ring->SetColorId(ui::kColorAshFocusRing); SetBorder(std::make_unique<views::HighlightBorder>(
diff --git a/ash/wm/overview/overview_highlightable_view.h b/ash/wm/overview/overview_highlightable_view.h index 977c59a..f47efe8 100644 --- a/ash/wm/overview/overview_highlightable_view.h +++ b/ash/wm/overview/overview_highlightable_view.h
@@ -42,7 +42,7 @@ void SetHighlightVisibility(bool visible); // Returns true if this is the current highlighted view. - bool IsViewHighlighted() { return is_highlighted_; } + bool IsViewHighlighted() const { return is_highlighted_; } // Returns the point the accessibility magnifiers should focus when this is // highlighted. If not overridden, this will return the centerpoint.
diff --git a/ash/wm/window_cycle/window_cycle_view.cc b/ash/wm/window_cycle/window_cycle_view.cc index e91d0bd5..23ecbf4c 100644 --- a/ash/wm/window_cycle/window_cycle_view.cc +++ b/ash/wm/window_cycle/window_cycle_view.cc
@@ -185,8 +185,11 @@ // Set a pill shaped (fully rounded rect) highlight path to focus ring. focus_ring->SetPathGenerator( std::make_unique<views::PillHighlightPathGenerator>()); - focus_ring->SetHasFocusPredicate( - [&](views::View* view) { return IsTabSliderFocused(); }); + focus_ring->SetHasFocusPredicate(base::BindRepeating( + [](const WindowCycleView* cycle_view, const views::View* view) { + return cycle_view->IsTabSliderFocused(); + }, + base::Unretained(this))); const bool per_desk = Shell::Get()->window_cycle_controller()->IsAltTabPerActiveDesk();
diff --git a/ash/wm/window_mini_view.cc b/ash/wm/window_mini_view.cc index a55925c..655478d 100644 --- a/ash/wm/window_mini_view.cc +++ b/ash/wm/window_mini_view.cc
@@ -30,6 +30,7 @@ #include "ui/views/layout/box_layout.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/layout/layout_provider.h" +#include "ui/views/view_utils.h" #include "ui/wm/core/window_util.h" namespace ash { @@ -214,7 +215,11 @@ views::FocusRing* focus_ring = views::FocusRing::Get(this); focus_ring->SetColorId(ui::kColorAshFocusRing); focus_ring->SetHasFocusPredicate( - [&](views::View* view) { return is_focused_; }); + base::BindRepeating([](const views::View* view) { + const auto* v = views::AsViewClass<WindowMiniView>(view); + CHECK(v); + return v->is_focused_; + })); } void WindowMiniView::UpdateIconView() {
diff --git a/base/BUILD.gn b/base/BUILD.gn index d5b4aa9a..356e316d 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1203,6 +1203,8 @@ "android/event_log.cc", "android/event_log.h", "android/feature_list_jni.cc", + "android/feature_map.cc", + "android/feature_map.h", "android/features_jni.cc", "android/field_trial_list.cc", "android/important_file_writer_android.cc",
diff --git a/base/android/feature_map.cc b/base/android/feature_map.cc new file mode 100644 index 0000000..129ff299 --- /dev/null +++ b/base/android/feature_map.cc
@@ -0,0 +1,39 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/android/feature_map.h" + +#include <stddef.h> + +#include <memory> +#include <string> + +#include "base/notreached.h" + +namespace base::android { + +std::pair<StringPiece, const Feature*> MakeNameToFeaturePair( + const Feature* feature) { + return std::make_pair(feature->name, feature); +} + +FeatureMap::FeatureMap(std::vector<const Feature*> features_exposed_to_java) { + mapping_ = MakeFlatMap<StringPiece, const Feature*>( + features_exposed_to_java, {}, &MakeNameToFeaturePair); +} + +FeatureMap::~FeatureMap() = default; + +const Feature* FeatureMap::FindFeatureExposedToJava( + const StringPiece& feature_name) { + auto it = mapping_.find(feature_name); + if (it != mapping_.end()) { + return it->second; + } + + NOTREACHED_NORETURN() << "Queried feature cannot be found in FeatureMap: " + << feature_name; +} + +} // namespace base::android
diff --git a/base/android/feature_map.h b/base/android/feature_map.h new file mode 100644 index 0000000..2fb6dc2b --- /dev/null +++ b/base/android/feature_map.h
@@ -0,0 +1,35 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_ANDROID_FEATURE_MAP_H_ +#define BASE_ANDROID_FEATURE_MAP_H_ + +#include "base/base_export.h" +#include "base/containers/flat_map.h" +#include "base/feature_list.h" +#include "base/strings/string_piece_forward.h" + +namespace base::android { + +// A FeatureMap is a mapping from base:Feature's names to a pointer to the +// base:Feature. +// This is necessary because in Java, features flags are identified by the +// feature name, a string, so calls from Java to (for example) check the state +// of a feature flag need to convert the string to a non-owning Feature*. +// Each component should have its own FeatureMap. +class BASE_EXPORT FeatureMap { + public: + explicit FeatureMap(std::vector<const Feature*> featuresExposedToJava); + ~FeatureMap(); + + // Map a |feature_name| to a Feature*. + const Feature* FindFeatureExposedToJava(const StringPiece& feature_name); + + private: + flat_map<StringPiece, const Feature*> mapping_; +}; + +} // namespace base::android + +#endif // BASE_ANDROID_FEATURE_MAP_H_
diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc index 70a0213..62565f1 100644 --- a/base/memory/weak_ptr.cc +++ b/base/memory/weak_ptr.cc
@@ -47,6 +47,11 @@ void WeakReference::Flag::DetachFromSequence() { DETACH_FROM_SEQUENCE(sequence_checker_); } + +void WeakReference::Flag::BindToCurrentSequence() { + DETACH_FROM_SEQUENCE(sequence_checker_); + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +} #endif WeakReference::Flag::~Flag() = default; @@ -96,6 +101,12 @@ flag_ = MakeRefCounted<WeakReference::Flag>(); } +void WeakReferenceOwner::BindToCurrentSequence() { +#if DCHECK_IS_ON() + flag_->BindToCurrentSequence(); +#endif +} + WeakPtrFactoryBase::WeakPtrFactoryBase(uintptr_t ptr) : ptr_(ptr) { DCHECK(ptr_); }
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h index 5e0ef7e..250ba23 100644 --- a/base/memory/weak_ptr.h +++ b/base/memory/weak_ptr.h
@@ -83,9 +83,14 @@ #include "base/memory/ref_counted.h" #include "base/sequence_checker.h" #include "base/synchronization/atomic_flag.h" +#include "base/types/pass_key.h" namespace base { +namespace sequence_manager::internal { +class TaskQueueImpl; +} + template <typename T> class SafeRef; template <typename T> class SupportsWeakPtr; @@ -110,6 +115,7 @@ #if DCHECK_IS_ON() void DetachFromSequence(); + void BindToCurrentSequence(); #endif private: @@ -159,6 +165,7 @@ bool HasRefs() const { return !flag_->HasOneRef(); } void Invalidate(); + void BindToCurrentSequence(); private: scoped_refptr<WeakReference::Flag> flag_; @@ -411,6 +418,14 @@ DCHECK(ptr_); return weak_reference_owner_.HasRefs(); } + + // Rebind the factory to the current sequence. This allows creating a task + // queue and associated weak pointers on a different thread from the one they + // are used on. + void BindToCurrentSequence( + PassKey<sequence_manager::internal::TaskQueueImpl>) { + weak_reference_owner_.BindToCurrentSequence(); + } }; // A class may extend from SupportsWeakPtr to let others take weak pointers to
diff --git a/base/task/sequence_manager/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc index e688f876..7dc05df 100644 --- a/base/task/sequence_manager/sequence_manager_impl.cc +++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -362,6 +362,9 @@ << "Can't register a second SequenceManagerImpl on the same thread."; thread_local_sequence_manager = this; } + for (internal::TaskQueueImpl* queue : main_thread_only().active_queues) { + queue->CompleteInitializationOnBoundThread(); + } } void SequenceManagerImpl::SetTimeDomain(TimeDomain* time_domain) {
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc index f37789f6..4c614ec 100644 --- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc +++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -5599,6 +5599,41 @@ sequence_manager.reset(); } +TEST(SequenceManagerTest, BindOnDifferentThreadWithActiveVoters) { + auto sequence_manager = CreateUnboundSequenceManager(); + auto queue = + sequence_manager->CreateTaskQueue(TaskQueue::Spec(QueueName::TEST_TQ)); + auto voter = queue->CreateQueueEnabledVoter(); + { + // Create a second voter that gets destroyed while unbound. + auto voter2 = queue->CreateQueueEnabledVoter(); + } + + voter->SetVoteToEnable(false); + EXPECT_FALSE(queue->IsQueueEnabled()); + + std::vector<bool> results; + WaitableEvent done_event; + Thread thread("TestThread"); + thread.Start(); + auto task = BindLambdaForTesting([&]() { + // Move `voter` so it gets destroyed on the bound thread. + auto scoped_voter = std::move(voter); + // Bind `sequence_manager` to this thread. + auto scoped_mgr = std::move(sequence_manager); + scoped_mgr->BindToCurrentThread(); + + results.push_back(queue->IsQueueEnabled()); + scoped_voter->SetVoteToEnable(true); + results.push_back(queue->IsQueueEnabled()); + done_event.Signal(); + }); + thread.task_runner()->PostTask(FROM_HERE, std::move(task)); + done_event.Wait(); + thread.Stop(); + EXPECT_THAT(results, ElementsAre(false, true)); +} + } // namespace internal } // namespace sequence_manager } // namespace base
diff --git a/base/task/sequence_manager/task_queue.cc b/base/task/sequence_manager/task_queue.cc index 15a6104..c83dfb9 100644 --- a/base/task/sequence_manager/task_queue.cc +++ b/base/task/sequence_manager/task_queue.cc
@@ -21,69 +21,25 @@ namespace sequence_manager { TaskQueue::QueueEnabledVoter::QueueEnabledVoter( - scoped_refptr<TaskQueue> task_queue) - : task_queue_(std::move(task_queue)), enabled_(true) { - task_queue_->AddQueueEnabledVoter(enabled_); + WeakPtr<internal::TaskQueueImpl> task_queue) + : task_queue_(std::move(task_queue)) { + task_queue_->AddQueueEnabledVoter(enabled_, *this); } TaskQueue::QueueEnabledVoter::~QueueEnabledVoter() { - task_queue_->RemoveQueueEnabledVoter(enabled_); + if (task_queue_) { + task_queue_->RemoveQueueEnabledVoter(enabled_, *this); + } } void TaskQueue::QueueEnabledVoter::SetVoteToEnable(bool enabled) { - if (enabled == enabled_) + if (enabled == enabled_) { return; + } enabled_ = enabled; - task_queue_->OnQueueEnabledVoteChanged(enabled_); -} - -void TaskQueue::AddQueueEnabledVoter(bool voter_is_enabled) { - DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); - ++voter_count_; - if (voter_is_enabled) - ++enabled_voter_count_; -} - -void TaskQueue::RemoveQueueEnabledVoter(bool voter_is_enabled) { - DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); - // Voters and task queues are often stored in pairs, and the voter is often - // destroyed after the queue is shut down. - if (!impl_) { - return; + if (task_queue_) { + task_queue_->OnQueueEnabledVoteChanged(enabled_); } - - bool was_enabled = AreAllQueueEnabledVotersEnabled(); - if (voter_is_enabled) { - --enabled_voter_count_; - DCHECK_GE(enabled_voter_count_, 0); - } - - --voter_count_; - DCHECK_GE(voter_count_, 0); - - bool is_enabled = AreAllQueueEnabledVotersEnabled(); - if (was_enabled != is_enabled) - impl_->SetQueueEnabled(is_enabled); -} - -bool TaskQueue::AreAllQueueEnabledVotersEnabled() const { - return enabled_voter_count_ == voter_count_; -} - -void TaskQueue::OnQueueEnabledVoteChanged(bool enabled) { - DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); - bool was_enabled = AreAllQueueEnabledVotersEnabled(); - if (enabled) { - ++enabled_voter_count_; - DCHECK_LE(enabled_voter_count_, voter_count_); - } else { - --enabled_voter_count_; - DCHECK_GE(enabled_voter_count_, 0); - } - - bool is_enabled = AreAllQueueEnabledVotersEnabled(); - if (was_enabled != is_enabled) - impl_->SetQueueEnabled(is_enabled); } TaskQueue::TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl, @@ -165,7 +121,7 @@ TaskQueue::CreateQueueEnabledVoter() { DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); DCHECK(impl_); - return WrapUnique(new QueueEnabledVoter(this)); + return impl_->CreateQueueEnabledVoter(); } bool TaskQueue::IsQueueEnabled() const {
diff --git a/base/task/sequence_manager/task_queue.h b/base/task/sequence_manager/task_queue.h index e95caaa..380919c 100644 --- a/base/task/sequence_manager/task_queue.h +++ b/base/task/sequence_manager/task_queue.h
@@ -225,7 +225,7 @@ // Votes to enable or disable the associated TaskQueue. The TaskQueue will // only be enabled if all the voters agree it should be enabled, or if there - // are no voters. + // are no voters. Voters don't keep the queue alive. // NOTE this must be called on the thread the associated TaskQueue was // created on. void SetVoteToEnable(bool enabled); @@ -233,11 +233,11 @@ bool IsVotingToEnable() const { return enabled_; } private: - friend class TaskQueue; - explicit QueueEnabledVoter(scoped_refptr<TaskQueue> task_queue); + friend class internal::TaskQueueImpl; + explicit QueueEnabledVoter(WeakPtr<internal::TaskQueueImpl> task_queue); - scoped_refptr<TaskQueue> const task_queue_; - bool enabled_; + WeakPtr<internal::TaskQueueImpl> task_queue_; + bool enabled_ = true; }; // Returns an interface that allows the caller to vote on whether or not this @@ -433,11 +433,6 @@ friend class internal::SequenceManagerImpl; friend class internal::TaskQueueImpl; - void AddQueueEnabledVoter(bool voter_is_enabled); - void RemoveQueueEnabledVoter(bool voter_is_enabled); - bool AreAllQueueEnabledVotersEnabled() const; - void OnQueueEnabledVoteChanged(bool enabled); - bool IsOnMainThread() const; // Shuts down the queue when there are no more tasks queued. @@ -463,8 +458,6 @@ const scoped_refptr<const internal::AssociatedThreadId> associated_thread_; const scoped_refptr<SingleThreadTaskRunner> default_task_runner_; - int enabled_voter_count_ = 0; - int voter_count_ = 0; QueueName name_; base::WeakPtrFactory<TaskQueue> weak_ptr_factory_{this};
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc index 457d611e..3d81db3 100644 --- a/base/task/sequence_manager/task_queue_impl.cc +++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -34,6 +34,7 @@ #include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "base/trace_event/base_tracing.h" +#include "base/types/pass_key.h" #include "build/build_config.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -273,6 +274,9 @@ void TaskQueueImpl::UnregisterTaskQueue() { TRACE_EVENT0("base", "TaskQueueImpl::UnregisterTaskQueue"); + // Invalidate weak pointers now so no voters reference this in a partially + // torn down state. + voter_weak_ptr_factory_.InvalidateWeakPtrs(); // Detach task runners. { ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait; @@ -1489,6 +1493,60 @@ } } +std::unique_ptr<TaskQueue::QueueEnabledVoter> +TaskQueueImpl::CreateQueueEnabledVoter() { + DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); + return WrapUnique( + new TaskQueue::QueueEnabledVoter(voter_weak_ptr_factory_.GetWeakPtr())); +} + +void TaskQueueImpl::AddQueueEnabledVoter(bool voter_is_enabled, + TaskQueue::QueueEnabledVoter& voter) { + ++main_thread_only().voter_count; + if (voter_is_enabled) { + ++main_thread_only().enabled_voter_count; + } +} + +void TaskQueueImpl::RemoveQueueEnabledVoter( + bool voter_is_enabled, + TaskQueue::QueueEnabledVoter& voter) { + bool was_enabled = AreAllQueueEnabledVotersEnabled(); + if (voter_is_enabled) { + --main_thread_only().enabled_voter_count; + DCHECK_GE(main_thread_only().enabled_voter_count, 0); + } + + --main_thread_only().voter_count; + DCHECK_GE(main_thread_only().voter_count, 0); + + bool is_enabled = AreAllQueueEnabledVotersEnabled(); + if (was_enabled != is_enabled) { + SetQueueEnabled(is_enabled); + } +} + +void TaskQueueImpl::OnQueueEnabledVoteChanged(bool enabled) { + bool was_enabled = AreAllQueueEnabledVotersEnabled(); + if (enabled) { + ++main_thread_only().enabled_voter_count; + DCHECK_LE(main_thread_only().enabled_voter_count, + main_thread_only().voter_count); + } else { + --main_thread_only().enabled_voter_count; + DCHECK_GE(main_thread_only().enabled_voter_count, 0); + } + + bool is_enabled = AreAllQueueEnabledVotersEnabled(); + if (was_enabled != is_enabled) { + SetQueueEnabled(is_enabled); + } +} + +void TaskQueueImpl::CompleteInitializationOnBoundThread() { + voter_weak_ptr_factory_.BindToCurrentSequence(PassKey<TaskQueueImpl>()); +} + TaskQueueImpl::DelayedIncomingQueue::DelayedIncomingQueue() = default; TaskQueueImpl::DelayedIncomingQueue::~DelayedIncomingQueue() = default;
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h index d6cdb83..75501af7 100644 --- a/base/task/sequence_manager/task_queue_impl.h +++ b/base/task/sequence_manager/task_queue_impl.h
@@ -149,6 +149,7 @@ bool BlockedByFence() const; void SetThrottler(TaskQueue::Throttler* throttler); void ResetThrottler(); + std::unique_ptr<TaskQueue::QueueEnabledVoter> CreateQueueEnabledVoter(); void UnregisterTaskQueue(); @@ -287,6 +288,15 @@ // policies enforced by the Throttler. void UpdateWakeUp(LazyNow* lazy_now); + void AddQueueEnabledVoter(bool voter_is_enabled, + TaskQueue::QueueEnabledVoter& voter); + void RemoveQueueEnabledVoter(bool voter_is_enabled, + TaskQueue::QueueEnabledVoter& voter); + void OnQueueEnabledVoteChanged(bool enabled); + + // Called by the associated sequence manager when it becomes bound. + void CompleteInitializationOnBoundThread(); + protected: // Sets this queue's next wake up time to |wake_up| in the time domain. void SetNextWakeUp(LazyNow* lazy_now, absl::optional<WakeUp> wake_up); @@ -479,6 +489,9 @@ // Whether or not the task queue should emit tracing events for tasks // posted to this queue when it is disabled. bool should_report_posted_tasks_when_disabled = false; + + int enabled_voter_count = 0; + int voter_count = 0; }; void PostTask(PostedTask task); @@ -551,6 +564,11 @@ TaskQueue::QueuePriority DefaultPriority() const; + bool AreAllQueueEnabledVotersEnabled() const { + return main_thread_only().enabled_voter_count == + main_thread_only().voter_count; + } + QueueName name_; const raw_ptr<SequenceManagerImpl, DanglingUntriaged> sequence_manager_; @@ -619,6 +637,8 @@ const bool should_monitor_quiescence_; const bool should_notify_observers_; const bool delayed_fence_allowed_; + + base::WeakPtrFactory<TaskQueueImpl> voter_weak_ptr_factory_{this}; }; } // namespace sequence_manager::internal
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc index 5e08929..adb9d96 100644 --- a/base/threading/platform_thread_unittest.cc +++ b/base/threading/platform_thread_unittest.cc
@@ -501,15 +501,9 @@ #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) TestPriorityResultingFromThreadType(ThreadType::kCompositing, ThreadPriorityForTest::kDisplay); -#if BUILDFLAG(IS_WIN) - TestPriorityResultingFromThreadType(ThreadType::kCompositing, - MessagePumpType::UI, - ThreadPriorityForTest::kNormal); -#else TestPriorityResultingFromThreadType(ThreadType::kCompositing, MessagePumpType::UI, ThreadPriorityForTest::kDisplay); -#endif // BUILDFLAG(IS_WIN) TestPriorityResultingFromThreadType(ThreadType::kCompositing, MessagePumpType::IO, ThreadPriorityForTest::kDisplay);
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc index e41758d..eb98c65 100644 --- a/base/threading/platform_thread_win.cc +++ b/base/threading/platform_thread_win.cc
@@ -43,7 +43,7 @@ base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kAboveNormalCompositingBrowserWin, "AboveNormalCompositingBrowserWin", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); namespace { @@ -52,7 +52,7 @@ std::atomic<bool> g_use_thread_priority_lowest{false}; // Flag used to map Compositing ThreadType |THREAD_PRIORITY_ABOVE_NORMAL| on the // UI thread for |kAboveNormalCompositingBrowserWin| Feature. -std::atomic<bool> g_above_normal_compositing_browser{false}; +std::atomic<bool> g_above_normal_compositing_browser{true}; // These values are sometimes returned by ::GetThreadPriority(). constexpr int kWinDisplayPriority1 = 5;
diff --git a/build/config/rust.gni b/build/config/rust.gni index c226e5fe..62052e74 100644 --- a/build/config/rust.gni +++ b/build/config/rust.gni
@@ -20,10 +20,9 @@ # TODO(crbug.com/1386212): Mac # TODO(crbug.com/1271215): Windows # TODO(crbug.com/1442491): Fuchsia - # TODO(crbug.com/1426472): use_clang_coverage # TODO(crbug.com/1229419): is_official_build enable_rust = !is_mac && !is_ios && !is_win && !is_fuchsia && - !is_official_build && !use_clang_coverage && build_with_chromium + !is_official_build && build_with_chromium # As we incrementally enable Rust on mainstream builders, we want to enable # the toolchain (by switching 'enable_rust' to true) while still disabling @@ -95,7 +94,7 @@ enable_rust_mojo = enable_all_rust_features # Support for the 'gnrt' Rust tool. - enable_rust_gnrt = enable_all_rust_features + enable_rust_gnrt = host_toolchain == current_toolchain # Rust gtest interop enable_rust_gtest_interop = enable_all_rust_features
diff --git a/build/rust/cargo_crate.gni b/build/rust/cargo_crate.gni index a376029c..5a25ab4 100644 --- a/build/rust/cargo_crate.gni +++ b/build/rust/cargo_crate.gni
@@ -375,7 +375,21 @@ "edition", "rustflags", ]) - configs -= [ "//build/config/compiler:chromium_code" ] + configs -= [ + "//build/config/compiler:chromium_code", + + # Avoid generating profiling data for build scripts. + # + # TODO(crbug.com/1426472): determine for sure whether to remove this + # config. I'm not sure of the overlap between PGO instrumentation and + # code coverage instrumentation, but we definitely don't want build + # script coverage for PGO, while we might for test coverage metrics. + # + # If we do include build script output in test metrics, it could be + # misleading: exercising some code from a build script doesn't give us + # the same signal as an actual test. + "//build/config/coverage:default_coverage", + ] configs += [ "//build/config/compiler:no_chromium_code" ] } } else {
diff --git a/cc/animation/keyframe_effect.cc b/cc/animation/keyframe_effect.cc index 35dc03b78..93cd301d 100644 --- a/cc/animation/keyframe_effect.cc +++ b/cc/animation/keyframe_effect.cc
@@ -228,6 +228,13 @@ })); } + // For a scroll timeline, we want KeyframeModel::CalculatePhase to return + // Phase::ACTIVE (and not Phase::AFTER) when we have scrolled to the maximum + // position. This differs from the behavior of time-linked animations. + if (animation_->IsScrollLinkedAnimation()) { + keyframe_model->set_active_at_boundary(true); + } + gfx::KeyframeEffect::AddKeyframeModel(std::move(keyframe_model)); if (has_bound_element_animations()) {
diff --git a/cc/animation/keyframe_model.cc b/cc/animation/keyframe_model.cc index 32301d74..16a32a3 100644 --- a/cc/animation/keyframe_model.cc +++ b/cc/animation/keyframe_model.cc
@@ -100,6 +100,7 @@ to_return->set_direction(direction()); to_return->set_playback_rate(playback_rate()); to_return->set_fill_mode(fill_mode()); + to_return->set_active_at_boundary(active_at_boundary()); DCHECK(!to_return->is_controlling_instance_); to_return->is_controlling_instance_ = true; #if DCHECK_IS_ON()
diff --git a/cc/animation/scroll_timeline.cc b/cc/animation/scroll_timeline.cc index 98b0e15..158321a 100644 --- a/cc/animation/scroll_timeline.cc +++ b/cc/animation/scroll_timeline.cc
@@ -126,8 +126,12 @@ end_offset == start_offset ? 1 : (current_offset - start_offset) / (end_offset - start_offset); - return base::TimeTicks() + - base::Milliseconds(progress * kScrollTimelineDurationMs); + + // Round to nearest microsecond for integer-backed TimeTicks + // (compare blink::TimeTolerance). + int64_t progress_us = + base::ClampRound(progress * kScrollTimelineDurationMs * 1000); + return base::TimeTicks() + base::Microseconds(progress_us); } void ScrollTimeline::PushPropertiesTo(AnimationTimeline* impl_timeline) {
diff --git a/chrome/VERSION b/chrome/VERSION index c4926e7..3d332d31 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=115 MINOR=0 -BUILD=5763 +BUILD=5764 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 720e1cbf..e195a2da 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -404,9 +404,6 @@ "//chrome/browser/user_education:java", "//chrome/browser/util:java", "//chrome/browser/version:java", - "//chrome/browser/video_tutorials:factory_java", - "//chrome/browser/video_tutorials:java", - "//chrome/browser/video_tutorials:java_resources", "//chrome/browser/webapps/android:java", "//chrome/browser/webauthn/android:java", "//chrome/browser/xsurface:java", @@ -761,7 +758,6 @@ "//chrome/browser/ui/android/edge_to_edge/internal:java", "//chrome/browser/ui/android/fast_checkout/internal:java", "//chrome/browser/ui/android/webid/internal:java", - "//chrome/browser/video_tutorials/internal:java", "//components/browser_ui/bottomsheet/android/internal:java", "//components/messages/android/internal:java", "//components/segmentation_platform/internal:internal_java", @@ -1012,10 +1008,6 @@ "//chrome/browser/util:java", "//chrome/browser/util:junit_tests", "//chrome/browser/version:java", - "//chrome/browser/video_tutorials:factory_java", - "//chrome/browser/video_tutorials:java", - "//chrome/browser/video_tutorials:test_support_java", - "//chrome/browser/video_tutorials/internal:junit", "//chrome/browser/webapps/android:java", "//chrome/browser/xsurface:java", "//chrome/test:sync_integration_test_support_java", @@ -1572,7 +1564,6 @@ "//chrome/browser/ui/messages/android:java", "//chrome/browser/uid/android:java", "//chrome/browser/util:java", - "//chrome/browser/video_tutorials:test_support_java", "//chrome/browser/webapps/android:java", "//chrome/test:sync_integration_test_support_java", "//chrome/test:test_support_java", @@ -2639,7 +2630,6 @@ "//chrome/browser/ui/android/searchactivityutils:unit_device_javatests", "//chrome/browser/ui/android/signin:unit_device_javatests", "//chrome/browser/ui/messages/android:unit_device_javatests", - "//chrome/browser/video_tutorials/internal:unit_device_javatests", "//components/browser_ui/bottomsheet/android/internal:unit_device_javatests", "//components/browser_ui/contacts_picker/android:unit_device_javatests", "//components/browser_ui/modaldialog/android:unit_device_javatests", @@ -3239,7 +3229,6 @@ "java/src/org/chromium/chrome/browser/announcement/AnnouncementNotificationManager.java", "java/src/org/chromium/chrome/browser/app/send_tab_to_self/SendTabToSelfNotificationReceiver.java", "java/src/org/chromium/chrome/browser/app/tab_activity_glue/ReparentingTask.java", - "java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialsServiceUtils.java", "java/src/org/chromium/chrome/browser/autofill/AutofillAccessibilityUtils.java", "java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowBridge.java", "java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java",
diff --git a/chrome/android/baseline_profiles/profile.txt b/chrome/android/baseline_profiles/profile.txt index b220380..d6d59ba 100644 --- a/chrome/android/baseline_profiles/profile.txt +++ b/chrome/android/baseline_profiles/profile.txt
@@ -7334,9 +7334,6 @@ HSPLorg/chromium/chrome/browser/util/ChromeAccessibilityUtil$ActivityStateListenerImpl;->onActivityStateChange(Landroid/app/Activity;I)V Lorg/chromium/chrome/browser/util/ChromeFileProvider; HSPLorg/chromium/chrome/browser/util/ChromeFileProvider;-><init>()V -Lorg/chromium/chrome/browser/video_tutorials/VideoTutorialServiceFactory$LazyHolder; -Lorg/chromium/chrome/browser/video_tutorials/iph/TryNowTrackerImpl; -HSPLorg/chromium/chrome/browser/video_tutorials/iph/TryNowTrackerImpl;-><init>()V Lorg/chromium/chrome/browser/vr/VrDelegate; HSPLorg/chromium/chrome/browser/vr/VrDelegate;-><init>()V Lorg/chromium/chrome/browser/vr/VrDelegateFallback; @@ -9791,4 +9788,4 @@ HSPLorg/chromium/url/Parsed;-><init>(IIIIIIIIIIIIIIIIZLorg/chromium/url/Parsed;)V HSPLorg/chromium/url/Parsed;->deserialize(I[Ljava/lang/String;)Lorg/chromium/url/Parsed; HSPLorg/chromium/url/Parsed;->serialize()Ljava/lang/String; -HSPLorg/chromium/url/Parsed;->toNativeParsed()J \ No newline at end of file +HSPLorg/chromium/url/Parsed;->toNativeParsed()J
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni index 1fed0f7..e6e5538 100644 --- a/chrome/android/chrome_java_resources.gni +++ b/chrome/android/chrome_java_resources.gni
@@ -476,7 +476,7 @@ "java/res/layout/autofill_server_data_label.xml", "java/res/layout/autofill_server_data_text_label.xml", "java/res/layout/autofill_update_address_profile_prompt.xml", - "java/res/layout/automotive_back_button_toolbar.xml", + "java/res/layout/automotive_layout_with_back_button_toolbar.xml", "java/res/layout/bookmark_edit.xml", "java/res/layout/bookmark_folder_select_activity.xml", "java/res/layout/bookmark_main.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index d66c020..05103a64 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -113,12 +113,6 @@ "java/src/org/chromium/chrome/browser/app/tabmodel/TabWindowManagerSingleton.java", "java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java", "java/src/org/chromium/chrome/browser/app/usb/UsbNotificationServiceImpl.java", - "java/src/org/chromium/chrome/browser/app/video_tutorials/ChromeLanguageInfoProvider.java", - "java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java", - "java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java", - "java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialListActivity.java", - "java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialShareHelper.java", - "java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialsServiceUtils.java", "java/src/org/chromium/chrome/browser/autofill/AutofillAccessibilityUtils.java", "java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowBridge.java", "java/src/org/chromium/chrome/browser/autofill/AutofillExpirationDateFixFlowPrompt.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni index 18e19b7..8699e45 100644 --- a/chrome/android/chrome_junit_test_java_sources.gni +++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -29,7 +29,6 @@ "junit/src/org/chromium/chrome/browser/app/tab_activity_glue/TabReparentingControllerTest.java", "junit/src/org/chromium/chrome/browser/app/tabmodel/TabPersistentStoreIntegrationTest.java", "junit/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestratorUnitTest.java", - "junit/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManagerTest.java", "junit/src/org/chromium/chrome/browser/autofill/AutofillSuggestionTest.java", "junit/src/org/chromium/chrome/browser/autofill/AutofillUiUtilsTest.java", "junit/src/org/chromium/chrome/browser/autofill/SaveUpdateAddressProfilePromptTest.java",
diff --git a/chrome/android/expectations/lint-baseline.xml b/chrome/android/expectations/lint-baseline.xml index 09ddfcb..31f1f59 100644 --- a/chrome/android/expectations/lint-baseline.xml +++ b/chrome/android/expectations/lint-baseline.xml
@@ -4969,39 +4969,6 @@ <issue id="WrongConstant" - message="Must be one of: UserAction.CHANGE_LANGUAGE, UserAction.WATCH_NEXT_VIDEO, UserAction.TRY_NOW, UserAction.SHARE, UserAction.CLOSE, UserAction.BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER, UserAction.OPEN_SHARED_VIDEO, UserAction.INVALID_SHARE_URL, UserAction.IPH_NTP_SHOWN, UserAction.IPH_NTP_CLICKED, UserAction.IPH_NTP_DISMISSED, UserAction.PLAYED_FROM_RECAP" - errorLine1=" UserAction.NUM_ENTRIES);" - errorLine2=" ~~~~~~~~~~~"> - <location - file="../../chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java" - line="74" - column="28"/> - </issue> - - <issue - id="WrongConstant" - message="Must be one of: WatchState.STARTED, WatchState.COMPLETED, WatchState.PAUSED, WatchState.RESUMED, WatchState.WATCHED" - errorLine1=" WatchState.NUM_ENTRIES);" - errorLine2=" ~~~~~~~~~~~"> - <location - file="../../chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java" - line="86" - column="28"/> - </issue> - - <issue - id="WrongConstant" - message="Must be one of: LanguagePickerAction.BACK_PRESS, LanguagePickerAction.CLOSE, LanguagePickerAction.WATCH" - errorLine1=" "VideoTutorials.LanguagePicker.Action", action, LanguagePickerAction.NUM_ENTRIES);" - errorLine2=" ~~~~~~~~~~~"> - <location - file="../../chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java" - line="92" - column="86"/> - </issue> - - <issue - id="WrongConstant" message="Must be one of: VoiceInteractionSource.OMNIBOX, VoiceInteractionSource.NTP, VoiceInteractionSource.SEARCH_WIDGET, VoiceInteractionSource.TASKS_SURFACE, VoiceInteractionSource.TOOLBAR" errorLine1=" "VoiceInteraction.StartEventSource", source, VoiceInteractionSource.NUM_ENTRIES);" errorLine2=" ~~~~~~~~~~~">
diff --git a/chrome/android/expectations/lint-suppressions.xml b/chrome/android/expectations/lint-suppressions.xml index 345ea020..83f7680 100644 --- a/chrome/android/expectations/lint-suppressions.xml +++ b/chrome/android/expectations/lint-suppressions.xml
@@ -154,26 +154,6 @@ <ignore regexp="The resource `R.string.tab_suggestion_review_button` appears to be unused"/> <!-- crbug.com/1117145 remove this line and the following 23 lines after the bug is resolved --> <ignore regexp="The resource `R.layout.language_picker` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_accessibility_close` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_accessibility_share` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_card_all_videos` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_card_chrome_intro` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_card_download` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_card_search` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_card_voice_search` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_change_language` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_iph_tap_here_to_start` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_iph_tap_voice_icon_to_start` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_language_picker_title` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_learn_chrome` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_popular_videos` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_tile_chrome_intro` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_tile_download` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_tile_search` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_tile_voice_search` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_try_now` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_watch` appears to be unused"/> - <ignore regexp="The resource `R.string.video_tutorials_watch_next_video` appears to be unused"/> <!-- crbug.com/1076538 remove this line and the following two lines after the bug is resolved --> <ignore regexp="The resource `R.string.accessibility_tab_suggestion_group_tabs_message` appears to be unused"/> <ignore regexp="The resource `R.string.tab_suggestion_group_tabs_message` appears to be unused"/>
diff --git a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected index 06b1a6d5..c5007e8 100644 --- a/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected +++ b/chrome/android/expectations/monochrome_public_bundle__chrome.AndroidManifest.expected
@@ -152,19 +152,6 @@ android:taskAffinity="" android:theme="@style/Theme.BrowserUI.Translucent"> </activity> # DIFF-ANCHOR: 50c7105b - <activity # DIFF-ANCHOR: aeab60ac - android:name="org.chromium.chrome.browser.app.video_tutorials.VideoPlayerActivity" - android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" - android:exported="false" - android:screenOrientation="portrait" - android:theme="@style/Theme.Chromium.Activity.Fullscreen"> - </activity> # DIFF-ANCHOR: aeab60ac - <activity # DIFF-ANCHOR: 170e9f21 - android:name="org.chromium.chrome.browser.app.video_tutorials.VideoTutorialListActivity" - android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" - android:exported="false" - android:theme="@style/Theme.Chromium.Activity.Fullscreen"> - </activity> # DIFF-ANCHOR: 170e9f21 <activity # DIFF-ANCHOR: be2dce69 android:name="org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProxy" android:excludeFromRecents="true"
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java index cbeed46e..3e03b5e 100644 --- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java +++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/CreditCardAccessorySheetViewTest.java
@@ -164,7 +164,11 @@ assertThat(getChipText(R.id.cardholder), is("Kirby Puckett")); // Verify that the icon is correctly set. ImageView iconImageView = (ImageView) mView.get().getChildAt(0).findViewById(R.id.icon); - Drawable expectedIcon = mActivityTestRule.getActivity().getDrawable(R.drawable.visa_card); + Drawable expectedIcon = + ChromeFeatureList.isEnabled( + ChromeFeatureList.AUTOFILL_ENABLE_NEW_CARD_ART_AND_NETWORK_IMAGES) + ? mActivityTestRule.getActivity().getDrawable(R.drawable.visa_metadata_card) + : mActivityTestRule.getActivity().getDrawable(R.drawable.visa_card); assertTrue(getBitmap(expectedIcon).sameAs(getBitmap(iconImageView.getDrawable()))); // Chips are clickable: TestThreadUtils.runOnUiThreadBlocking(findChipView(R.id.cc_number)::performClick); @@ -244,7 +248,11 @@ assertThat(getChipText(R.id.cardholder), is("Kirby Puckett")); // Verify that the icon is set to the drawable corresponding to `visaCC`. ImageView iconImageView = (ImageView) mView.get().getChildAt(0).findViewById(R.id.icon); - Drawable expectedIcon = mActivityTestRule.getActivity().getDrawable(R.drawable.visa_card); + Drawable expectedIcon = + ChromeFeatureList.isEnabled( + ChromeFeatureList.AUTOFILL_ENABLE_NEW_CARD_ART_AND_NETWORK_IMAGES) + ? mActivityTestRule.getActivity().getDrawable(R.drawable.visa_metadata_card) + : mActivityTestRule.getActivity().getDrawable(R.drawable.visa_card); assertTrue(getBitmap(expectedIcon).sameAs(getBitmap(iconImageView.getDrawable()))); }
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 e69254fd..ddd53c7d 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
@@ -277,13 +277,13 @@ MultiThumbnailCardProvider(Context context, TabContentManager tabContentManager, TabModelSelector tabModelSelector) { mContext = context; - Resources resource = context.getResources(); + Resources resources = context.getResources(); mTabContentManager = tabContentManager; mTabModelSelector = tabModelSelector; - mRadius = resource.getDimension(R.dimen.tab_list_mini_card_radius); + mRadius = resources.getDimension(R.dimen.tab_list_mini_card_radius); mFaviconFrameCornerRadius = - resource.getDimension(R.dimen.tab_grid_thumbnail_favicon_frame_corner_radius); + resources.getDimension(R.dimen.tab_grid_thumbnail_favicon_frame_corner_radius); mTabListFaviconProvider = new TabListFaviconProvider(context, false); @@ -306,14 +306,14 @@ mThumbnailFramePaint = new Paint(); mThumbnailFramePaint.setStyle(Paint.Style.STROKE); mThumbnailFramePaint.setStrokeWidth( - resource.getDimension(R.dimen.tab_list_mini_card_frame_size)); + resources.getDimension(R.dimen.tab_list_mini_card_frame_size)); mThumbnailFramePaint.setColor(SemanticColorUtils.getDividerLineBgColor(context)); mThumbnailFramePaint.setAntiAlias(true); // TODO(996048): Use pre-defined styles to avoid style out of sync if any text/color styles // changes. mTextPaint = new Paint(); - mTextPaint.setTextSize(resource.getDimension(R.dimen.compositor_tab_title_text_size)); + mTextPaint.setTextSize(resources.getDimension(R.dimen.compositor_tab_title_text_size)); mTextPaint.setFakeBoldText(true); mTextPaint.setAntiAlias(true); mTextPaint.setTextAlign(Paint.Align.CENTER); @@ -329,9 +329,9 @@ mFaviconBackgroundPaint.setColor(mFaviconBackgroundPaintColor); mFaviconBackgroundPaint.setStyle(Paint.Style.FILL); mFaviconBackgroundPaint.setShadowLayer( - 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)); + resources.getDimension(R.dimen.tab_grid_thumbnail_favicon_background_radius), 0, + resources.getDimension(R.dimen.tab_grid_thumbnail_favicon_background_down_shift), + resources.getColor(R.color.modern_grey_800_alpha_38)); mTabModelSelectorObserver = new TabModelSelectorObserver() { @Override
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index db72fb7..7f44ecf 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -662,13 +662,6 @@ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"> </activity> - <!-- Activities for video tutorials. --> - <activity android:name="org.chromium.chrome.browser.app.video_tutorials.VideoTutorialListActivity" - android:theme="@style/Theme.Chromium.Activity.Fullscreen" - android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" - android:exported="false"> - </activity> - <!-- Activities for downloads. --> <activity-alias android:name="org.chromium.chrome.browser.download.DownloadActivity" android:targetActivity="org.chromium.chrome.browser.app.download.home.DownloadActivity" @@ -710,16 +703,6 @@ android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"> </activity> - <!-- Activities for video tutorials. --> - <activity android:name="org.chromium.chrome.browser.app.video_tutorials.VideoPlayerActivity" - android:theme="@style/Theme.Chromium.Activity.Fullscreen" - android:screenOrientation="portrait" - android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize" - android:exported="false" - tools:ignore="LockedOrientationActivity"> - <!-- We want to explicitly disallow landscape UI for video tutorials. --> - </activity> - <!-- Activities for history. --> <activity android:name="org.chromium.chrome.browser.history.HistoryActivity" android:theme="@style/Theme.Chromium.Activity.Fullscreen"
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS index 275b6e4..c6cf0b9 100644 --- a/chrome/android/java/DEPS +++ b/chrome/android/java/DEPS
@@ -24,7 +24,6 @@ "+chrome/browser/password_check/android", "+chrome/browser/settings/android/java", "+chrome/browser/tabmodel/android/java", - "+chrome/browser/video_tutorials/android", "+components/autofill/android/java/src/org/chromium/components/autofill", "+components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler", "+components/bookmarks/common/android/java/src/org/chromium/components/bookmarks",
diff --git a/chrome/android/java/res/layout/automotive_back_button_toolbar.xml b/chrome/android/java/res/layout/automotive_back_button_toolbar.xml deleted file mode 100644 index 8f0f017..0000000 --- a/chrome/android/java/res/layout/automotive_back_button_toolbar.xml +++ /dev/null
@@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2023 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> -<merge xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> - - <androidx.appcompat.widget.Toolbar - android:id="@+id/automotive_back_button_toolbar" - android:layout_width="match_parent" - android:layout_height="?attr/actionBarSize" - android:background="@android:color/black" - app:navigationIcon="@drawable/ic_arrow_back_white_24dp" - app:theme="@style/DarkModeRippleColor" - app:navigationContentDescription="@string/back" - android:visibility="gone"/> - -</merge>
diff --git a/chrome/android/java/res/layout/automotive_layout_with_back_button_toolbar.xml b/chrome/android/java/res/layout/automotive_layout_with_back_button_toolbar.xml new file mode 100644 index 0000000..8e21d1f6 --- /dev/null +++ b/chrome/android/java/res/layout/automotive_layout_with_back_button_toolbar.xml
@@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright 2023 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/automotive_base_linear_layout" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.appcompat.widget.Toolbar + android:id="@+id/back_button_toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:background="@android:color/black" + app:theme="@style/DarkModeActionBarTheme" + app:navigationIcon="@drawable/ic_arrow_back_24dp" + app:navigationContentDescription="@string/back"/> + + <ViewStub + android:id="@+id/original_layout" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + +</LinearLayout>
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml index e6c62ddf..2165ff4 100644 --- a/chrome/android/java/res/layout/new_tab_page_layout.xml +++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -77,16 +77,6 @@ android:layout_marginTop="@dimen/search_resumption_module_margin_top" android:layout="@layout/search_resumption_module_layout" /> - <!-- Video tutorial IPH card --> - <ViewStub - android:id="@+id/video_iph_stub" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="12dp" - android:layout_marginBottom="12dp" - android:layout="@layout/video_tutorial_iph_card" - android:inflatedId="@+id/video_iph_card"/> - <!-- Spacer for when there is no search provider logo. --> <View android:id="@+id/no_search_logo_spacer"
diff --git a/chrome/android/java/res/layout/settings_activity.xml b/chrome/android/java/res/layout/settings_activity.xml index ef8be6e..2f1ede8 100644 --- a/chrome/android/java/res/layout/settings_activity.xml +++ b/chrome/android/java/res/layout/settings_activity.xml
@@ -20,8 +20,6 @@ android:theme="@style/ThemeOverlay.Settings.DisableElevationOverlay" app:liftOnScroll="true"> - <include layout="@layout/automotive_back_button_toolbar"/> - <com.google.android.material.appbar.MaterialToolbar android:id="@+id/action_bar" android:layout_width="match_parent"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 2864fe1..27ad3f1 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -161,6 +161,7 @@ <dimen name="tile_grid_layout_bottom_margin_push_down_large">64dp</dimen> <dimen name="tile_grid_layout_bottom_margin_pull_up">24dp</dimen> <dimen name="tile_carousel_layout_bottom_margin">24dp</dimen> + <dimen name="ntp_iph_searchbox_y_inset">6dp</dimen> <dimen name="ntp_logo_height">100dp</dimen> <dimen name="ntp_logo_margin_top">26dp</dimen> <dimen name="ntp_logo_margin_bottom">23dp</dimen> @@ -381,9 +382,6 @@ <dimen name="long_screenshots_button_padding">8dp</dimen> <dimen name="long_screenshots_button_margin">17dp</dimen> - <!-- Video tutorials dimensions --> - <dimen name="video_tutorial_try_now_iph_ntp_searchbox_y_inset">6dp</dimen> - <!-- IPH shared highlighting builder padding top --> <dimen name="iph_shared_highlighting_padding_top">120dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java index 73670387..59eee24c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
@@ -14,8 +14,12 @@ import android.os.Bundle; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; +import android.view.ViewStub; +import android.widget.LinearLayout; import androidx.annotation.CallSuper; +import androidx.annotation.IntDef; import androidx.annotation.LayoutRes; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @@ -43,20 +47,50 @@ import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogManagerHolder; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.LinkedHashSet; /** * A subclass of {@link AppCompatActivity} that maintains states and objects applied to all * activities in {@link ChromeApplication} (e.g. night mode). - * - * This class also adds a persistent back button toolbar for automotive by applying a ThemeOverlay. - * Activities that already use their own ActionBar must override - * {@link #shouldUseActionBarForAutomotiveToolbar} to false and add - * <include layout="@layout/automotive_back_button_toolbar"/> - * in their xml layout. See SettingsActivity and settings_activity.xml for an example. */ public class ChromeBaseAppCompatActivity extends AppCompatActivity implements NightModeStateProvider.Observer, ModalDialogManagerHolder { + /** + * Chrome in automotive needs a persistent back button toolbar above all activities because + * AAOS/cars do not have a built in back button. This is implemented differently in each + * activity. + * + * Activities that use the <merge> tag or delay layout inflation cannot use WITH_TOOLBAR_VIEW. + * Activities that use their own action bar cannot use WITH_ACTION_BAR. + * Activities that appear as Dialogs using themes do not have an automotive toolbar yet (NONE). + */ + @IntDef({ + AutomotiveToolbarImplementation.WITH_TOOLBAR_VIEW, + AutomotiveToolbarImplementation.WITH_ACTION_BAR, + AutomotiveToolbarImplementation.NONE, + }) + @Retention(RetentionPolicy.SOURCE) + protected @interface AutomotiveToolbarImplementation { + /** + * Automotive toolbar is added by including the original layout into a bigger LinearLayout + * that has a Toolbar View, see R.layout.automotive_layout_with_back_button_toolbar. + */ + int WITH_TOOLBAR_VIEW = 0; + + /** + * Automotive toolbar is added using AppCompatActivity's ActionBar, provided with a + * ThemeOverlay, see R.style.ThemeOverlay_BrowserUI_Automotive_PersistentBackButtonToolbar. + */ + int WITH_ACTION_BAR = 1; + + /** + * Automotive toolbar is not added. + */ + int NONE = -1; + } + private final ObservableSupplierImpl<ModalDialogManager> mModalDialogManagerSupplier = new ObservableSupplierImpl<>(); private NightModeStateProvider mNightModeStateProvider; @@ -262,7 +296,9 @@ "IsDynamicColorAvailable", isDynamicColorAvailable ? "Enabled" : "Disabled"); }); - if (BuildInfo.getInstance().isAutomotive && shouldUseActionBarForAutomotiveToolbar()) { + if (BuildInfo.getInstance().isAutomotive + && getAutomotiveToolbarImplementation() + == AutomotiveToolbarImplementation.WITH_ACTION_BAR) { setTheme(R.style.ThemeOverlay_BrowserUI_Automotive_PersistentBackButtonToolbar); } } @@ -319,35 +355,79 @@ @Override public void setContentView(@LayoutRes int layoutResID) { - super.setContentView(layoutResID); + if (BuildInfo.getInstance().isAutomotive + && getAutomotiveToolbarImplementation() + == AutomotiveToolbarImplementation.WITH_TOOLBAR_VIEW) { + super.setContentView(R.layout.automotive_layout_with_back_button_toolbar); + setAutomotiveToolbarBackButtonAction(); + ViewStub stub = findViewById(R.id.original_layout); + stub.setLayoutResource(layoutResID); + stub.inflate(); + } else { + super.setContentView(layoutResID); + } + } - // Activities that use their own ActionBar can add the persistent back button toolbar for - // automotive using a Toolbar View. - if (BuildInfo.getInstance().isAutomotive && !shouldUseActionBarForAutomotiveToolbar()) { - Toolbar backButtonToolbarForAutomotive = - findViewById(R.id.automotive_back_button_toolbar); - if (backButtonToolbarForAutomotive != null) { - backButtonToolbarForAutomotive.setVisibility(View.VISIBLE); - backButtonToolbarForAutomotive.setNavigationOnClickListener( - view -> { getOnBackPressedDispatcher().onBackPressed(); }); - } + @Override + public void setContentView(View view) { + if (BuildInfo.getInstance().isAutomotive + && getAutomotiveToolbarImplementation() + == AutomotiveToolbarImplementation.WITH_TOOLBAR_VIEW) { + super.setContentView(R.layout.automotive_layout_with_back_button_toolbar); + setAutomotiveToolbarBackButtonAction(); + LinearLayout linearLayout = findViewById(R.id.automotive_base_linear_layout); + linearLayout.addView(view); + } else { + super.setContentView(view); + } + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + if (BuildInfo.getInstance().isAutomotive + && getAutomotiveToolbarImplementation() + == AutomotiveToolbarImplementation.WITH_TOOLBAR_VIEW) { + super.setContentView(R.layout.automotive_layout_with_back_button_toolbar); + setAutomotiveToolbarBackButtonAction(); + LinearLayout linearLayout = findViewById(R.id.automotive_base_linear_layout); + linearLayout.setLayoutParams(params); + linearLayout.addView(view); + } else { + super.setContentView(view, params); } } @Override protected void onResume() { - if (BuildInfo.getInstance().isAutomotive && shouldUseActionBarForAutomotiveToolbar() + if (BuildInfo.getInstance().isAutomotive + && getAutomotiveToolbarImplementation() + == AutomotiveToolbarImplementation.WITH_ACTION_BAR && getSupportActionBar() != null) { getSupportActionBar().setHomeActionContentDescription(R.string.back); } super.onResume(); } - /** - * @return true if the persistent back button toolbar for automotive will be added by default - * using AppCompatActivity's ActionBar, provided by a ThemeOverlay. - */ - protected boolean shouldUseActionBarForAutomotiveToolbar() { - return true; + protected int getAutomotiveToolbarImplementation() { + int activityStyle = -1; + try { + activityStyle = + getPackageManager().getActivityInfo(getComponentName(), 0).getThemeResource(); + } catch (Exception e) { + e.printStackTrace(); + } + if (activityStyle == R.style.Theme_Chromium_DialogWhenLarge) { + return AutomotiveToolbarImplementation.NONE; + } else { + return AutomotiveToolbarImplementation.WITH_TOOLBAR_VIEW; + } + } + + private void setAutomotiveToolbarBackButtonAction() { + Toolbar backButtonToolbarForAutomotive = findViewById(R.id.back_button_toolbar); + if (backButtonToolbarForAutomotive != null) { + backButtonToolbarForAutomotive.setNavigationOnClickListener( + backButtonClick -> { getOnBackPressedDispatcher().onBackPressed(); }); + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java index f134968..d05eba1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java
@@ -11,12 +11,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Px; -import androidx.core.view.WindowInsetsCompat; -import org.chromium.base.TraceEvent; import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.flags.MutableFlagWithSafeDefault; import org.chromium.chrome.browser.init.SingleWindowKeyboardVisibilityDelegate; import org.chromium.chrome.browser.keyboard_accessory.ManualFillingComponent; @@ -28,8 +24,6 @@ */ public class ChromeKeyboardVisibilityDelegate extends SingleWindowKeyboardVisibilityDelegate implements ManualFillingComponent.SoftKeyboardDelegate { - private static final MutableFlagWithSafeDefault sScrollOptimizationsFlag = - new MutableFlagWithSafeDefault(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); private final Supplier<ManualFillingComponent> mManualFillingComponentSupplier; /** @@ -60,29 +54,6 @@ && mManualFillingComponentSupplier.get().isFillingViewShown(view)); } - @Override - public int calculateKeyboardHeight(View rootView) { - try (TraceEvent te = TraceEvent.scoped( - "ChromeKeyboardVisibilityDelegate.calculateKeyboardHeight")) { - // TODO(https://crbug.com/1385562: remove the flag guard once this change is known to be - // safe). - if (sScrollOptimizationsFlag.isEnabled()) { - if (rootView == null || rootView.getRootWindowInsets() == null) return 0; - WindowInsetsCompat windowInsetsCompat = WindowInsetsCompat.toWindowInsetsCompat( - rootView.getRootWindowInsets(), rootView); - int imeHeightIncludingNavigationBar = - windowInsetsCompat.getInsets(WindowInsetsCompat.Type.ime()).bottom; - if (imeHeightIncludingNavigationBar == 0) return 0; - int navigationBarHeight = - windowInsetsCompat.getInsets(WindowInsetsCompat.Type.navigationBars()) - .bottom; - return imeHeightIncludingNavigationBar - navigationBarHeight; - } - - return super.calculateKeyboardHeight(rootView); - } - } - /** * Implementation ignoring the Chrome-specific keyboard logic on top of the system keyboard. * @see ManualFillingComponent.SoftKeyboardDelegate#hideSoftKeyboardOnly(View)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 0f509ca..fde24cc 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -3056,6 +3056,11 @@ } } + @Override + protected int getAutomotiveToolbarImplementation() { + return AutomotiveToolbarImplementation.WITH_ACTION_BAR; + } + /** * Reports that a new tab launcher shortcut was selected or an action equivalent to a shortcut * was performed.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java index b09179a..d1a9be2b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java
@@ -30,7 +30,6 @@ import org.chromium.base.Log; import org.chromium.base.PackageManagerUtils; import org.chromium.base.StrictModeContext; -import org.chromium.chrome.browser.app.video_tutorials.VideoTutorialShareHelper; import org.chromium.chrome.browser.browserservices.SessionDataHolder; import org.chromium.chrome.browser.browserservices.ui.splashscreen.trustedwebactivity.TwaSplashController; import org.chromium.chrome.browser.customtabs.CustomTabActivity; @@ -169,11 +168,6 @@ return Action.FINISH_ACTIVITY; } - // Check if the URL is a video tutorial and needs to be handled in a video player. - if (VideoTutorialShareHelper.handleVideoTutorialURL(url)) { - return Action.FINISH_ACTIVITY; - } - // Check if a LIVE WebappActivity has to be brought back to the foreground. We can't // check for a dead WebappActivity because we don't have that information without a global // TabManager. If that ever lands, code to bring back any Tab could be consolidated
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/app/DEPS index 919aecb..c8cf528 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/DEPS +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/DEPS
@@ -1,4 +1,3 @@ include_rules = [ "+chrome/browser/tabmodel", - "+chrome/browser/video_tutorials", ]
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkAddEditFolderActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkAddEditFolderActivity.java index e679c70..6c359a1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkAddEditFolderActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkAddEditFolderActivity.java
@@ -262,11 +262,6 @@ mModel.removeObserver(mBookmarkModelObserver); } - @Override - protected boolean shouldUseActionBarForAutomotiveToolbar() { - return false; - } - private void updateParent(BookmarkId newParent) { mParentId = newParent; mParentTextView.setText(mModel.getBookmarkTitle(mParentId));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkEditActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkEditActivity.java index 57795b7..ac73b15 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkEditActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkEditActivity.java
@@ -183,11 +183,6 @@ super.onDestroy(); } - @Override - protected boolean shouldUseActionBarForAutomotiveToolbar() { - return false; - } - @VisibleForTesting BookmarkTextInputLayout getTitleEditText() { return mTitleEditText;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderSelectActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderSelectActivity.java index fc931fd..8f7aa7c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderSelectActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/bookmarks/BookmarkFolderSelectActivity.java
@@ -287,11 +287,6 @@ } } - @Override - protected boolean shouldUseActionBarForAutomotiveToolbar() { - return false; - } - private void moveBookmarksAndFinish(List<BookmarkId> bookmarks, BookmarkId parent) { List<BookmarkId> movedBookmarks = new ArrayList<>(); ReadingListUtils.typeSwapBookmarksIfNecessary(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/ChromeLanguageInfoProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/ChromeLanguageInfoProvider.java deleted file mode 100644 index 2df259c..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/ChromeLanguageInfoProvider.java +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.video_tutorials; - -import org.chromium.chrome.browser.language.settings.LanguageItem; -import org.chromium.chrome.browser.language.settings.LanguagesManager; -import org.chromium.chrome.browser.video_tutorials.Language; -import org.chromium.chrome.browser.video_tutorials.LanguageInfoProvider; - -/** - * See {@link LanguageInfoProvider}. - */ -public class ChromeLanguageInfoProvider implements LanguageInfoProvider { - @Override - public Language getLanguageInfo(String locale) { - LanguageItem languageItem = LanguagesManager.getInstance().getLanguageMap().get(locale); - if (languageItem == null) return null; - - return new Language(languageItem.getCode(), languageItem.getDisplayName(), - languageItem.getNativeDisplayName()); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA deleted file mode 100644 index e4c6644..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA +++ /dev/null
@@ -1,2 +0,0 @@ -mixins: "//chrome/browser/video_tutorials/COMMON_METADATA" -team_email: "chrome-upboarding@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java deleted file mode 100644 index f00d6b8..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java +++ /dev/null
@@ -1,137 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.video_tutorials; - -import android.content.Context; -import android.content.Intent; -import android.view.ViewStub; - -import androidx.annotation.VisibleForTesting; - -import org.chromium.base.Callback; -import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory; -import org.chromium.chrome.browser.video_tutorials.iph.VideoIPHCoordinator; -import org.chromium.chrome.browser.video_tutorials.iph.VideoTutorialIPHUtils; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.UserAction; -import org.chromium.components.browser_ui.util.GlobalDiscardableReferencePool; -import org.chromium.components.feature_engagement.Tracker; -import org.chromium.components.image_fetcher.ImageFetcher; -import org.chromium.components.image_fetcher.ImageFetcherConfig; -import org.chromium.components.image_fetcher.ImageFetcherFactory; - -import java.util.ArrayList; -import java.util.List; - -/** - * Handles all the logic required for showing the appropriate video tutorial IPH on new tab page. - * Queries the backend for the sorted list of available video tutorials, and shows the one not seen - * by user yet. Also responsible for showing the next tutorial IPH when one is consumed or - * dismissed. - */ -public class NewTabPageVideoIPHManager { - private Context mContext; - private Tracker mTracker; - private VideoIPHCoordinator mVideoIPHCoordinator; - private VideoTutorialService mVideoTutorialService; - - /** - * Constructor. - * @param viewStub The {@link ViewStub} to be inflated to show the IPH. - * @param profile The associated profile. - */ - public NewTabPageVideoIPHManager(ViewStub viewStub, Profile profile) { - if (!ChromeFeatureList.isEnabled(ChromeFeatureList.VIDEO_TUTORIALS)) return; - - mContext = viewStub.getContext(); - mTracker = TrackerFactory.getTrackerForProfile(profile); - mVideoIPHCoordinator = createVideoIPHCoordinator( - viewStub, createImageFetcher(profile), this::onClickIPH, this::onDismissIPH); - mVideoTutorialService = VideoTutorialServiceFactory.getForProfile(profile); - mVideoTutorialService.getTutorials(this::onFetchTutorials); - } - - private void onFetchTutorials(List<Tutorial> tutorials) { - if (tutorials.isEmpty()) return; - - // Add the summary tutorial to the list. - List<Tutorial> tutorialsCopy = new ArrayList<>(tutorials); - mVideoTutorialService.getTutorial(FeatureType.SUMMARY, tutorial -> { - if (tutorial != null) tutorialsCopy.add(tutorial); - - mTracker.addOnInitializedCallback(success -> { - if (!success) return; - showFirstEligibleIPH(tutorialsCopy); - }); - }); - } - - private void showFirstEligibleIPH(List<Tutorial> tutorials) { - for (Tutorial tutorial : tutorials) { - String featureName = VideoTutorialIPHUtils.getFeatureNameForNTP(tutorial.featureType); - if (featureName == null) continue; - if (mTracker.shouldTriggerHelpUI(featureName)) { - VideoTutorialMetrics.recordUserAction( - tutorial.featureType, UserAction.IPH_NTP_SHOWN); - mVideoIPHCoordinator.showVideoIPH(tutorial); - mTracker.dismissed(featureName); - break; - } - } - } - - private void onClickIPH(Tutorial tutorial) { - // TODO(shaktisahu): Maybe collect this event when video has been halfway watched. - mTracker.notifyEvent(VideoTutorialIPHUtils.getClickEvent(tutorial.featureType)); - VideoTutorialMetrics.recordUserAction(tutorial.featureType, UserAction.IPH_NTP_CLICKED); - - // Bring up the player and start playing the video. - if (tutorial.featureType == FeatureType.SUMMARY) { - launchTutorialListActivity(); - } else { - launchVideoPlayer(tutorial); - } - } - - private void onDismissIPH(Tutorial tutorial) { - mTracker.notifyEvent(VideoTutorialIPHUtils.getDismissEvent(tutorial.featureType)); - VideoTutorialMetrics.recordUserAction(tutorial.featureType, UserAction.IPH_NTP_DISMISSED); - - // TODO(shaktisahu): Animate this. Maybe add a delay. - mVideoTutorialService.getTutorials(this::onFetchTutorials); - } - - @VisibleForTesting - protected void launchVideoPlayer(Tutorial tutorial) { - VideoPlayerActivity.playVideoTutorial(mContext, tutorial.featureType); - } - - @VisibleForTesting - protected void launchTutorialListActivity() { - Intent intent = new Intent(); - intent.setClass(mContext, VideoTutorialListActivity.class); - mContext.startActivity(intent); - } - - @VisibleForTesting - protected ImageFetcher createImageFetcher(Profile profile) { - return ImageFetcherFactory.createImageFetcher(ImageFetcherConfig.IN_MEMORY_WITH_DISK_CACHE, - profile.getProfileKey(), GlobalDiscardableReferencePool.getReferencePool()); - } - - @VisibleForTesting - protected VideoIPHCoordinator createVideoIPHCoordinator(ViewStub viewStub, - ImageFetcher imageFetcher, Callback<Tutorial> clickListener, - Callback<Tutorial> dismissListener) { - return VideoTutorialServiceFactory.createVideoIPHCoordinator( - viewStub, imageFetcher, clickListener, dismissListener); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/OWNERS deleted file mode 100644 index 36c3bec..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://chrome/browser/video_tutorials/OWNERS
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java deleted file mode 100644 index 5151e9d..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java +++ /dev/null
@@ -1,103 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.video_tutorials; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.util.Pair; -import android.view.WindowManager; - -import org.chromium.base.IntentUtils; -import org.chromium.chrome.browser.BackPressHelper; -import org.chromium.chrome.browser.ChromeTabbedActivity; -import org.chromium.chrome.browser.SynchronousInitializationActivity; -import org.chromium.chrome.browser.WebContentsFactory; -import org.chromium.chrome.browser.back_press.BackPressManager; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory; -import org.chromium.chrome.browser.video_tutorials.player.VideoPlayerCoordinator; -import org.chromium.components.embedder_support.util.UrlConstants; -import org.chromium.components.embedder_support.view.ContentView; -import org.chromium.components.version_info.VersionConstants; -import org.chromium.content_public.browser.WebContents; -import org.chromium.ui.base.ActivityWindowAndroid; -import org.chromium.ui.base.IntentRequestTracker; -import org.chromium.ui.base.ViewAndroidDelegate; -import org.chromium.ui.base.WindowAndroid; - -/** - * Java interface for interacting with the native video tutorial service. Responsible for - * initializing and fetching data fo be shown on the UI. - */ -public class VideoPlayerActivity extends SynchronousInitializationActivity { - public static final String EXTRA_VIDEO_TUTORIAL = "extra_video_tutorial"; - - private WindowAndroid mWindowAndroid; - private VideoPlayerCoordinator mCoordinator; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); - - VideoTutorialService videoTutorialService = - VideoTutorialServiceFactory.getForProfile(Profile.getLastUsedRegularProfile()); - IntentRequestTracker intentRequestTracker = IntentRequestTracker.createFromActivity(this); - mWindowAndroid = new ActivityWindowAndroid( - this, /* listenToActivityState= */ true, intentRequestTracker); - mCoordinator = VideoTutorialServiceFactory.createVideoPlayerCoordinator(this, - videoTutorialService, this::createWebContents, new ChromeLanguageInfoProvider(), - this::tryNow, this::finish, intentRequestTracker); - setContentView(mCoordinator.getView()); - - int featureType = - IntentUtils.safeGetIntExtra(getIntent(), EXTRA_VIDEO_TUTORIAL, FeatureType.INVALID); - videoTutorialService.getTutorial(featureType, mCoordinator::playVideoTutorial); - if (!BackPressManager.isSecondaryActivityEnabled()) { - // See comments in VideoPlayerMediator#handleBackPressed. - BackPressHelper.create(this, getOnBackPressedDispatcher(), mCoordinator::onBackPressed); - } - } - - private Pair<WebContents, ContentView> createWebContents() { - Profile profile = Profile.getLastUsedRegularProfile(); - WebContents webContents = WebContentsFactory.createWebContents(profile, false, false); - ContentView contentView = - ContentView.createContentView(this, null /* eventOffsetHandler */, webContents); - webContents.initialize(VersionConstants.PRODUCT_VERSION, - ViewAndroidDelegate.createBasicDelegate(contentView), contentView, mWindowAndroid, - WebContents.createDefaultInternalsHolder()); - return Pair.create(webContents, contentView); - } - - @Override - protected void onDestroy() { - mCoordinator.destroy(); - super.onDestroy(); - } - - /** Called to launch this activity to play a given video tutorial. */ - public static void playVideoTutorial(Context context, @FeatureType int featureType) { - Intent intent = new Intent(); - intent.setClass(context, VideoPlayerActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(VideoPlayerActivity.EXTRA_VIDEO_TUTORIAL, featureType); - context.startActivity(intent); - } - - private void tryNow(Tutorial tutorial) { - VideoTutorialServiceFactory.getTryNowTracker().recordTryNowButtonClicked( - tutorial.featureType); - Intent intent = new Intent(); - intent.setData(Uri.parse(UrlConstants.NTP_URL)); - intent.setClass(this, ChromeTabbedActivity.class); - startActivity(intent); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialListActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialListActivity.java deleted file mode 100644 index c7a67f1..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialListActivity.java +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.video_tutorials; - -import android.os.Bundle; - -import org.chromium.chrome.R; -import org.chromium.chrome.browser.SynchronousInitializationActivity; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory; -import org.chromium.chrome.browser.video_tutorials.list.TutorialListCoordinator; -import org.chromium.components.browser_ui.util.GlobalDiscardableReferencePool; -import org.chromium.components.image_fetcher.ImageFetcher; -import org.chromium.components.image_fetcher.ImageFetcherConfig; -import org.chromium.components.image_fetcher.ImageFetcherFactory; - -/** - * Activity for displaying a list of video tutorials available to watch. - */ -public class VideoTutorialListActivity extends SynchronousInitializationActivity { - private TutorialListCoordinator mCoordinator; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.video_tutorial_list); - - Profile profile = Profile.getLastUsedRegularProfile(); - VideoTutorialService videoTutorialService = - VideoTutorialServiceFactory.getForProfile(profile); - ImageFetcher imageFetcher = - ImageFetcherFactory.createImageFetcher(ImageFetcherConfig.IN_MEMORY_WITH_DISK_CACHE, - profile.getProfileKey(), GlobalDiscardableReferencePool.getReferencePool()); - mCoordinator = VideoTutorialServiceFactory.createTutorialListCoordinator( - findViewById(R.id.video_tutorial_list), videoTutorialService, imageFetcher, - this::onTutorialSelected); - findViewById(R.id.close_button).setOnClickListener(v -> finish()); - } - - private void onTutorialSelected(Tutorial tutorial) { - VideoPlayerActivity.playVideoTutorial(this, tutorial.featureType); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialShareHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialShareHelper.java deleted file mode 100644 index 91ae2c0..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialShareHelper.java +++ /dev/null
@@ -1,97 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.video_tutorials; - -import android.text.TextUtils; - -import org.chromium.base.ContextUtils; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.init.BrowserParts; -import org.chromium.chrome.browser.init.ChromeBrowserInitializer; -import org.chromium.chrome.browser.init.EmptyBrowserParts; -import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; -import org.chromium.chrome.browser.preferences.SharedPreferencesManager; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.UserAction; - -import java.util.HashSet; -import java.util.Set; - -/** - * Helper class to handle share intents for video tutorials. - */ -public class VideoTutorialShareHelper { - /** - * Handles the URL, if it is a video tutorial share URL, otherwise returns false. - * @param url The URL being checked. - * @return True, if the URL was recognized as a video tutorial URL and handled, false otherwise. - */ - public static boolean handleVideoTutorialURL(String url) { - Set<String> videoTutorialUrls = SharedPreferencesManager.getInstance().readStringSet( - ChromePreferenceKeys.VIDEO_TUTORIALS_SHARE_URL_SET, new HashSet<>()); - if (!videoTutorialUrls.contains(url)) return false; - if (!ChromeFeatureList.isEnabled(ChromeFeatureList.VIDEO_TUTORIALS)) return false; - - launchVideoPlayer(url); - return true; - } - - /** - * Writes the video tutorial share URLs to shared preferences. This is later used to identify - * whether a URL is a video tutorial. - */ - public static void saveUrlsToSharedPrefs() { - if (!ChromeFeatureList.isEnabled(ChromeFeatureList.VIDEO_TUTORIALS)) { - SharedPreferencesManager.getInstance().removeKey( - ChromePreferenceKeys.VIDEO_TUTORIALS_SHARE_URL_SET); - return; - } - - VideoTutorialService videoTutorialService = - VideoTutorialServiceFactory.getForProfile(Profile.getLastUsedRegularProfile()); - videoTutorialService.getTutorials(tutorials -> { - Set<String> shareUrlSet = new HashSet<>(); - for (Tutorial tutorial : tutorials) { - if (TextUtils.isEmpty(tutorial.shareUrl)) continue; - shareUrlSet.add(tutorial.shareUrl); - } - SharedPreferencesManager.getInstance().writeStringSet( - ChromePreferenceKeys.VIDEO_TUTORIALS_SHARE_URL_SET, shareUrlSet); - }); - } - - private static void launchVideoPlayer(String shareUrl) { - assert !TextUtils.isEmpty(shareUrl); - - BrowserParts parts = new EmptyBrowserParts() { - @Override - public void finishNativeInitialization() { - VideoTutorialService videoTutorialService = - VideoTutorialServiceFactory.getForProfile( - Profile.getLastUsedRegularProfile()); - videoTutorialService.getTutorials(tutorials -> { - for (Tutorial tutorial : tutorials) { - if (TextUtils.equals(tutorial.shareUrl, shareUrl)) { - VideoTutorialMetrics.recordUserAction( - tutorial.featureType, UserAction.OPEN_SHARED_VIDEO); - VideoPlayerActivity.playVideoTutorial( - ContextUtils.getApplicationContext(), tutorial.featureType); - return; - } - } - VideoTutorialMetrics.recordUserAction( - FeatureType.INVALID, UserAction.INVALID_SHARE_URL); - }); - } - }; - ChromeBrowserInitializer.getInstance().handlePreNativeStartupAndLoadLibraries(parts); - ChromeBrowserInitializer.getInstance().handlePostNativeStartup(true, parts); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialsServiceUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialsServiceUtils.java deleted file mode 100644 index 32a6594..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/VideoTutorialsServiceUtils.java +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.video_tutorials; - -import org.chromium.base.annotations.CalledByNative; -import org.chromium.chrome.browser.AppHooks; - -/** - * Class for providing helper method for talking with the video - * tutorial service. - */ -public class VideoTutorialsServiceUtils { - /** - * @return Default server URL for getting video tutorials. - */ - @CalledByNative - private static String getDefaultServerUrl() { - // TODO(qinmin): having a separate method in AppHooks to provide - // server URLs for video tutorials. - return AppHooks.get().getDefaultQueryTilesServerUrl(); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java index 7e648ff2..cc63c204 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -1280,10 +1280,15 @@ displayText = formattedDisplayText; } else { UrlBarData urlBarData = mLocationBarDataProvider.getUrlBarData(); - displayText = urlBarData.displayText.subSequence( - urlBarData.originStartIndex, urlBarData.originEndIndex); originStart = 0; - originEnd = displayText.length(); + if (urlBarData.displayText != null) { + displayText = urlBarData.displayText.subSequence( + urlBarData.originStartIndex, urlBarData.originEndIndex); + originEnd = displayText.length(); + } else { + displayText = null; + originEnd = 0; + } } mUrlCoordinator.setUrlBarData(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java index 7374c11..caa5844a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ProcessInitializationHandler.java
@@ -37,7 +37,6 @@ import org.chromium.chrome.browser.app.bluetooth.BluetoothNotificationService; import org.chromium.chrome.browser.app.feature_guide.notifications.FeatureNotificationGuideDelegate; import org.chromium.chrome.browser.app.usb.UsbNotificationService; -import org.chromium.chrome.browser.app.video_tutorials.VideoTutorialShareHelper; import org.chromium.chrome.browser.bluetooth.BluetoothNotificationManager; import org.chromium.chrome.browser.bookmarkswidget.BookmarkWidgetProvider; import org.chromium.chrome.browser.contacts_picker.ChromePickerAdapter; @@ -433,8 +432,6 @@ deferredStartupHandler.addDeferredTask( () -> EnterpriseInfo.getInstance().logDeviceEnterpriseInfo()); deferredStartupHandler.addDeferredTask( - () -> VideoTutorialShareHelper.saveUrlsToSharedPrefs()); - deferredStartupHandler.addDeferredTask( () -> TosDialogBehaviorSharedPrefInvalidator.refreshSharedPreferenceIfTosSkipped()); deferredStartupHandler.addDeferredTask( () -> OfflineMeasurementsBackgroundTask.clearPersistedDataFromPrefs());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java index bcb47f1..482e9ffa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -31,7 +31,6 @@ import org.chromium.base.MathUtils; import org.chromium.base.TraceEvent; import org.chromium.chrome.R; -import org.chromium.chrome.browser.app.video_tutorials.NewTabPageVideoIPHManager; import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider; import org.chromium.chrome.browser.cryptids.ProbabilisticCryptidRenderer; import org.chromium.chrome.browser.feed.FeedSurfaceScrollDelegate; @@ -55,9 +54,6 @@ import org.chromium.chrome.browser.util.BrowserUiUtils; import org.chromium.chrome.browser.util.BrowserUiUtils.HostSurface; import org.chromium.chrome.browser.util.BrowserUiUtils.ModuleTypeOnStartAndNTP; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory; -import org.chromium.chrome.browser.video_tutorials.iph.VideoTutorialTryNowTracker; import org.chromium.components.browser_ui.styles.ChromeColors; import org.chromium.components.browser_ui.widget.displaystyle.UiConfig; import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter; @@ -88,7 +84,6 @@ private LogoCoordinator mLogoCoordinator; private SearchBoxCoordinator mSearchBoxCoordinator; private QueryTileSection mQueryTileSection; - private NewTabPageVideoIPHManager mVideoIPHManager; private ImageView mCryptidHolder; private ViewGroup mMvTilesContainerLayout; private MostVisitedTilesCoordinator mMostVisitedTilesCoordinator; @@ -153,8 +148,6 @@ protected void onFinishInflate() { super.onFinishInflate(); mMiddleSpacer = findViewById(R.id.ntp_middle_spacer); - mVideoIPHManager = new NewTabPageVideoIPHManager( - findViewById(R.id.video_iph_stub), Profile.getLastUsedRegularProfile()); insertSiteSectionView(); } @@ -722,7 +715,6 @@ if (visibility == VISIBLE) { updateActionButtonVisibility(); - maybeShowVideoTutorialTryNowIPH(); } } @@ -790,29 +782,6 @@ } } - private void maybeShowVideoTutorialTryNowIPH() { - if (getToolbarTransitionPercentage() > 0f) return; - VideoTutorialTryNowTracker tryNowTracker = VideoTutorialServiceFactory.getTryNowTracker(); - UserEducationHelper userEducationHelper = new UserEducationHelper(mActivity, new Handler()); - if (tryNowTracker.didClickTryNowButton(FeatureType.SEARCH)) { - IPHCommandBuilder iphCommandBuilder = createIPHCommandBuilder(mActivity.getResources(), - R.string.video_tutorials_iph_tap_here_to_start, - R.string.video_tutorials_iph_tap_here_to_start, mSearchBoxCoordinator.getView(), - false); - userEducationHelper.requestShowIPH(iphCommandBuilder.build()); - tryNowTracker.tryNowUIShown(FeatureType.SEARCH); - } - - if (tryNowTracker.didClickTryNowButton(FeatureType.VOICE_SEARCH)) { - IPHCommandBuilder iphCommandBuilder = createIPHCommandBuilder(mActivity.getResources(), - R.string.video_tutorials_iph_tap_voice_icon_to_start, - R.string.video_tutorials_iph_tap_voice_icon_to_start, - mSearchBoxCoordinator.getVoiceSearchButton(), true); - userEducationHelper.requestShowIPH(iphCommandBuilder.build()); - tryNowTracker.tryNowUIShown(FeatureType.VOICE_SEARCH); - } - } - @VisibleForTesting MostVisitedTilesCoordinator getMostVisitedTilesCoordinatorForTesting() { return mMostVisitedTilesCoordinator; @@ -840,8 +809,7 @@ FeatureConstants.FEATURE_NOTIFICATION_GUIDE_VOICE_SEARCH_HELP_BUBBLE_FEATURE, stringId, accessibilityStringId); iphCommandBuilder.setAnchorView(anchorView); - int yInsetPx = resources.getDimensionPixelOffset( - R.dimen.video_tutorial_try_now_iph_ntp_searchbox_y_inset); + int yInsetPx = resources.getDimensionPixelOffset(R.dimen.ntp_iph_searchbox_y_inset); iphCommandBuilder.setInsetRect(new Rect(0, 0, 0, -yInsetPx)); if (showHighlight) { iphCommandBuilder.setOnShowCallback(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java index 958740e..ba88b55 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
@@ -571,9 +571,4 @@ return divider; } - - @Override - protected boolean shouldUseActionBarForAutomotiveToolbar() { - return false; - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivity.java index 9701eca..1a99fb7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentActivity.java
@@ -95,9 +95,4 @@ } return mWindowAndroid; } - - @Override - protected boolean shouldUseActionBarForAutomotiveToolbar() { - return false; - } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFavicon.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFavicon.java index 96e8632..de40951 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFavicon.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFavicon.java
@@ -13,7 +13,6 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.NativeMethods; import org.chromium.chrome.R; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.content_public.browser.WebContents; import org.chromium.url.GURL; @@ -143,16 +142,9 @@ mFaviconWidth = icon.getWidth(); mFaviconHeight = icon.getHeight(); mFaviconTabUrl = currentTabUrl; - if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS)) { - RewindableIterator<TabObserver> observers = mTab.getTabObservers(); - while (observers.hasNext()) observers.next().onFaviconUpdated(mTab, icon, iconUrl); - } + RewindableIterator<TabObserver> observers = mTab.getTabObservers(); + while (observers.hasNext()) observers.next().onFaviconUpdated(mTab, icon, iconUrl); } - - if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS)) return; - // TODO(yfriedman): Remove this code after ANDROID_SCROLL_OPTIMIZATIONS is fully rolled out. - RewindableIterator<TabObserver> observers = mTab.getTabObservers(); - while (observers.hasNext()) observers.next().onFaviconUpdated(mTab, icon, iconUrl); } @NativeMethods
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFaviconTest.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFaviconTest.java index 08c8c43..eb06dce 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFaviconTest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabFaviconTest.java
@@ -28,7 +28,6 @@ import org.chromium.base.UserDataHost; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.test.util.browser.Features; import org.chromium.content_public.browser.WebContents; import org.chromium.url.JUnitTestGURLs; @@ -36,7 +35,6 @@ /** Unit tests for {@link TabFavicon}. */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) -@Features.EnableFeatures(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS) public class TabFaviconTest { private static final int IDEAL_SIZE = 4; @@ -139,4 +137,4 @@ Assert.assertNotNull(bitmap); Assert.assertEquals(Color.GREEN, bitmap.getPixel(0, 0)); } -} \ No newline at end of file +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java index 74576d5..33c74d82 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
@@ -42,8 +42,6 @@ import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate; import org.chromium.chrome.browser.user_education.IPHCommandBuilder; import org.chromium.chrome.browser.user_education.UserEducationHelper; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory; -import org.chromium.chrome.browser.video_tutorials.iph.VideoTutorialTryNowTracker; import org.chromium.components.feature_engagement.EventConstants; import org.chromium.components.feature_engagement.FeatureConstants; import org.chromium.components.feature_engagement.Tracker; @@ -205,7 +203,6 @@ // (e.g. tab switch or in overview mode). if (DeviceFormFactor.isWindowOnTablet(mWindowAndroid)) return; mScreenshotMonitor.startMonitoring(); - mHandler.post(this::showVideoTutorialTryNowUIForDownload); } @Override @@ -310,30 +307,6 @@ .build()); } - /** Show the Try Now UI for video tutorial download feature. */ - private void showVideoTutorialTryNowUIForDownload() { - VideoTutorialTryNowTracker tryNowTracker = VideoTutorialServiceFactory.getTryNowTracker(); - if (!tryNowTracker.didClickTryNowButton( - org.chromium.chrome.browser.video_tutorials.FeatureType.DOWNLOAD)) { - return; - } - - Integer menuItemId = DownloadUtils.isAllowedToDownloadPage(mCurrentTabSupplier.get()) - ? R.id.offline_page_id - : R.id.downloads_menu_id; - - mUserEducationHelper.requestShowIPH( - new IPHCommandBuilder(mActivity.getResources(), null, - R.string.video_tutorials_iph_tap_here_to_start, - R.string.video_tutorials_iph_tap_here_to_start) - .setAnchorView(mMenuButtonAnchorView) - .setOnShowCallback(() -> turnOnHighlightForMenuItem(menuItemId)) - .setOnDismissCallback(this::turnOffHighlightForMenuItem) - .build()); - tryNowTracker.tryNowUIShown( - org.chromium.chrome.browser.video_tutorials.FeatureType.DOWNLOAD); - } - private void turnOnHighlightForMenuItem(Integer highlightMenuItemId) { if (mAppMenuHandler != null) { mAppMenuHandler.setMenuHighlight(highlightMenuItemId);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java index a14c48f..39fd574 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -1378,6 +1378,9 @@ mTabModelSelector = mTabModelSelectorSupplier.get(); mShowStartSurfaceSupplier = showStartSurfaceSupplier; + // Must be initialized before Toolbar attempts to use it. + mLocationBarModel.initializeWithNative(); + mToolbar.initializeWithNative(layoutManager::requestUpdate, tabSwitcherClickHandler, newTabClickHandler, bookmarkClickHandler, customTabsBackClickHandler, mAppMenuDelegate, layoutManager, mActivityTabProvider, mBrowserControlsSizer, @@ -1396,8 +1399,6 @@ } }); - mLocationBarModel.initializeWithNative(); - if (layoutManager != null) { mLayoutManager = layoutManager; mLayoutManager.getOverlayPanelManager().addObserver(mOverlayPanelManagerObserver);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/automotive/backbuttontoolbar/BackButtonToolbarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/automotive/backbuttontoolbar/BackButtonToolbarTest.java index cbfdf82..cf6a132 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/automotive/backbuttontoolbar/BackButtonToolbarTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/automotive/backbuttontoolbar/BackButtonToolbarTest.java
@@ -107,7 +107,7 @@ SettingsActivity settingsActivity = mSettingsActivityTestRule.getActivity(); // Check that the automotive toolbar is present with only a back button. - Toolbar toolbar = settingsActivity.findViewById(R.id.automotive_back_button_toolbar); + Toolbar toolbar = settingsActivity.findViewById(R.id.back_button_toolbar); assertNotNull(toolbar); assertEquals("Toolbar not visible", toolbar.getVisibility(), View.VISIBLE); assertEquals("Toolbar should only contain a back button", toolbar.getChildCount(), 1);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageColorWithFeedV2Test.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageColorWithFeedV2Test.java index 9787c35..e253b0a2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageColorWithFeedV2Test.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageColorWithFeedV2Test.java
@@ -22,14 +22,12 @@ import org.chromium.chrome.browser.feed.v2.FeedV2TestHelper; import org.chromium.chrome.browser.feed.v2.TestFeedServer; import org.chromium.chrome.browser.firstrun.FirstRunUtils; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.R; import org.chromium.chrome.test.util.NewTabPageTestUtils; -import org.chromium.chrome.test.util.browser.Features; import org.chromium.components.browser_ui.styles.ChromeColors; import org.chromium.components.browser_ui.widget.RecyclerViewTestUtils; import org.chromium.components.embedder_support.util.UrlConstants; @@ -44,7 +42,6 @@ @RunWith(ChromeJUnit4ClassRunner.class) @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "disable-features=IPH_FeedHeaderMenu"}) -@Features.DisableFeatures({ChromeFeatureList.QUERY_TILES, ChromeFeatureList.VIDEO_TUTORIALS}) // clang-format on public class NewTabPageColorWithFeedV2Test { private static final int MIN_ITEMS_AFTER_LOAD = 10;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java index 1d376779..6c79720a 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -134,7 +134,7 @@ @ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class) @CommandLineFlags. Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE, "disable-features=IPH_FeedHeaderMenu"}) -@Features.DisableFeatures({ChromeFeatureList.QUERY_TILES, ChromeFeatureList.VIDEO_TUTORIALS}) +@Features.DisableFeatures({ChromeFeatureList.QUERY_TILES}) public class NewTabPageTest { /** * Parameter set controlling whether scrollable mvt is enabled.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java index a27a2ad..ae2aefe 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
@@ -33,7 +33,6 @@ import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.browser.ChromeTabbedActivity; import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeSwitches; import org.chromium.chrome.browser.omnibox.LocationBarDataProvider; import org.chromium.chrome.browser.omnibox.NewTabPageDelegate; @@ -47,8 +46,6 @@ import org.chromium.chrome.test.R; import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.chrome.test.util.browser.Features; -import org.chromium.chrome.test.util.browser.Features.DisableFeatures; -import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.url.GURL; @@ -94,7 +91,6 @@ @Test @SmallTest - @DisableFeatures(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS) public void testDisplayAndEditText() { TestThreadUtils.runOnUiThreadBlocking(() -> { TestLocationBarModel model = new TestLocationBarModel(mActivityTestRule.getActivity()); @@ -123,37 +119,6 @@ model.destroy(); }); } - @Test - @SmallTest - @EnableFeatures(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS) - public void testDisplayAndEditText_optimizationsEnabled() { - TestThreadUtils.runOnUiThreadBlocking(() -> { - TestLocationBarModel model = new TestLocationBarModel(mActivityTestRule.getActivity()); - model.setVisibleGurl(UrlConstants.ntpGurl()); - assertDisplayAndEditText(model, "", null); - - model.setVisibleGurl(new GURL(JUnitTestGURLs.CHROME_ABOUT)); - model.setDisplayUrl(JUnitTestGURLs.CHROME_ABOUT); - model.setFullUrl(JUnitTestGURLs.CHROME_ABOUT); - assertDisplayAndEditText(model, "chrome://about", "chrome://about"); - - model.setVisibleGurl(new GURL(JUnitTestGURLs.URL_1)); - model.setDisplayUrl("https://one.com"); - model.setFullUrl("https://one.com"); - assertDisplayAndEditText(model, "https://one.com", "https://one.com"); - - model.setDisplayUrl("one.com"); - assertDisplayAndEditText(model, "one.com", "https://one.com"); - - // https://crbug.com/1214481 - model.setVisibleGurl(GURL.emptyGURL()); - model.setDisplayUrl("about:blank"); - model.setFullUrl("about:blank"); - assertDisplayAndEditText(model, "about:blank", "about:blank"); - - model.destroy(); - }); - } /** Provides parameters for different types of transitions between tabs. */ public static class IncognitoTransitionParamProvider implements ParameterProvider {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java index 9426f95..ff1b6c0 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
@@ -14,12 +14,14 @@ import androidx.annotation.ColorRes; import androidx.test.filters.SmallTest; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.chromium.base.ContextUtils; @@ -31,6 +33,8 @@ import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.R; import org.chromium.chrome.browser.flags.ChromeFeatureList; +import org.chromium.chrome.browser.omnibox.ChromeAutocompleteSchemeClassifier; +import org.chromium.chrome.browser.omnibox.ChromeAutocompleteSchemeClassifierJni; import org.chromium.chrome.browser.omnibox.NewTabPageDelegate; import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils; import org.chromium.chrome.browser.profiles.Profile; @@ -45,7 +49,10 @@ import org.chromium.components.security_state.SecurityStateModelJni; import org.chromium.content_public.browser.test.NativeLibraryTestUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.url.GURL; +import org.chromium.url.JUnitTestGURLs; +import java.util.Random; import java.util.concurrent.ExecutionException; /** @@ -53,12 +60,10 @@ */ @RunWith(BaseJUnit4ClassRunner.class) @Batch(Batch.UNIT_TESTS) -@Features.DisableFeatures({ChromeFeatureList.OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS, - ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) +@Features.DisableFeatures({ChromeFeatureList.OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS}) public final class ToolbarSecurityIconTest { private static final boolean IS_SMALL_DEVICE = true; private static final boolean IS_OFFLINE_PAGE = true; - private static final boolean IS_PREVIEW = true; private static final boolean IS_PAINT_PREVIEW = true; private static final int[] SECURITY_LEVELS = new int[] {ConnectionSecurityLevel.NONE, ConnectionSecurityLevel.WARNING, @@ -72,16 +77,25 @@ @Mock private TabImpl mTab; + @Mock SecurityStateModel.Natives mSecurityStateMocks; @Mock private LocationBarModel mLocationBarModel; + + @Mock + private LocationBarModel.Natives mLocationBarModelJni; + @Mock private SearchEngineLogoUtils mSearchEngineLogoUtils; @Mock + private ChromeAutocompleteSchemeClassifier.Natives mChromeAutocompleteSchemeClassifierJni; + + @Mock private Profile mMockProfile; + @Mock private TrustedCdn mTrustedCdn; @@ -90,8 +104,24 @@ MockitoAnnotations.initMocks(this); NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess(); - mocker.mock(SecurityStateModelJni.TEST_HOOKS, mSecurityStateMocks); + mocker.mock(ChromeAutocompleteSchemeClassifierJni.TEST_HOOKS, + mChromeAutocompleteSchemeClassifierJni); + mocker.mock(org.chromium.chrome.browser.toolbar.LocationBarModelJni.TEST_HOOKS, + mLocationBarModelJni); + + String exampleUrl = JUnitTestGURLs.EXAMPLE_URL; + GURL exampleGurl = JUnitTestGURLs.getGURL(exampleUrl); + doReturn(exampleGurl) + .when(mLocationBarModelJni) + .getUrlOfVisibleNavigationEntry(Mockito.anyLong(), Mockito.any()); + doReturn(exampleUrl) + .when(mLocationBarModelJni) + .getFormattedFullURL(Mockito.anyLong(), Mockito.any()); + doReturn(exampleUrl) + .when(mLocationBarModelJni) + .getURLForDisplay(Mockito.anyLong(), Mockito.any()); + doReturn((new Random()).nextLong()).when(mLocationBarModelJni).init(Mockito.any()); Context context = new ContextThemeWrapper( ContextUtils.getApplicationContext(), R.style.Theme_BrowserUI_DayNight); @@ -110,6 +140,11 @@ }); } + @After + public void tearDown() throws ExecutionException { + mLocationBarModel.destroy(); + } + @Test @SmallTest @UiThreadTest
diff --git a/chrome/android/junit/DEPS b/chrome/android/junit/DEPS index 1e7a5c9..aafa7c9f 100644 --- a/chrome/android/junit/DEPS +++ b/chrome/android/junit/DEPS
@@ -17,7 +17,6 @@ "+chrome/browser/ui/android/appmenu/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuPropertiesDelegate.java", "+chrome/browser/ui/android/theme/java", "+chrome/browser/ui/messages/android/java", - "+chrome/browser/video_tutorials", "+chrome/browser/xsurface/android", "+components/autofill/android/java/src/org/chromium/components/autofill", "+components/background_task_scheduler/android",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/accessibility/PageZoomIPHControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/accessibility/PageZoomIPHControllerTest.java index 563c21e..a524b23 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/accessibility/PageZoomIPHControllerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/accessibility/PageZoomIPHControllerTest.java
@@ -30,7 +30,6 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Features; import org.chromium.chrome.R; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler; import org.chromium.chrome.browser.user_education.IPHCommand; import org.chromium.chrome.browser.user_education.UserEducationHelper; @@ -63,7 +62,6 @@ public void setUp() { MockitoAnnotations.initMocks(this); - mTestValues.addFeatureFlagOverride(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, true); FeatureList.setTestValues(mTestValues); Resources resources = ApplicationProvider.getApplicationContext().getResources(); @@ -91,4 +89,4 @@ command.onDismissCallback.run(); verify(mAppMenuHandler).clearMenuHighlight(); } -} \ No newline at end of file +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA deleted file mode 100644 index e4c6644..0000000 --- a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA +++ /dev/null
@@ -1,2 +0,0 @@ -mixins: "//chrome/browser/video_tutorials/COMMON_METADATA" -team_email: "chrome-upboarding@chromium.org"
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManagerTest.java deleted file mode 100644 index 842990e5..0000000 --- a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManagerTest.java +++ /dev/null
@@ -1,221 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.app.video_tutorials; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; - -import android.content.Context; -import android.view.ViewStub; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.AdditionalAnswers; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.Callback; -import org.chromium.base.FeatureList; -import org.chromium.base.metrics.UmaRecorderHolder; -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialServiceFactory; -import org.chromium.chrome.browser.video_tutorials.iph.VideoIPHCoordinator; -import org.chromium.chrome.browser.video_tutorials.iph.VideoTutorialIPHUtils; -import org.chromium.chrome.browser.video_tutorials.test.TestVideoTutorialService; -import org.chromium.chrome.test.util.browser.Features; -import org.chromium.components.feature_engagement.EventConstants; -import org.chromium.components.feature_engagement.FeatureConstants; -import org.chromium.components.feature_engagement.Tracker; -import org.chromium.components.feature_engagement.TriggerDetails; -import org.chromium.components.image_fetcher.ImageFetcher; - -import java.util.HashMap; -import java.util.Map; - -/** - * Unit tests for {@link NewTabPageVideoIPHManager}. - */ -@RunWith(BaseRobolectricTestRunner.class) -@Features.EnableFeatures(ChromeFeatureList.VIDEO_TUTORIALS) -public class NewTabPageVideoIPHManagerTest { - @Mock - private Context mContext; - @Mock - private ViewStub mViewStub; - @Mock - private Profile mProfile; - @Mock - private ImageFetcher mImageFetcher; - @Mock - private Tracker mTracker; - @Mock - private VideoIPHCoordinator mVideoIPHCoordinator; - - private TestVideoTutorialService mTestVideoTutorialService; - private TestNewTabPageVideoIPHManager mVideoIPHManager; - private Callback<Tutorial> mIPHClickListener; - private Callback<Tutorial> mIPHDismissListener; - - private class TestNewTabPageVideoIPHManager extends NewTabPageVideoIPHManager { - public boolean videoPlayerLaunched; - public boolean videoListLaunched; - - public TestNewTabPageVideoIPHManager(ViewStub viewStub, Profile profile) { - super(viewStub, profile); - } - - @Override - protected VideoIPHCoordinator createVideoIPHCoordinator(ViewStub viewStub, - ImageFetcher imageFetcher, Callback<Tutorial> clickListener, - Callback<Tutorial> dismissListener) { - mIPHClickListener = clickListener; - mIPHDismissListener = dismissListener; - return mVideoIPHCoordinator; - } - - @Override - protected void launchVideoPlayer(Tutorial tutorial) { - videoPlayerLaunched = true; - } - - @Override - protected void launchTutorialListActivity() { - videoListLaunched = true; - } - - @Override - protected ImageFetcher createImageFetcher(Profile profile) { - return mImageFetcher; - } - } - - @Before - public void setUp() { - UmaRecorderHolder.resetForTesting(); - MockitoAnnotations.initMocks(this); - Mockito.when(mViewStub.getContext()).thenReturn(mContext); - - Map<String, Boolean> features = new HashMap<>(); - features.put(ChromeFeatureList.VIDEO_TUTORIALS, true); - FeatureList.setTestFeatures(features); - - mTestVideoTutorialService = new TestVideoTutorialService(); - VideoTutorialServiceFactory.setVideoTutorialServiceForTesting(mTestVideoTutorialService); - Mockito.doAnswer(AdditionalAnswers.answerVoid( - (Callback<Boolean> callback) -> callback.onResult(true))) - .when(mTracker) - .addOnInitializedCallback(Mockito.any()); - TrackerFactory.setTrackerForTests(mTracker); - } - - @Test - public void testShowFirstEnabledIPH() { - // We have already watched the first tutorial, the second one should show up as IPH card. - Tutorial testTutorial = mTestVideoTutorialService.getTestTutorials().get(1); - Mockito.when(mTracker.shouldTriggerHelpUI(Mockito.anyString())).thenReturn(false, true); - Mockito.when(mTracker.shouldTriggerHelpUIWithSnooze(Mockito.anyString())) - .thenReturn(new TriggerDetails(false, false), new TriggerDetails(true, false)); - mVideoIPHManager = new TestNewTabPageVideoIPHManager(mViewStub, mProfile); - Mockito.verify(mVideoIPHCoordinator).showVideoIPH(testTutorial); - - // Click on the IPH. The video player should be launched. - mIPHClickListener.onResult(testTutorial); - assertThat(mVideoIPHManager.videoPlayerLaunched, equalTo(true)); - assertThat(mVideoIPHManager.videoListLaunched, equalTo(false)); - Mockito.verify(mTracker, Mockito.times(1)) - .notifyEvent(VideoTutorialIPHUtils.getClickEvent(testTutorial.featureType)); - } - - @Test - public void testShowSummaryIPH() { - // We have already seen all the tutorials. Now summary card should show up. - Mockito.when(mTracker.shouldTriggerHelpUI(Mockito.anyString())) - .thenReturn(false, false, false, true); - Mockito.when(mTracker.shouldTriggerHelpUIWithSnooze(Mockito.anyString())) - .thenReturn(new TriggerDetails(false, false), new TriggerDetails(false, false), - new TriggerDetails(false, false), new TriggerDetails(true, false)); - - mVideoIPHManager = new TestNewTabPageVideoIPHManager(mViewStub, mProfile); - - ArgumentCaptor<Tutorial> tutorialArgument = ArgumentCaptor.forClass(Tutorial.class); - Mockito.verify(mVideoIPHCoordinator).showVideoIPH(tutorialArgument.capture()); - assertThat(tutorialArgument.getValue().featureType, equalTo(FeatureType.SUMMARY)); - - // Click on the IPH. Video list activity should be launched. - mIPHClickListener.onResult(tutorialArgument.getValue()); - assertThat(mVideoIPHManager.videoPlayerLaunched, equalTo(false)); - assertThat(mVideoIPHManager.videoListLaunched, equalTo(true)); - } - - @Test - public void testDismissIPH() { - // Show a tutorial IPH. - Tutorial testTutorial = mTestVideoTutorialService.getTestTutorials().get(0); - Mockito.when(mTracker.shouldTriggerHelpUI(Mockito.anyString())).thenReturn(true); - Mockito.when(mTracker.shouldTriggerHelpUIWithSnooze(Mockito.anyString())) - .thenReturn(new TriggerDetails(true, false)); - - mVideoIPHManager = new TestNewTabPageVideoIPHManager(mViewStub, mProfile); - Mockito.verify(mVideoIPHCoordinator).showVideoIPH(testTutorial); - - // Dismiss the IPH. The tracker should record this event. - mIPHDismissListener.onResult(testTutorial); - Mockito.verify(mTracker, Mockito.times(1)) - .notifyEvent(VideoTutorialIPHUtils.getDismissEvent(testTutorial.featureType)); - assertThat(mVideoIPHManager.videoPlayerLaunched, equalTo(false)); - assertThat(mVideoIPHManager.videoListLaunched, equalTo(false)); - } - - @Test - public void testClickEventForFeatureTypes() { - assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.SUMMARY), - equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_SUMMARY)); - assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.CHROME_INTRO), - equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_CHROME_INTRO)); - assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.DOWNLOAD), - equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_DOWNLOAD)); - assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.SEARCH), - equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_SEARCH)); - assertThat(VideoTutorialIPHUtils.getClickEvent(FeatureType.VOICE_SEARCH), - equalTo(EventConstants.VIDEO_TUTORIAL_CLICKED_VOICE_SEARCH)); - } - - @Test - public void testDismissEventForFeatureTypes() { - assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.SUMMARY), - equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_SUMMARY)); - assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.CHROME_INTRO), - equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_CHROME_INTRO)); - assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.DOWNLOAD), - equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_DOWNLOAD)); - assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.SEARCH), - equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_SEARCH)); - assertThat(VideoTutorialIPHUtils.getDismissEvent(FeatureType.VOICE_SEARCH), - equalTo(EventConstants.VIDEO_TUTORIAL_DISMISSED_VOICE_SEARCH)); - } - - @Test - public void testNTPFeatureNameForFeatureTypes() { - assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.SUMMARY), - equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_SUMMARY_FEATURE)); - assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.CHROME_INTRO), - equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_CHROME_INTRO_FEATURE)); - assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.DOWNLOAD), - equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_DOWNLOAD_FEATURE)); - assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.SEARCH), - equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_SEARCH_FEATURE)); - assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.VOICE_SEARCH), - equalTo(FeatureConstants.VIDEO_TUTORIAL_NTP_VOICE_SEARCH_FEATURE)); - assertThat(VideoTutorialIPHUtils.getFeatureNameForNTP(FeatureType.INVALID), equalTo(null)); - } -}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/OWNERS deleted file mode 100644 index 36c3bec..0000000 --- a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://chrome/browser/video_tutorials/OWNERS
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/StaticLayoutUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/StaticLayoutUnitTest.java index 41083d3..6b9cc9f 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/StaticLayoutUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/compositor/layouts/StaticLayoutUnitTest.java
@@ -79,7 +79,7 @@ @Mock private Context mContext; @Mock - private Resources mResource; + private Resources mResources; @Mock private DisplayMetrics mDisplayMetrics; @Mock @@ -135,8 +135,8 @@ mTab1 = prepareTab(TAB1_ID, JUnitTestGURLs.getGURL(TAB1_URL)); mTab2 = prepareTab(TAB2_ID, JUnitTestGURLs.getGURL(TAB2_URL)); - doReturn(mResource).when(mContext).getResources(); - doReturn(mDisplayMetrics).when(mResource).getDisplayMetrics(); + doReturn(mResources).when(mContext).getResources(); + doReturn(mDisplayMetrics).when(mResources).getDisplayMetrics(); mDisplayMetrics.density = 1; doReturn(mTabModel).when(mTabModel).getComprehensiveModel();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/desktop_site/DesktopSiteSettingsIPHControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/desktop_site/DesktopSiteSettingsIPHControllerUnitTest.java index bdefe8046..853b4e3 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/desktop_site/DesktopSiteSettingsIPHControllerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/desktop_site/DesktopSiteSettingsIPHControllerUnitTest.java
@@ -122,7 +122,6 @@ MockitoAnnotations.initMocks(this); mJniMocker.mock(WebsitePreferenceBridgeJni.TEST_HOOKS, mWebsitePreferenceBridgeJniMock); - enableFeatureWithParams(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, null); enableFeatureWithParams(ChromeFeatureList.REQUEST_DESKTOP_SITE_PER_SITE_IPH, null); Resources resources = ApplicationProvider.getApplicationContext().getResources();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/read_later/ReadLaterIPHControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/read_later/ReadLaterIPHControllerUnitTest.java index d627a92..b96f2c6 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/read_later/ReadLaterIPHControllerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/read_later/ReadLaterIPHControllerUnitTest.java
@@ -28,17 +28,14 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.R; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler; import org.chromium.chrome.browser.user_education.IPHCommand; import org.chromium.chrome.browser.user_education.UserEducationHelper; -import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.JUnitProcessor; /** Unit test for {@link ReadLaterIPHController}. */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) -@DisableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) public class ReadLaterIPHControllerUnitTest { @Rule public TestRule mFeaturesProcessor = new JUnitProcessor(); @@ -90,4 +87,4 @@ command.onDismissCallback.run(); verify(mAppMenuHandler).clearMenuHighlight(); } -} \ No newline at end of file +}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java index 5b17428..900a1cf 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java
@@ -4,15 +4,13 @@ package org.chromium.chrome.browser.toolbar; -import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.text.SpannableStringBuilder; -import android.util.LruCache; import android.view.ContextThemeWrapper; import androidx.annotation.Nullable; @@ -52,7 +50,6 @@ import org.chromium.chrome.features.start_surface.StartSurfaceState; import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features.DisableFeatures; -import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.components.dom_distiller.core.DomDistillerUrlUtilsJni; import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.omnibox.OmniboxUrlEmphasizerJni; @@ -67,8 +64,7 @@ */ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE, shadows = {ShadowGURL.class, ShadowTrustedCdn.class}) -@DisableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, - ChromeFeatureList.OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS}) +@DisableFeatures({ChromeFeatureList.OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS}) @SuppressWarnings("DoNotMock") // Mocks GURL public class LocationBarModelUnitTest { @Implements(TrustedCdn.class) @@ -127,6 +123,8 @@ public void setUp() { MockitoAnnotations.initMocks(this); Profile.setLastUsedProfileForTesting(mRegularProfileMock); + mJniMocker.mock(ChromeAutocompleteSchemeClassifierJni.TEST_HOOKS, + mChromeAutocompleteSchemeClassifierJni); mJniMocker.mock(LocationBarModelJni.TEST_HOOKS, mLocationBarModelJni); mJniMocker.mock(UrlFormatterJni.TEST_HOOKS, mUrlFormatterJniMock); mJniMocker.mock(DomDistillerUrlUtilsJni.TEST_HOOKS, mDomDistillerUrlUtilsJni); @@ -193,6 +191,7 @@ incognitoLocationBarModel.initializeWithNative(); Profile otrProfile = incognitoLocationBarModel.getProfile(); Assert.assertEquals(mPrimaryOTRProfileMock, otrProfile); + incognitoLocationBarModel.destroy(); } @Test @@ -203,6 +202,7 @@ incognitoLocationBarModel.initializeWithNative(); Profile otrProfile = incognitoLocationBarModel.getProfile(); Assert.assertEquals(mNonPrimaryOTRProfileMock, otrProfile); + incognitoLocationBarModel.destroy(); } @Test @@ -213,6 +213,7 @@ incognitoLocationBarModel.initializeWithNative(); Profile otrProfile = incognitoLocationBarModel.getProfile(); Assert.assertEquals(mPrimaryOTRProfileMock, otrProfile); + incognitoLocationBarModel.destroy(); } @Test @@ -223,6 +224,7 @@ regularLocationBarModel.initializeWithNative(); Profile profile = regularLocationBarModel.getProfile(); Assert.assertEquals(mRegularProfileMock, profile); + regularLocationBarModel.destroy(); } @Test @@ -233,6 +235,7 @@ regularLocationBarModel.initializeWithNative(); Profile profile = regularLocationBarModel.getProfile(); Assert.assertEquals(mRegularProfileMock, profile); + regularLocationBarModel.destroy(); } @Test @@ -257,20 +260,38 @@ @Test @MediumTest public void testObserversNotified_urlChange() { + doReturn(123L).when(mLocationBarModelJni).init(Mockito.any()); LocationBarModel regularLocationBarModel = new TestRegularLocationBarModel(null, mSearchEngineLogoUtils); + regularLocationBarModel.initializeWithNative(); regularLocationBarModel.addObserver(mLocationBarDataObserver); + + String url = "http://www.example.com/"; + doReturn(url).when(mMockGurl).getSpec(); + doReturn(mMockGurl) + .when(mLocationBarModelJni) + .getUrlOfVisibleNavigationEntry(Mockito.anyLong(), Mockito.any()); + regularLocationBarModel.updateVisibleGurl(); + + // The visible url should be cached and hasn't changed, so onUrlChanged shouldn't be called + regularLocationBarModel.notifyUrlChanged(); verify(mLocationBarDataObserver, never()).onUrlChanged(); - regularLocationBarModel.notifyUrlChanged(); - verify(mLocationBarDataObserver).onUrlChanged(); - + // Setting to a new tab with a different url + String url2 = "http://www.example2.com/"; + GURL mMockGurl2 = Mockito.mock(GURL.class); + doReturn(url2).when(mMockGurl2).getSpec(); + doReturn(mMockGurl2) + .when(mLocationBarModelJni) + .getUrlOfVisibleNavigationEntry(Mockito.anyLong(), Mockito.any()); regularLocationBarModel.setTab(mRegularTabMock, false); - verify(mLocationBarDataObserver, times(2)).onUrlChanged(); + verify(mLocationBarDataObserver).onUrlChanged(); regularLocationBarModel.removeObserver(mLocationBarDataObserver); regularLocationBarModel.notifyUrlChanged(); - verify(mLocationBarDataObserver, times(2)).onUrlChanged(); + verify(mLocationBarDataObserver).onUrlChanged(); + + regularLocationBarModel.destroy(); } @Test @@ -288,9 +309,15 @@ @Test @MediumTest public void testObserversNotified_setIsShowingTabSwitcher() { + doReturn(123L).when(mLocationBarModelJni).init(Mockito.any()); LocationBarModel regularLocationBarModel = new TestRegularLocationBarModel(null, mSearchEngineLogoUtils); + regularLocationBarModel.initializeWithNative(); regularLocationBarModel.addObserver(mLocationBarDataObserver); + doReturn(mMockGurl) + .when(mLocationBarModelJni) + .getUrlOfVisibleNavigationEntry(Mockito.anyLong(), Mockito.any()); + regularLocationBarModel.updateVisibleGurl(); verify(mLocationBarDataObserver, never()).onTitleChanged(); verify(mLocationBarDataObserver, never()).onUrlChanged(); @@ -298,100 +325,53 @@ verify(mLocationBarDataObserver, never()).onSecurityStateChanged(); regularLocationBarModel.updateForNonStaticLayout(true, false); + + // The omnibox is not showing, and we have not switched to a new tab yet, so don't expect + // notifications of a url change + verify(mLocationBarDataObserver, never()).onUrlChanged(); + Assert.assertEquals(regularLocationBarModel.getCurrentGurl(), mMockGurl); + verify(mLocationBarDataObserver).onTitleChanged(); - verify(mLocationBarDataObserver).onUrlChanged(); verify(mLocationBarDataObserver).onPrimaryColorChanged(); verify(mLocationBarDataObserver).onSecurityStateChanged(); + + regularLocationBarModel.destroy(); } @Test @MediumTest public void testObserversNotified_setIsShowingStartSurface() { + doReturn(123L).when(mLocationBarModelJni).init(Mockito.any()); LocationBarModel regularLocationBarModel = new TestRegularLocationBarModel(null, mSearchEngineLogoUtils); + regularLocationBarModel.initializeWithNative(); regularLocationBarModel.addObserver(mLocationBarDataObserver); + doReturn(mMockGurl) + .when(mLocationBarModelJni) + .getUrlOfVisibleNavigationEntry(Mockito.anyLong(), Mockito.any()); + regularLocationBarModel.updateVisibleGurl(); verify(mLocationBarDataObserver, never()).onTitleChanged(); verify(mLocationBarDataObserver, never()).onUrlChanged(); verify(mLocationBarDataObserver, never()).onPrimaryColorChanged(); verify(mLocationBarDataObserver, never()).onSecurityStateChanged(); + regularLocationBarModel.setShouldShowOmniboxInOverviewMode(true); + regularLocationBarModel.setLayoutStateProvider(mLayoutStateProvider); regularLocationBarModel.updateForNonStaticLayout(false, true); + verify(mLocationBarDataObserver).onTitleChanged(); verify(mLocationBarDataObserver).onUrlChanged(); - verify(mLocationBarDataObserver).onPrimaryColorChanged(); + verify(mLocationBarDataObserver, atLeast(1)).onPrimaryColorChanged(); verify(mLocationBarDataObserver).onSecurityStateChanged(); + + regularLocationBarModel.destroy(); } - @EnableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) @Test @MediumTest public void testSpannableCache() { doReturn(123L).when(mLocationBarModelJni).init(Mockito.any()); - mJniMocker.mock(ChromeAutocompleteSchemeClassifierJni.TEST_HOOKS, - mChromeAutocompleteSchemeClassifierJni); - LocationBarModel regularLocationBarModel = - new TestRegularLocationBarModel(mRegularTabMock, mSearchEngineLogoUtils); - doReturn(true).when(mRegularTabMock).isInitialized(); - regularLocationBarModel.initializeWithNative(); - LruCache<LocationBarModel.SpannableDisplayTextCacheKey, SpannableStringBuilder> cache = - regularLocationBarModel.getCacheForTesting(); - Assert.assertEquals(cache.size(), 0); - - String url = "http://www.example.com/"; - doReturn(url).when(mMockGurl).getSpec(); - doReturn(mMockGurl) - .when(mLocationBarModelJni) - .getUrlOfVisibleNavigationEntry(Mockito.anyLong(), Mockito.any()); - doReturn(url) - .when(mLocationBarModelJni) - .getFormattedFullURL(Mockito.anyLong(), Mockito.any()); - doReturn(url).when(mLocationBarModelJni).getURLForDisplay(Mockito.anyLong(), Mockito.any()); - regularLocationBarModel.updateVisibleGurl(); - doReturn(mMockGurl).when(mUrlFormatterJniMock).fixupUrl(url); - doReturn(new int[] {0, 7, 7, 15}) - .when(mOmniboxUrlEmphasizerJni) - .parseForEmphasizeComponents(any(), any()); - regularLocationBarModel.getUrlBarData(); - Assert.assertEquals(cache.size(), 1); - regularLocationBarModel.getUrlBarData(); - Assert.assertEquals(cache.hitCount(), 1); - - regularLocationBarModel.destroy(); - } - - @DisableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) - @Test - @MediumTest - public void testNoCacheWhenScrollOptimizationsDisabled() { - doReturn(123L).when(mLocationBarModelJni).init(Mockito.any()); - mJniMocker.mock(ChromeAutocompleteSchemeClassifierJni.TEST_HOOKS, - mChromeAutocompleteSchemeClassifierJni); - LocationBarModel regularLocationBarModel = - new TestRegularLocationBarModel(mRegularTabMock, mSearchEngineLogoUtils); - doReturn(true).when(mRegularTabMock).isInitialized(); - regularLocationBarModel.initializeWithNative(); - - String url = "http://www.example.com/"; - doReturn(url).when(mMockGurl).getSpec(); - doReturn(mMockGurl) - .when(mLocationBarModelJni) - .getUrlOfVisibleNavigationEntry(Mockito.anyLong(), Mockito.any()); - doReturn(url) - .when(mLocationBarModelJni) - .getFormattedFullURL(Mockito.anyLong(), Mockito.any()); - doReturn(url).when(mLocationBarModelJni).getURLForDisplay(Mockito.anyLong(), Mockito.any()); - Assert.assertTrue(regularLocationBarModel.updateVisibleGurl()); - regularLocationBarModel.destroy(); - } - - @EnableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) - @Test - @MediumTest - public void testCacheWhenScrollOptimizationsEnabled() { - doReturn(123L).when(mLocationBarModelJni).init(Mockito.any()); - mJniMocker.mock(ChromeAutocompleteSchemeClassifierJni.TEST_HOOKS, - mChromeAutocompleteSchemeClassifierJni); LocationBarModel regularLocationBarModel = new TestRegularLocationBarModel(mRegularTabMock, mSearchEngineLogoUtils); doReturn(true).when(mRegularTabMock).isInitialized(); @@ -429,35 +409,32 @@ regularLocationBarModel.destroy(); } - @EnableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) @Test @MediumTest public void testUpdateVisibleGurlStartSurfaceShowing() { doReturn(123L).when(mLocationBarModelJni).init(Mockito.any()); - mJniMocker.mock(ChromeAutocompleteSchemeClassifierJni.TEST_HOOKS, - mChromeAutocompleteSchemeClassifierJni); LocationBarModel regularLocationBarModel = new TestRegularLocationBarModel(mRegularTabMock, mSearchEngineLogoUtils); doReturn(true).when(mRegularTabMock).isInitialized(); + doReturn(mMockGurl) + .when(mLocationBarModelJni) + .getUrlOfVisibleNavigationEntry(Mockito.anyLong(), Mockito.any()); + regularLocationBarModel.initializeWithNative(); regularLocationBarModel.setShouldShowOmniboxInOverviewMode(true); regularLocationBarModel.setLayoutStateProvider(mLayoutStateProvider); regularLocationBarModel.addObserver(mLocationBarDataObserver); - doReturn(mMockGurl) - .when(mLocationBarModelJni) - .getUrlOfVisibleNavigationEntry(Mockito.anyLong(), Mockito.any()); - Assert.assertNotEquals(regularLocationBarModel.getCurrentGurl(), UrlConstants.ntpGurl()); + + regularLocationBarModel.updateVisibleGurl(); + Assert.assertEquals(regularLocationBarModel.getCurrentGurl(), mMockGurl); regularLocationBarModel.updateForNonStaticLayout(true, false); - verify(mLocationBarDataObserver).onUrlChanged(); regularLocationBarModel.setStartSurfaceState(StartSurfaceState.SHOWN_HOMEPAGE); - - verify(mLocationBarDataObserver, times(2)).onUrlChanged(); + verify(mLocationBarDataObserver).onUrlChanged(); Assert.assertEquals(regularLocationBarModel.getCurrentGurl(), UrlConstants.ntpGurl()); regularLocationBarModel.setStartSurfaceState(StartSurfaceState.NOT_SHOWN); - - verify(mLocationBarDataObserver, times(3)).onUrlChanged(); + verify(mLocationBarDataObserver, times(2)).onUrlChanged(); Assert.assertEquals(regularLocationBarModel.getCurrentGurl(), mMockGurl); regularLocationBarModel.destroy();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java index b597fb3..ff68a55 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediatorUnitTest.java
@@ -83,7 +83,6 @@ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE) @LooperMode(LooperMode.Mode.LEGACY) -@DisableFeatures(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS) public class StartSurfaceToolbarMediatorUnitTest { private PropertyModel mPropertyModel; private StartSurfaceToolbarMediator mMediator;
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index 11056ec..932808ba 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd
@@ -1720,6 +1720,18 @@ </message> </if> </if> + + <!-- Payments settings DeviceAuthentication strings --> + <if expr="is_macosx"> + <message name="IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT" desc="Message to be displayed to the user in the device authentication prompt when they click on the mandatory auth toggle on the Payments settings page, irrespective to enable or disable it. When mandatory auth toggle is enabled, we would authenticate the user before autofilling in the payment details. Note: MacOS has the wording 'Chromium is trying to' prepended onto the message during user auth."> + modify settings for filling payment methods. + </message> + </if> + <if expr="is_win"> + <message name="IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT" desc="Message to be displayed to the user in the device authentication prompt when they click on the mandatory auth toggle on the Payments settings page, irrespective to enable or disable it. When mandatory auth toggle is enabled, we would authenticate the user before autofilling in the payment details."> + Chromium is trying to modify settings for filling payment methods. + </message> + </if> </messages> </release> </grit>
diff --git a/chrome/app/chromium_strings_grd/IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT.png.sha1 b/chrome/app/chromium_strings_grd/IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT.png.sha1 new file mode 100644 index 0000000..f503b05 --- /dev/null +++ b/chrome/app/chromium_strings_grd/IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT.png.sha1
@@ -0,0 +1 @@ +806044854b5e53130c7152ec21dae790de989851 \ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index cd728eed..badd84b0 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -2656,7 +2656,7 @@ </message> <message name="IDS_DOWNLOAD_BUBBLE_STATUS_DEEP_SCANNING_DONE" desc="When a download has finished deep scanning and the result is safe, let the user know."> - Done, no issues found + Scan is done </message> <message name="IDS_DOWNLOAD_BUBBLE_STATUS_BLOCKED" desc="When a download is blocked because of warnings, let the user know.">
diff --git a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_STATUS_DEEP_SCANNING_DONE.png.sha1 b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_STATUS_DEEP_SCANNING_DONE.png.sha1 index 7117056..285b5af 100644 --- a/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_STATUS_DEEP_SCANNING_DONE.png.sha1 +++ b/chrome/app/generated_resources_grd/IDS_DOWNLOAD_BUBBLE_STATUS_DEEP_SCANNING_DONE.png.sha1
@@ -1 +1 @@ -0da76380b25fd33750d5763c6709f60d5af37f9e \ No newline at end of file +61160924ee2f4cb10869287edbf0f640b874326d \ No newline at end of file
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index a4f04c3..7937843 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd
@@ -1820,6 +1820,18 @@ </message> </if> </if> + + <!-- Payments settings DeviceAuthentication strings --> + <if expr="is_macosx"> + <message name="IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT" desc="Message to be displayed to the user in the device authentication prompt when they click on the mandatory auth toggle on the Payments settings page, irrespective to enable or disable it. When mandatory auth toggle is enabled, we would authenticate the user before autofilling in the payment details. Note: MacOS has the wording 'Google Chrome is trying to' prepended onto the message during user auth."> + modify settings for filling payment methods. + </message> + </if> + <if expr="is_win"> + <message name="IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT" desc="Message to be displayed to the user in the device authentication prompt when they click on the mandatory auth toggle on the Payments settings page, irrespective to enable or disable it. When mandatory auth toggle is enabled, we would authenticate the user before autofilling in the payment details."> + Google Chrome is trying to modify settings for filling payment methods. + </message> + </if> </messages> </release> </grit>
diff --git a/chrome/app/google_chrome_strings_grd/IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT.png.sha1 b/chrome/app/google_chrome_strings_grd/IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT.png.sha1 new file mode 100644 index 0000000..f503b05 --- /dev/null +++ b/chrome/app/google_chrome_strings_grd/IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT.png.sha1
@@ -0,0 +1 @@ +806044854b5e53130c7152ec21dae790de989851 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 106be4c..bf8b031f 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -1814,8 +1814,6 @@ "usb/web_usb_histograms.h", "user_bypass/user_bypass_web_contents_observer.cc", "user_bypass/user_bypass_web_contents_observer.h", - "video_tutorials/video_tutorial_service_factory.cc", - "video_tutorials/video_tutorial_service_factory.h", "visibility_timer_tab_helper.cc", "visibility_timer_tab_helper.h", "vr/ui_suppressed_element.h", @@ -2011,7 +2009,6 @@ "//chrome/browser/ui/webui/suggest_internals:mojo_bindings", "//chrome/browser/ui/webui/usb_internals:mojo_bindings", "//chrome/browser/updates/announcement_notification", - "//chrome/browser/video_tutorials", "//chrome/browser/web_applications/mojom:mojom_web_apps_enum", "//chrome/browser/web_share_target", "//chrome/common:channel_info", @@ -3234,7 +3231,6 @@ "usb/android/usb_bridge.cc", "usb/android/web_usb_chooser_android.cc", "usb/android/web_usb_chooser_android.h", - "video_tutorials/internal/android/video_tutorial_service_bridge_factory.cc", "webapps/web_app_offline_android.cc", "webauthn/android/cable_module_android.cc", "webauthn/android/chrome_webauthn_client_android.cc", @@ -3312,8 +3308,6 @@ "//chrome/browser/ui/android/layouts:android", "//chrome/browser/ui/webui/feed_internals:mojo_bindings", "//chrome/browser/usb/android:jni_headers", - "//chrome/browser/video_tutorials/internal", - "//chrome/browser/video_tutorials/internal:jni_headers", "//chrome/common:non_code_constants", "//chrome/services/media_gallery_util/public/cpp", "//components/background_sync", @@ -3659,6 +3653,8 @@ "enterprise/connectors/reporting/crash_reporting_context.h", "enterprise/connectors/reporting/extension_install_event_router.cc", "enterprise/connectors/reporting/extension_install_event_router.h", + "enterprise/connectors/reporting/metrics_utils.cc", + "enterprise/connectors/reporting/metrics_utils.h", "enterprise/connectors/reporting/realtime_reporting_client.cc", "enterprise/connectors/reporting/realtime_reporting_client.h", "enterprise/connectors/reporting/realtime_reporting_client_factory.cc", @@ -7820,10 +7816,7 @@ } if (is_android) { - deps += [ - "//chrome/browser/resources/offline_pages:build_ts", - "//chrome/browser/resources/video_tutorials:build_ts", - ] + deps += [ "//chrome/browser/resources/offline_pages:build_ts" ] } if (!is_android) { deps += [ "//chrome/browser/resources/media_router/internals:build_ts" ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 2fd12c7f..538c9ec5 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -63,7 +63,6 @@ #include "chrome/browser/ui/ui_features.h" #include "chrome/browser/unexpire_flags.h" #include "chrome/browser/unexpire_flags_gen.h" -#include "chrome/browser/video_tutorials/switches.h" #include "chrome/browser/webauthn/webauthn_switches.h" #include "chrome/common/buildflags.h" #include "chrome/common/channel_info.h" @@ -4908,9 +4907,6 @@ flag_descriptions::kQueryTilesSwapTrendingDescription, kOsAndroid, FEATURE_VALUE_TYPE( query_tiles::features::kQueryTilesRemoveTrendingTilesAfterInactivity)}, - {"video-tutorials", flag_descriptions::kVideoTutorialsName, - flag_descriptions::kVideoTutorialsDescription, kOsAndroid, - FEATURE_VALUE_TYPE(video_tutorials::features::kVideoTutorials)}, {"reengagement-notification", flag_descriptions::kReengagementNotificationName, flag_descriptions::kReengagementNotificationDescription, kOsAndroid, @@ -8702,6 +8698,14 @@ kPasswordStrengthIndicatorVariations, "PasswordStrengthIndicator")}, +#if !BUILDFLAG(IS_ANDROID) + {"password-generation-experiment", + flag_descriptions::kPasswordGenerationExperimentName, + flag_descriptions::kPasswordGenerationExperimentDescription, kOsDesktop, + FEATURE_VALUE_TYPE( + password_manager::features::kPasswordGenerationExperiment)}, +#endif + #if BUILDFLAG(IS_ANDROID) {"privacy-guide-android", flag_descriptions::kPrivacyGuideAndroidName, flag_descriptions::kPrivacyGuideAndroidDescription, kOsAndroid, @@ -9735,6 +9739,11 @@ {"cloud-ap-auth", flag_descriptions::kCloudApAuthName, flag_descriptions::kCloudApAuthDescription, kOsWin, FEATURE_VALUE_TYPE(enterprise_auth::kCloudApAuth)}, + + {"cloud-ap-auth-attach-as-header", + flag_descriptions::kCloudApAuthAttachAsHeaderName, + flag_descriptions::kCloudApAuthAttachAsHeaderDescription, kOsWin, + FEATURE_VALUE_TYPE(enterprise_auth::kCloudApAuthAttachAsHeader)}, #endif // BUILDFLAG(IS_WIN) #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/about_flags_browsertest.cc b/chrome/browser/about_flags_browsertest.cc index 57aaf99..8252c2f7 100644 --- a/chrome/browser/about_flags_browsertest.cc +++ b/chrome/browser/about_flags_browsertest.cc
@@ -61,7 +61,7 @@ void SimulateTextType(content::WebContents* contents, const char* experiment_id, const char* text) { - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( contents, base::StringPrintf( "var parent = document.getElementById('%s');" "var textarea = parent.getElementsByTagName('textarea')[0];" @@ -74,7 +74,7 @@ void ToggleEnableDropdown(content::WebContents* contents, const char* experiment_id, bool enable) { - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( contents, base::StringPrintf( "var k = document.getElementById('%s');"
diff --git a/chrome/browser/ash/arc/input_overlay/ui/action_label.cc b/chrome/browser/ash/arc/input_overlay/ui/action_label.cc index 42b57a9..f18f318 100644 --- a/chrome/browser/ash/arc/input_overlay/ui/action_label.cc +++ b/chrome/browser/ash/arc/input_overlay/ui/action_label.cc
@@ -563,9 +563,10 @@ auto* focus_ring = views::FocusRing::Get(this); focus_ring->SetHaloInset(kHaloInset); focus_ring->SetHaloThickness(kHaloThickness); - focus_ring->SetHasFocusPredicate([](views::View* view) { - return view->IsMouseHovered() || view->HasFocus(); - }); + focus_ring->SetHasFocusPredicate( + base::BindRepeating([](const views::View* view) { + return view->IsMouseHovered() || view->HasFocus(); + })); SetEnabledTextColors(kTextColorDefault);
diff --git a/chrome/browser/ash/file_manager/external_filesystem_apitest.cc b/chrome/browser/ash/file_manager/external_filesystem_apitest.cc index 6e47173..0bbb8ec 100644 --- a/chrome/browser/ash/file_manager/external_filesystem_apitest.cc +++ b/chrome/browser/ash/file_manager/external_filesystem_apitest.cc
@@ -125,7 +125,7 @@ self.testNameToRun = '$1'; } )"; - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( navigation_handle->GetRenderFrameHost(), base::ReplaceStringPlaceholders(kScript, {test_name_}, nullptr)));
diff --git a/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc b/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc index 3a853b0..91c9db27b 100644 --- a/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc +++ b/chrome/browser/ash/login/configuration_based_oobe_browsertest.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/ash/login/test/oobe_base_test.h" #include "chrome/browser/ash/login/test/oobe_configuration_waiter.h" #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" +#include "chrome/browser/ash/login/test/oobe_screens_utils.h" #include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/ash/policy/enrollment/enrollment_requisition_manager.h" #include "chrome/browser/browser_process.h" @@ -170,7 +171,7 @@ // welcome screen is not automated. IN_PROC_BROWSER_TEST_F(OobeConfigurationTest, TestConnectedNetworkNoWelcome) { LoadConfiguration(); - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); } // Check that when configuration has ONC and EULA, we get to update screen.
diff --git a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc index e052af76..f3e0b8cb 100644 --- a/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc +++ b/chrome/browser/ash/login/demo_mode/demo_setup_browsertest.cc
@@ -753,7 +753,7 @@ test::WaitForNetworkSelectionScreen(); test::OobeJS().ClickOnPath(kNetworkBackButton); - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); } IN_PROC_BROWSER_TEST_F(DemoSetupArcSupportedTest, BackOnTermsScreen) { @@ -798,7 +798,7 @@ test::OobeJS().ExpectEnabledPath(kDemoSetupErrorDialogBack); test::OobeJS().ClickOnPath(kDemoSetupErrorDialogBack); - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); } // TODO(crbug.com/1399073): Flaky on ChromeOS.
diff --git a/chrome/browser/ash/login/error_screen_browsertest.cc b/chrome/browser/ash/login/error_screen_browsertest.cc index cf36c8c..ce4c6bb3 100644 --- a/chrome/browser/ash/login/error_screen_browsertest.cc +++ b/chrome/browser/ash/login/error_screen_browsertest.cc
@@ -72,7 +72,7 @@ InProcessBrowserTest::SetUpOnMainThread(); ShowLoginWizard(WelcomeView::kScreenId); - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); } void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/ash/login/login_browsertest.cc b/chrome/browser/ash/login/login_browsertest.cc index 7588323e..3c2e09f 100644 --- a/chrome/browser/ash/login/login_browsertest.cc +++ b/chrome/browser/ash/login/login_browsertest.cc
@@ -291,7 +291,7 @@ // Verifies the cursor is hidden at startup on login screen. IN_PROC_BROWSER_TEST_F(LoginCursorTest, CursorHidden) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); // Cursor should be hidden at startup EXPECT_FALSE(Shell::Get()->cursor_manager()->IsCursorVisible());
diff --git a/chrome/browser/ash/login/login_ui_browsertest.cc b/chrome/browser/ash/login/login_ui_browsertest.cc index 3347721ae..8304a37 100644 --- a/chrome/browser/ash/login/login_ui_browsertest.cc +++ b/chrome/browser/ash/login/login_ui_browsertest.cc
@@ -23,6 +23,7 @@ #include "chrome/browser/ash/login/test/login_manager_mixin.h" #include "chrome/browser/ash/login/test/oobe_base_test.h" #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" +#include "chrome/browser/ash/login/test/oobe_screens_utils.h" #include "chrome/browser/ash/login/test/scoped_policy_update.h" #include "chrome/browser/ash/login/test/test_predicate_waiter.h" #include "chrome/browser/ash/login/test/user_policy_mixin.h" @@ -71,11 +72,11 @@ // Tests that the default first screen is the welcome screen after OOBE // when auto enrollment is enabled and device is not yet enrolled. IN_PROC_BROWSER_TEST_F(InterruptedAutoStartEnrollmentTest, ShowsWelcome) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); } IN_PROC_BROWSER_TEST_F(OobeBaseTest, OobeNoExceptions) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); OobeBaseTest::CheckJsExceptionErrors(0); }
diff --git a/chrome/browser/ash/login/oobe_browsertest.cc b/chrome/browser/ash/login/oobe_browsertest.cc index 49e37523..e8d71d1 100644 --- a/chrome/browser/ash/login/oobe_browsertest.cc +++ b/chrome/browser/ash/login/oobe_browsertest.cc
@@ -16,6 +16,7 @@ #include "chrome/browser/ash/login/test/local_state_mixin.h" #include "chrome/browser/ash/login/test/oobe_base_test.h" #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" +#include "chrome/browser/ash/login/test/oobe_screens_utils.h" #include "chrome/browser/ash/login/test/session_manager_state_waiter.h" #include "chrome/browser/ash/login/ui/login_display_host_webui.h" #include "chrome/browser/ash/login/wizard_context.h" @@ -172,7 +173,7 @@ }; IN_PROC_BROWSER_TEST_F(InvalidPendingScreenTest, WelcomeScreenShown) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); } class DisplayOobeTest : public OobeBaseTest {
diff --git a/chrome/browser/ash/login/reset_browsertest.cc b/chrome/browser/ash/login/reset_browsertest.cc index 25b52b4..f55e99a 100644 --- a/chrome/browser/ash/login/reset_browsertest.cc +++ b/chrome/browser/ash/login/reset_browsertest.cc
@@ -304,7 +304,7 @@ } IN_PROC_BROWSER_TEST_F(ResetOobeTest, ResetOnWelcomeScreen) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown()); InvokeResetScreen(); @@ -316,12 +316,12 @@ } IN_PROC_BROWSER_TEST_F(ResetOobeTest, RequestAndCancleResetOnWelcomeScreen) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown()); InvokeResetScreen(); ClickCancelButton(); - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); EXPECT_FALSE(LoginScreenTestApi::IsGuestButtonShown()); EXPECT_EQ(
diff --git a/chrome/browser/ash/login/screens/hid_detection_screen_browsertest.cc b/chrome/browser/ash/login/screens/hid_detection_screen_browsertest.cc index 39389db..67302d4 100644 --- a/chrome/browser/ash/login/screens/hid_detection_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/hid_detection_screen_browsertest.cc
@@ -140,7 +140,7 @@ // Simulate the user's click on "Continue" button. test::OobeJS().CreateVisibilityWaiter(true, kHidContinueButton)->Wait(); test::OobeJS().TapOnPath(kHidContinueButton); - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); } protected: @@ -681,7 +681,7 @@ test::OobeJS().TapOnPath(kHidContinueButton); EXPECT_EQ(GetExitResult(), HIDDetectionScreen::Result::NEXT); - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::TapWelcomeNext(); OobeScreenWaiter(NetworkScreenView::kScreenId).Wait(); } @@ -729,7 +729,7 @@ INSTANTIATE_TEST_SUITE_P(All, HIDDetectionSkipTest, testing::Bool()); IN_PROC_BROWSER_TEST_P(HIDDetectionSkipTest, BothDevicesPreConnected) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); AssertInitialHidsMissingCount(HidsMissing::kNone, /*count=*/1); EXPECT_FALSE(GetExitResult().has_value()); histogram_tester.ExpectTotalCount("OOBE.HidDetectionScreen.HidConnected", 0); @@ -795,7 +795,7 @@ IN_PROC_BROWSER_TEST_P(HIDDetectionScreenDisabledAfterRestartTest, PRE_SkipToUpdate) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); EXPECT_TRUE(StartupUtils::IsHIDDetectionScreenDisabledForTests()); EXPECT_FALSE(WizardController::default_controller()->HasScreen( @@ -804,7 +804,7 @@ IN_PROC_BROWSER_TEST_P(HIDDetectionScreenDisabledAfterRestartTest, SkipToUpdate) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); // The pref should persist restart. EXPECT_TRUE(StartupUtils::IsHIDDetectionScreenDisabledForTests()); EXPECT_FALSE(WizardController::default_controller()->HasScreen( @@ -820,7 +820,7 @@ IN_PROC_BROWSER_TEST_F(HIDDetectionScreenChromebookTest, HIDDetectionScreenNotAllowed) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); ASSERT_TRUE(WizardController::default_controller()); EXPECT_FALSE(WizardController::default_controller()->HasScreen(
diff --git a/chrome/browser/ash/login/screens/os_install_screen_browsertest.cc b/chrome/browser/ash/login/screens/os_install_screen_browsertest.cc index e200f10..ef1c2e6a 100644 --- a/chrome/browser/ash/login/screens/os_install_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/os_install_screen_browsertest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/ash/login/screens/welcome_screen.h" #include "chrome/browser/ash/login/test/oobe_base_test.h" #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" +#include "chrome/browser/ash/login/test/oobe_screens_utils.h" #include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/ui/webui/ash/login/network_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/os_install_screen_handler.h" @@ -87,7 +88,7 @@ } void AdvanceToOsInstallScreen() { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath(kWelcomeGetStarted); OobeScreenWaiter(OsTrialScreenView::kScreenId).Wait(); @@ -144,7 +145,7 @@ // If the kAllowOsInstall switch is not set, clicking `Get Started` button // should show the network screen. IN_PROC_BROWSER_TEST_F(OobeBaseTest, InstallButtonHiddenByDefault) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().ExpectVisiblePath(kWelcomeScreen); test::OobeJS().TapOnPath(kWelcomeGetStarted); @@ -154,7 +155,7 @@ // If the kAllowOsInstall is set, clicking `Get Started` button show show the // `OS Trial` screen IN_PROC_BROWSER_TEST_F(OsInstallScreenTest, InstallButtonVisibleWithSwitch) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().ExpectVisiblePath(kWelcomeScreen); test::OobeJS().TapOnPath(kWelcomeGetStarted);
diff --git a/chrome/browser/ash/login/screens/os_trial_screen_browsertest.cc b/chrome/browser/ash/login/screens/os_trial_screen_browsertest.cc index acc7013..c07e2dd 100644 --- a/chrome/browser/ash/login/screens/os_trial_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/os_trial_screen_browsertest.cc
@@ -7,6 +7,7 @@ #include "chrome/browser/ash/login/screens/welcome_screen.h" #include "chrome/browser/ash/login/test/oobe_base_test.h" #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" +#include "chrome/browser/ash/login/test/oobe_screens_utils.h" #include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/ui/webui/ash/login/network_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/os_install_screen_handler.h" @@ -39,7 +40,7 @@ } void ShowOsTrialScreen() { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath(kWelcomeGetStartedButton); OobeScreenWaiter(OsTrialScreenView::kScreenId).Wait(); test::OobeJS().ExpectHasAttribute("checked", kInstallRadioButton); @@ -73,7 +74,7 @@ IN_PROC_BROWSER_TEST_F(OsTrialScreenTest, BackNavigation) { ShowOsTrialScreen(); test::OobeJS().ClickOnPath(kBackButton); - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); } // If `Start OS Install` button was clicked from the shelf in the user creation
diff --git a/chrome/browser/ash/login/screens/quick_start_screen_browsertest.cc b/chrome/browser/ash/login/screens/quick_start_screen_browsertest.cc index b6b6466..2d56c17 100644 --- a/chrome/browser/ash/login/screens/quick_start_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/quick_start_screen_browsertest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "ash/constants/ash_features.h" +#include "ash/public/cpp/login_accelerators.h" #include "base/run_loop.h" #include "base/test/scoped_feature_list.h" #include "chrome/browser/ash/login/oobe_quick_start/connectivity/fake_target_device_connection_broker.h" @@ -11,6 +12,8 @@ #include "chrome/browser/ash/login/test/js_checker.h" #include "chrome/browser/ash/login/test/oobe_base_test.h" #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" +#include "chrome/browser/ash/login/test/oobe_screens_utils.h" +#include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/ui/webui/ash/login/quick_start_screen_handler.h" #include "chrome/browser/ui/webui/ash/login/welcome_screen_handler.h" #include "content/public/test/browser_test.h" @@ -24,12 +27,10 @@ WelcomeView::kScreenId.name, kWelcomeScreen, kQuickStartButton}; } // namespace -class QuickStartBrowserTest : public OobeBaseTest { +class QuickStartBrowserTestBase : public OobeBaseTest { public: - QuickStartBrowserTest() { - feature_list_.InitAndEnableFeature(features::kOobeQuickStart); - } - ~QuickStartBrowserTest() override = default; + QuickStartBrowserTestBase() = default; + ~QuickStartBrowserTestBase() override = default; void SetUpInProcessBrowserTestFixture() override { OobeBaseTest::SetUpInProcessBrowserTestFixture(); @@ -46,6 +47,13 @@ protected: quick_start::FakeTargetDeviceConnectionBroker::Factory connection_broker_factory_; +}; + +class QuickStartBrowserTest : public QuickStartBrowserTestBase { + public: + QuickStartBrowserTest() { + feature_list_.InitAndEnableFeature(features::kOobeQuickStart); + } private: base::test::ScopedFeatureList feature_list_; @@ -60,9 +68,11 @@ } }; +class QuickStartAcceleratorBrowserTest : public QuickStartBrowserTestBase {}; + IN_PROC_BROWSER_TEST_F(QuickStartNotDeterminedBrowserTest, ButtonVisibleOnWelcomeScreen) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().ExpectHiddenPath(kQuickStartButtonPath); connection_broker_factory_.instances().front()->set_feature_support_status( @@ -75,7 +85,7 @@ } IN_PROC_BROWSER_TEST_F(QuickStartBrowserTest, QRCode) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().ExpectVisiblePath(kQuickStartButtonPath); test::OobeJS().ClickOnPath(kQuickStartButtonPath); @@ -92,4 +102,17 @@ {QuickStartView::kScreenId.name}, 185); } +IN_PROC_BROWSER_TEST_F(QuickStartAcceleratorBrowserTest, + ButtonVisibleOnWelcomeScreen) { + OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::OobeJS().ExpectHiddenPath(kQuickStartButtonPath); + + WizardController::default_controller()->HandleAccelerator( + LoginAcceleratorAction::kEnableQuickStart); + + test::OobeJS() + .CreateVisibilityWaiter(/*visibility=*/true, kQuickStartButtonPath) + ->Wait(); +} + } // namespace ash
diff --git a/chrome/browser/ash/login/screens/theme_selection_screen_browsertest.cc b/chrome/browser/ash/login/screens/theme_selection_screen_browsertest.cc index 36a0670f..ed59f531 100644 --- a/chrome/browser/ash/login/screens/theme_selection_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/theme_selection_screen_browsertest.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/ash/login/test/oobe_base_test.h" #include "chrome/browser/ash/login/test/oobe_screen_exit_waiter.h" #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" +#include "chrome/browser/ash/login/test/oobe_screens_utils.h" #include "chrome/browser/ash/login/wizard_controller.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/ash/login/guest_tos_screen_handler.h" @@ -61,7 +62,7 @@ class ThemeSelectionScreenTest : public OobeBaseTest, - public ::testing::WithParamInterface<test::UIPath> { + public ::testing::WithParamInterface<std::tuple<test::UIPath, bool>> { public: void SetUpOnMainThread() override { ThemeSelectionScreen* theme_selection_screen = @@ -113,9 +114,31 @@ base::OnceClosure quit_closure_; }; -IN_PROC_BROWSER_TEST_F(ThemeSelectionScreenTest, ProceedWithDefaultTheme) { +IN_PROC_BROWSER_TEST_F(ThemeSelectionScreenTest, + ProceedWithDefaultThemeBrandedBuild) { + LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = true; ShowThemeSelectionScreen(); test::OobeJS().ClickOnPath(kNextButtonPath); + + WaitForScreenExit(); + + EXPECT_THAT( + histogram_tester_.GetAllSamples(kStepShownStatusHistogram), + ElementsAre(base::Bucket( + static_cast<int>(WizardController::ScreenShownStatus::kShown), 1))); + histogram_tester_.ExpectTotalCount(kStepCompletionTimeHistogram, 1); + histogram_tester_.ExpectTotalCount(kProceedExitReasonHistogram, 1); +} + +IN_PROC_BROWSER_TEST_F(ThemeSelectionScreenTest, + ProceedWithDefaultThemeNotBrandedBuild) { + LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = + false; + ShowThemeSelectionScreen(); + + // for not branded build marketingOptIn screen is skipped causing + // login host controller and oobe UI to be detoryed + ash::test::TapOnPathAndWaitForOobeToBeDestroyed(kNextButtonPath); WaitForScreenExit(); EXPECT_THAT( @@ -127,16 +150,23 @@ } IN_PROC_BROWSER_TEST_P(ThemeSelectionScreenTest, SelectTheme) { + auto selected_option_path = std::get<0>(GetParam()); + bool branded_build = std::get<1>(GetParam()); + + LoginDisplayHost::default_host()->GetWizardContext()->is_branded_build = + branded_build; + ShowThemeSelectionScreen(); Profile* profile = ProfileManager::GetActiveUserProfile(); // Expect the default dark mode schedule type to be sunset-to-sunrise. EXPECT_EQ(profile->GetPrefs()->GetInteger(prefs::kDarkModeScheduleType), 1); - test::OobeJS().ExpectVisiblePath(GetParam()); - test::OobeJS().ClickOnPath(GetParam()); + test::OobeJS().ExpectVisiblePath(selected_option_path); + test::OobeJS().ClickOnPath(selected_option_path); - auto selectedOption = GetParam().begin()[GetParam().size() - 1]; + auto selectedOption = + selected_option_path.begin()[selected_option_path.size() - 1]; ThemeSelectionScreen::SelectedTheme theme = ThemeSelectionScreen::SelectedTheme::kDark; if (selectedOption == kDarkThemeButton) { @@ -153,7 +183,14 @@ theme = ThemeSelectionScreen::SelectedTheme::kAuto; } - test::OobeJS().ClickOnPath(kNextButtonPath); + // for not branded build marketingOptIn screen is skipped causing + // login host controller and oobe UI to be detoryed + if (branded_build) { + test::OobeJS().ClickOnPath(kNextButtonPath); + } else { + ash::test::TapOnPathAndWaitForOobeToBeDestroyed(kNextButtonPath); + } + EXPECT_THAT(histogram_tester_.GetAllSamples(kSelectedThemeHistogram), ElementsAre(base::Bucket(static_cast<int>(theme), 1))); WaitForScreenExit(); @@ -173,11 +210,13 @@ test::OobeJS().ExpectVisiblePath(kScreenSubtitleClamshellPath); } -INSTANTIATE_TEST_SUITE_P(All, - ThemeSelectionScreenTest, - ::testing::Values(kDarkThemeButtonPath, - kLightThemeButtonPath, - kAutoThemeButtonPath)); +INSTANTIATE_TEST_SUITE_P( + All, + ThemeSelectionScreenTest, + testing::Combine(testing::ValuesIn({kDarkThemeButtonPath, + kLightThemeButtonPath, + kAutoThemeButtonPath}), + testing::Bool())); class ThemeSelectionScreenResumeTest : public OobeBaseTest,
diff --git a/chrome/browser/ash/login/screens/welcome_screen.cc b/chrome/browser/ash/login/screens/welcome_screen.cc index b9121fd..0e0bc89 100644 --- a/chrome/browser/ash/login/screens/welcome_screen.cc +++ b/chrome/browser/ash/login/screens/welcome_screen.cc
@@ -381,12 +381,12 @@ base::DefaultTickClock::GetInstance(), this); if (view_) view_->Show(); + + // Quick Start can be enabled either by feature flag or by keyboard shortcut. + // The shortcut method enables a simpler workflow for testers, while the + // feature flag will enable us to perform a first run field trial. if (features::IsOobeQuickStartEnabled()) { - bootstrap_controller_ = - LoginDisplayHost::default_host()->GetQuickStartBootstrapController(); - bootstrap_controller_->GetFeatureSupportStatusAsync( - base::BindOnce(&WelcomeScreen::OnFeatureSupportStatusDetermined, - weak_ptr_factory_.GetWeakPtr())); + EnableQuickStart(); } if (LoginScreenClientImpl::HasInstance()) { @@ -397,7 +397,7 @@ void WelcomeScreen::HideImpl() { CancelChromeVoxHintIdleDetection(); - if (features::IsOobeQuickStartEnabled()) { + if (context()->quick_start_enabled) { bootstrap_controller_.reset(); } } @@ -405,7 +405,7 @@ void WelcomeScreen::OnUserAction(const base::Value::List& args) { const std::string& action_id = args[0].GetString(); if (action_id == kUserActionQuickStartClicked) { - DCHECK(features::IsOobeQuickStartEnabled()); + CHECK(context()->quick_start_enabled); Exit(Result::QUICK_START); return; } @@ -547,6 +547,13 @@ if (view_) view_->ShowRemoraRequisitionDialog(); return true; + } else if (action == LoginAcceleratorAction::kEnableQuickStart) { + if (context()->quick_start_enabled) { + return true; + } + + EnableQuickStart(); + return true; } return false; @@ -565,12 +572,22 @@ } } -void WelcomeScreen::OnFeatureSupportStatusDetermined( +void WelcomeScreen::EnableQuickStart() { + context()->quick_start_enabled = true; + bootstrap_controller_ = + LoginDisplayHost::default_host()->GetQuickStartBootstrapController(); + bootstrap_controller_->GetFeatureSupportStatusAsync( + base::BindOnce(&WelcomeScreen::OnGetQuickStartFeatureSupportStatus, + weak_ptr_factory_.GetWeakPtr())); +} + +void WelcomeScreen::OnGetQuickStartFeatureSupportStatus( quick_start::TargetDeviceConnectionBroker::FeatureSupportStatus status) { if (status != quick_start::TargetDeviceConnectionBroker:: FeatureSupportStatus::kSupported) { return; } + if (!view_) { return; }
diff --git a/chrome/browser/ash/login/screens/welcome_screen.h b/chrome/browser/ash/login/screens/welcome_screen.h index 492c715..f505a2fff 100644 --- a/chrome/browser/ash/login/screens/welcome_screen.h +++ b/chrome/browser/ash/login/screens/welcome_screen.h
@@ -141,7 +141,8 @@ Profile* profile, bool show_message) override; - void OnFeatureSupportStatusDetermined( + void EnableQuickStart(); + void OnGetQuickStartFeatureSupportStatus( quick_start::TargetDeviceConnectionBroker::FeatureSupportStatus status); // Handlers for various user actions:
diff --git a/chrome/browser/ash/login/screens/welcome_screen_browsertest.cc b/chrome/browser/ash/login/screens/welcome_screen_browsertest.cc index 1edd2c66..0bec64f1 100644 --- a/chrome/browser/ash/login/screens/welcome_screen_browsertest.cc +++ b/chrome/browser/ash/login/screens/welcome_screen_browsertest.cc
@@ -162,7 +162,7 @@ }; IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenElements) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().ExpectVisiblePath({"connect", "welcomeScreen"}); test::OobeJS().ExpectHiddenPath({"connect", "accessibilityScreen"}); @@ -183,19 +183,19 @@ // for measurements during OOBE speedup work. Also verifies OOBE.WebUI.LoadTime // metric. IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, OobeStartupTime) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); histogram_tester_.ExpectTotalCount("OOBE.WebUI.LoadTime.FirstRun", 1); } IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenNext) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath({"connect", "welcomeScreen", "getStarted"}); WaitForScreenExit(); } // Set of browser tests for Welcome Screen Language options. IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenLanguageFlow) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "languageSelectionButton"}); @@ -206,7 +206,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenLanguageElements) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "languageSelectionButton"}); @@ -218,7 +218,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenLanguageSelection) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "languageSelectionButton"}); @@ -248,7 +248,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenKeyboardSelection) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "languageSelectionButton"}); @@ -271,7 +271,7 @@ // Set of browser tests for Welcome Screen Accessibility options. IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenAccessibilityFlow) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); @@ -282,7 +282,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenAccessibilitySpokenFeedback) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); @@ -304,7 +304,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenAccessibilityLargeCursor) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); @@ -326,7 +326,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenAccessibilityHighContrast) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); @@ -348,7 +348,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenAccessibilitySelectToSpeak) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); @@ -370,7 +370,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenAccessibilityScreenMagnifier) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); @@ -392,7 +392,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenAccessibilityDockedMagnifier) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); @@ -416,7 +416,7 @@ EXPECT_EQ( StartupCustomizationDocument::GetInstance()->initial_locale_default(), "en-US"); - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); const std::string locale = "ru"; test::LanguageReloadObserver observer(welcome_screen()); welcome_screen()->SetApplicationLocale(locale, /*is_from_ui*/ true); @@ -442,7 +442,7 @@ } IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, A11yVirtualKeyboard) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); @@ -464,7 +464,7 @@ // Set of tests for the OOBE.WelcomeScreen.UserChangedLocale IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, UserChangedLocaleMetric) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); // We need to proceed to the next screen because metric is written right // before we call exit_callback_(). test::OobeJS().TapOnPath({"connect", "welcomeScreen", "getStarted"}); @@ -476,7 +476,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, UserChangedLocaleMetricAfterUILocaleChange) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "languageSelectionButton"}); @@ -513,7 +513,7 @@ IN_PROC_BROWSER_TEST_F(WelcomeScreenSystemDevModeBrowserTest, DebuggerModeTest) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().ClickOnPath( {"connect", "welcomeScreen", "enableDebuggingButton"}); @@ -572,7 +572,7 @@ }; IN_PROC_BROWSER_TEST_F(WelcomeScreenTimezone, ChangeTimezoneFlow) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); test::OobeJS().TapOnPath( {"connect", "welcomeScreen", "timezoneSettingsButton"}); @@ -652,7 +652,7 @@ // Clicking the 'activate' button in the dialog should activate ChromeVox. // crbug.com/1341515 Disabled due to flakiness. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, DISABLED_LaptopClick) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); // A consistency check to ensure the ChromeVox hint idle detector is disabled // for this and similar tests. ASSERT_FALSE(IdleDetectionActivatedForTesting()); @@ -686,7 +686,7 @@ // Assert that the ChromeVox hint gives speech output and shows a dialog. // Pressing the space bar while the dialog is open should activate ChromeVox. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, LaptopSpaceBar) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); test::ExecuteOobeJS(kSetAvailableVoices); test::SpeechMonitor monitor; @@ -715,7 +715,7 @@ // Tests the ChromeVox hint speech given in tablet mode. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, Tablet) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); test::ExecuteOobeJS(kSetAvailableVoices); ShellTestApi().SetTabletModeEnabledForTest(true); @@ -731,7 +731,7 @@ // Tests that the ChromeVox hint can be spoken, even if the necessary voice // hasn't loaded when the idle detector has fired. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, VoicesChanged) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); const std::string set_no_english_voice = R"( chrome.tts.getVoices = function(callback) { @@ -765,7 +765,7 @@ // Assert that clicking on one of the three buttons on the welcome screen // cancels the ChromeVox hint. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, CancelHint) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); ASSERT_FALSE(IdleDetectionCancelledForTesting()); test::OobeJS().ClickOnPath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); @@ -781,7 +781,7 @@ // timeout. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, MAYBE_ActivateChromeVoxBeforeHint) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); ASSERT_FALSE(IdleDetectionCancelledForTesting()); ToggleAccessibilityFeature("accessibility-spoken-feedback", true); ASSERT_TRUE(AccessibilityManager::Get()->IsSpokenFeedbackEnabled()); @@ -792,7 +792,7 @@ // dialog. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, DISABLED_ActivateChromeVoxAfterHint) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); test::ExecuteOobeJS(kSetAvailableVoices); test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); @@ -808,7 +808,7 @@ // Assert that we can dismiss the ChromeVox hint dialog and that the appropriate // metrics get recorded. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, DismissAfterHint) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); test::ExecuteOobeJS(kSetAvailableVoices); test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); @@ -826,7 +826,7 @@ // focus when using tab. // TODO(crbug/1161398): The test is flaky. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, DISABLED_TrapFocus) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); test::ExecuteOobeJS(kSetAvailableVoices); test::OobeJS().ExpectAttributeEQ("open", kChromeVoxHintDialog, false); @@ -860,7 +860,7 @@ // Verifies that the ChromeVox idle detector is cancelled when // skipToLoginForTesting is called. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, SkipToLoginForTesting) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); WizardController::default_controller()->SkipToLoginForTesting(); OobeScreenWaiter(GaiaView::kScreenId).Wait(); @@ -870,7 +870,7 @@ // Verifies that the ChromeVox idle detector is cancelled when the status tray // is shown. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, StatusTray) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); ASSERT_FALSE(IdleDetectionCancelledForTesting()); SystemTrayTestApi::Create()->ShowBubble(); ASSERT_TRUE(IdleDetectionCancelledForTesting()); @@ -878,7 +878,7 @@ // Verifies that TTS output stops after the user has closed the dialog. IN_PROC_BROWSER_TEST_F(WelcomeScreenChromeVoxHintTest, StopSpeechAfterClose) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); test::ExecuteOobeJS(kSetAvailableVoices); const std::string set_is_speaking = R"( @@ -918,7 +918,7 @@ // Tests the ChromeVox hint speech can be given in a language other than // English. IN_PROC_BROWSER_TEST_F(WelcomeScreenInternationalChromeVoxHintTest, SpeakHint) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); test::ExecuteOobeJS(kSetAvailableVoices); test::SpeechMonitor monitor; @@ -932,7 +932,7 @@ // available voice can be loaded. IN_PROC_BROWSER_TEST_F(WelcomeScreenInternationalChromeVoxHintTest, DefaultAnnouncement) { - OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::WaitForWelcomeScreen(); TtsExtensionEngine::GetInstance()->DisableBuiltInTTSEngineForTesting(); // Load an English voice, but do not load a French voice. // Also set the timeout for the fallback hint to 0 MS.
diff --git a/chrome/browser/ash/login/ui/login_display_host_common.cc b/chrome/browser/ash/login/ui/login_display_host_common.cc index 645712b..08e0309 100644 --- a/chrome/browser/ash/login/ui/login_display_host_common.cc +++ b/chrome/browser/ash/login/ui/login_display_host_common.cc
@@ -712,7 +712,7 @@ base::WeakPtr<quick_start::TargetDeviceBootstrapController> LoginDisplayHostCommon::GetQuickStartBootstrapController() { - DCHECK(features::IsOobeQuickStartEnabled()); + CHECK(wizard_context_->quick_start_enabled); if (!bootstrap_controller_) { Profile* profile = ProfileManager::GetActiveUserProfile(); DCHECK(profile);
diff --git a/chrome/browser/ash/login/wizard_context.h b/chrome/browser/ash/login/wizard_context.h index 310df37a..8fe3f58 100644 --- a/chrome/browser/ash/login/wizard_context.h +++ b/chrome/browser/ash/login/wizard_context.h
@@ -126,6 +126,11 @@ // ash::OOBE_SCREEN_UNKNOWN. OobeScreenId screen_after_managed_tos; + // This is set to true when the user hits the keyboard shortcut triggering the + // associated LoginAccelerator. This is used in place of a feature flag to + // determine whether to display the Quick Start calls to action. + bool quick_start_enabled = false; + // This ID maps onto the instance_id used in // ash::multidevice::RemoteDevice. If a user connects their phone during Quick // Start, Quick Start saves this ID. After Quick Start, the multidevice screen
diff --git a/chrome/browser/ash/login/wizard_controller.cc b/chrome/browser/ash/login/wizard_controller.cc index db2d76bc..59b8b518 100644 --- a/chrome/browser/ash/login/wizard_controller.cc +++ b/chrome/browser/ash/login/wizard_controller.cc
@@ -603,12 +603,10 @@ base::BindRepeating(&WizardController::OnDemoPreferencesScreenExit, weak_factory_.GetWeakPtr()))); - if (ash::features::IsOobeQuickStartEnabled()) { - append(std::make_unique<QuickStartScreen>( - oobe_ui->GetView<QuickStartScreenHandler>()->AsWeakPtr(), - base::BindRepeating(&WizardController::OnQuickStartScreenExit, - weak_factory_.GetWeakPtr()))); - } + append(std::make_unique<QuickStartScreen>( + oobe_ui->GetView<QuickStartScreenHandler>()->AsWeakPtr(), + base::BindRepeating(&WizardController::OnQuickStartScreenExit, + weak_factory_.GetWeakPtr()))); } append(std::make_unique<NetworkScreen>( @@ -903,7 +901,7 @@ } void WizardController::ShowQuickStartScreen() { - CHECK(ash::features::IsOobeQuickStartEnabled()); + CHECK(wizard_context_->quick_start_enabled); SetCurrentScreen(GetScreen(QuickStartView::kScreenId)); }
diff --git a/chrome/browser/ash/login/wizard_controller_browsertest.cc b/chrome/browser/ash/login/wizard_controller_browsertest.cc index e3d9904e..8c1f72d 100644 --- a/chrome/browser/ash/login/wizard_controller_browsertest.cc +++ b/chrome/browser/ash/login/wizard_controller_browsertest.cc
@@ -61,6 +61,7 @@ #include "chrome/browser/ash/login/test/oobe_configuration_waiter.h" #include "chrome/browser/ash/login/test/oobe_screen_exit_waiter.h" #include "chrome/browser/ash/login/test/oobe_screen_waiter.h" +#include "chrome/browser/ash/login/test/oobe_screens_utils.h" #include "chrome/browser/ash/login/ui/login_display_host.h" #include "chrome/browser/ash/login/ui/webui_login_view.h" #include "chrome/browser/ash/net/network_portal_detector_test_impl.h" @@ -481,7 +482,7 @@ } bool JSExecute(const std::string& script) { - return content::ExecuteScript(GetWebContents(), script); + return content::ExecJs(GetWebContents(), script); } bool JSExecuteBooleanExpression(const std::string& expression) {
diff --git a/chrome/browser/ash/nearby/nearby_dependencies_provider_factory.cc b/chrome/browser/ash/nearby/nearby_dependencies_provider_factory.cc index 3ecdbe9..9de42ee 100644 --- a/chrome/browser/ash/nearby/nearby_dependencies_provider_factory.cc +++ b/chrome/browser/ash/nearby/nearby_dependencies_provider_factory.cc
@@ -16,19 +16,11 @@ ProfileSelections BuildNearbyDependenciesProviderProfileSelections() { // This needs to be overridden because the default implementation returns // nullptr for OTR profiles, which would prevent using this with Quick Start. - if (features::IsOobeQuickStartEnabled()) { - return ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOwnInstance) - // TODO(crbug.com/1418376): Check if this service is needed in - // Guest mode. - .WithGuest(ProfileSelection::kOwnInstance) - .Build(); - } - return ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOriginalOnly) - // TODO(crbug.com/1418376): Check if this service is needed in Guest mode. - .WithGuest(ProfileSelection::kOriginalOnly) + .WithRegular(ProfileSelection::kOwnInstance) + // TODO(crbug.com/1418376): Check if this service is needed in + // Guest mode. + .WithGuest(ProfileSelection::kOwnInstance) .Build(); }
diff --git a/chrome/browser/ash/nearby/nearby_process_manager_factory.cc b/chrome/browser/ash/nearby/nearby_process_manager_factory.cc index df4c760..de92ccc 100644 --- a/chrome/browser/ash/nearby/nearby_process_manager_factory.cc +++ b/chrome/browser/ash/nearby/nearby_process_manager_factory.cc
@@ -31,8 +31,7 @@ bool NearbyProcessManagerFactory::CanBeLaunchedForProfile(Profile* profile) { // We allow NearbyProcessManager to be used with the signin profile since it // is required for OOBE Quick Start. - if (ProfileHelper::IsSigninProfile(profile) && - features::IsOobeQuickStartEnabled()) { + if (ProfileHelper::IsSigninProfile(profile)) { return true; } @@ -63,8 +62,14 @@ } NearbyProcessManagerFactory::NearbyProcessManagerFactory() - : ProfileKeyedServiceFactory("NearbyProcessManager", - ProfileSelections::BuildForAllProfiles()) { + : ProfileKeyedServiceFactory( + "NearbyProcessManager", + ProfileSelections::Builder() + .WithRegular(ProfileSelection::kOwnInstance) + // TODO(crbug.com/1418376): Check if this service is needed in + // Guest mode. + .WithGuest(ProfileSelection::kOwnInstance) + .Build()) { DependsOn(NearbyDependenciesProviderFactory::GetInstance()); }
diff --git a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc index a062c76f..a030d9b9 100644 --- a/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc +++ b/chrome/browser/ash/policy/dlp/dlp_files_controller_ash_unittest.cc
@@ -2114,7 +2114,16 @@ MockDlpWarnNotifier* mock_dlp_warn_notifier = wrapper.get(); files_controller_->SetWarnNotifierForTesting(std::move(wrapper)); - EXPECT_CALL(*mock_dlp_warn_notifier, ShowDlpWarningDialog).Times(1); + EXPECT_CALL(*mock_dlp_warn_notifier, ShowDlpFilesWarningDialog) + .WillOnce([&choice_result]( + OnDlpRestrictionCheckedCallback callback, + const std::vector<DlpConfidentialFile>& confidential_files, + const DlpFileDestination& destination, + DlpFilesController::FileAction action, + gfx::NativeWindow modal_parent) { + std::move(callback).Run(choice_result); + return nullptr; + }); MockCheckIfDlpAllowedCallback cb; EXPECT_CALL(cb, Run(/*is_allowed=*/choice_result)).Times(1); @@ -2356,21 +2365,17 @@ AddFilesToDlpClient(std::move(files), files_urls); std::unique_ptr<MockDlpWarnNotifier> wrapper = - std::make_unique<MockDlpWarnNotifier>(false); + std::make_unique<MockDlpWarnNotifier>(); MockDlpWarnNotifier* mock_dlp_warn_notifier = wrapper.get(); files_controller_->SetWarnNotifierForTesting(std::move(wrapper)); - std::vector<DlpConfidentialFile> expected_files; + std::vector<DlpConfidentialFile> expected_files; if (transfer_info.files_action != DlpFilesControllerAsh::FileAction::kDownload) { for (const auto& file_path : transfer_info.file_paths) { expected_files.emplace_back(base::FilePath(file_path)); } } - DlpWarnDialog::DlpWarnDialogOptions expected_dialog_options( - DlpWarnDialog::Restriction::kFiles, expected_files, - DlpFileDestination(DlpRulesManager::Component::kUsb), - transfer_info.files_action); EXPECT_CALL( *rules_manager_, @@ -2381,8 +2386,18 @@ .Times(::testing::AnyNumber()); EXPECT_CALL(*mock_dlp_warn_notifier, - ShowDlpWarningDialog(_, expected_dialog_options, _)) - .Times(1); + ShowDlpFilesWarningDialog( + base::test::IsNotNullCallback(), expected_files, + DlpFileDestination(DlpRulesManager::Component::kUsb), + transfer_info.files_action, _)) + .WillOnce([](OnDlpRestrictionCheckedCallback callback, + const std::vector<DlpConfidentialFile>& confidential_files, + const DlpFileDestination& destination, + DlpFilesController::FileAction action, + gfx::NativeWindow modal_parent) { + std::move(callback).Run(false); + return nullptr; + }); MockIsFilesTransferRestrictedCallback cb; EXPECT_CALL(cb, Run(files_levels)).Times(1);
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc index f4e1a74..a74e6bf3 100644 --- a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc +++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.cc
@@ -43,6 +43,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/reporting/metric_default_utils.h" #include "chrome/browser/chromeos/reporting/network/network_bandwidth_sampler.h" +#include "chrome/browser/chromeos/reporting/user_reporting_settings.h" #include "chrome/browser/profiles/profile.h" #include "chromeos/ash/components/settings/cros_settings_names.h" #include "components/reporting/client/report_queue_configuration.h" @@ -146,6 +147,10 @@ delegate_->CreateMetricReportQueue( EventType::kUser, Destination::PERIPHERAL_EVENTS, Priority::SECURITY); + DCHECK(profile); + user_reporting_settings_ = + std::make_unique<UserReportingSettings>(profile->GetWeakPtr()); + InitOnAffiliatedLogin(profile); DelayedInitOnAffiliatedLogin(profile); } @@ -218,6 +223,7 @@ event_report_queue_.reset(); user_event_report_queue_.reset(); user_peripheral_events_and_telemetry_report_queue_.reset(); + user_reporting_settings_.reset(); } void MetricReportingManager::DelayedInit() { @@ -287,12 +293,14 @@ InitEventObserverManager( std::make_unique<AudioEventsObserver>(), user_event_report_queue_.get(), + &reporting_settings_, /*enable_setting_path=*/::ash::kReportDeviceAudioStatus, metrics::kReportDeviceAudioStatusDefaultValue, /*init_delay=*/base::TimeDelta()); // Network health events observer. InitEventObserverManager( std::make_unique<NetworkEventsObserver>(), event_report_queue_.get(), + &reporting_settings_, /*enable_setting_path=*/::ash::kDeviceReportNetworkEvents, metrics::kDeviceReportNetworkEventsDefaultValue, /*init_delay=*/base::TimeDelta()); @@ -309,6 +317,7 @@ auto app_events_observer = AppEventsObserver::CreateForProfile(profile); InitEventObserverManager( std::move(app_events_observer), user_event_report_queue_.get(), + &reporting_settings_, /*enable_setting_path=*/::ash::kReportDeviceAppInfo, metrics::kReportDeviceAppInfoDefaultValue, /*init_delay=*/base::TimeDelta()); @@ -429,13 +438,15 @@ sampler, std::move(event_detector), &reporting_settings_, rate_setting_path, default_rate, rate_unit_to_ms); InitEventObserverManager(std::move(periodic_event_collector), - metric_report_queue, enable_setting_path, - enable_default_value, init_delay); + metric_report_queue, &reporting_settings_, + enable_setting_path, enable_default_value, + init_delay); } void MetricReportingManager::InitEventObserverManager( std::unique_ptr<MetricEventObserver> event_observer, MetricReportQueue* metric_report_queue, + ReportingSettings* reporting_settings, const std::string& enable_setting_path, bool setting_enabled_default_value, base::TimeDelta init_delay) { @@ -444,7 +455,7 @@ return; } event_observer_managers_.emplace_back(delegate_->CreateEventObserverManager( - std::move(event_observer), metric_report_queue, &reporting_settings_, + std::move(event_observer), metric_report_queue, reporting_settings, enable_setting_path, setting_enabled_default_value, /*collector_pool=*/this, init_delay)); }
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.h b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.h index 29c8309..5db4866 100644 --- a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.h +++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager.h
@@ -22,6 +22,7 @@ #include "chrome/browser/ash/policy/status_collector/managed_session_service.h" #include "chrome/browser/ash/settings/device_settings_service.h" #include "chrome/browser/chromeos/reporting/metric_reporting_manager_delegate_base.h" +#include "chrome/browser/chromeos/reporting/user_reporting_settings.h" #include "chrome/browser/profiles/profile.h" #include "chromeos/ash/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h" #include "components/reporting/metrics/event_driven_telemetry_collector_pool.h" @@ -154,6 +155,7 @@ void InitEventObserverManager( std::unique_ptr<MetricEventObserver> event_observer, MetricReportQueue* report_queue, + ReportingSettings* reporting_settings, const std::string& enable_setting_path, bool setting_enabled_default_value, base::TimeDelta init_delay); @@ -192,6 +194,7 @@ base::StringPiece setting_name); CrosReportingSettings reporting_settings_; + std::unique_ptr<UserReportingSettings> user_reporting_settings_; SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc index b3c599f..08c58ba 100644 --- a/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc +++ b/chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_manager_unittest.cc
@@ -349,7 +349,7 @@ EXPECT_EQ(periodic_event_collector_count, 0); EXPECT_EQ(observer_manager_count, 0); - metric_reporting_manager->OnLogin(nullptr); + metric_reporting_manager->OnLogin(profile()); EXPECT_EQ(one_shot_collector_count, 0); EXPECT_EQ(periodic_collector_count, 0);
diff --git a/chrome/browser/ash/web_applications/projector_app/projector_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/projector_app/projector_app_integration_browsertest.cc index adade574..34bf651 100644 --- a/chrome/browser/ash/web_applications/projector_app/projector_app_integration_browsertest.cc +++ b/chrome/browser/ash/web_applications/projector_app/projector_app_integration_browsertest.cc
@@ -9,6 +9,7 @@ #include "ash/webui/projector_app/buildflags.h" #include "ash/webui/projector_app/projector_app_client.h" #include "ash/webui/projector_app/public/cpp/projector_app_constants.h" +#include "base/files/safe_base_name.h" #include "base/run_loop.h" #include "chrome/browser/ash/system_web_apps/system_web_app_manager.h" #include "chrome/browser/ash/system_web_apps/test_support/system_web_app_integration_test.h" @@ -75,7 +76,8 @@ base::OnceClosure callback = run_loop.QuitClosure(); controller->set_canvas_initialized_callback_for_test(std::move(callback)); - controller->StartProjectorSession("projector_data"); + controller->StartProjectorSession( + base::SafeBaseName::Create("projector_data").value()); capture_mode_controller->PerformCapture(); run_loop.Run();
diff --git a/chrome/browser/autofill/DEPS b/chrome/browser/autofill/DEPS index 67d4531..24cd311 100644 --- a/chrome/browser/autofill/DEPS +++ b/chrome/browser/autofill/DEPS
@@ -2,3 +2,9 @@ '+third_party/libaddressinput/chromium/chrome_metadata_source.h', '+third_party/libaddressinput/chromium/chrome_storage_impl.h', ] + +specific_include_rules = { + "PersonalDataManagerTest\.java": [ + '+components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/test/TestImageFetcher.java', + ] +}
diff --git a/chrome/browser/autofill/autofill_across_iframes_browsertest.cc b/chrome/browser/autofill/autofill_across_iframes_browsertest.cc index 70550415..fcf600dd 100644 --- a/chrome/browser/autofill/autofill_across_iframes_browsertest.cc +++ b/chrome/browser/autofill/autofill_across_iframes_browsertest.cc
@@ -1024,7 +1024,7 @@ [[nodiscard]] const FormStructure* FormAfterRemovalOfExtraFields() { // A core part of this test is in the following lines: We check that after // removing fields, the BrowserAutofillAgent learns about that. - if (!content::ExecuteScript(web_contents(), "removeFields();")) { + if (!content::ExecJs(web_contents(), "removeFields();")) { ADD_FAILURE() << "Failed to call removeFields();"; return nullptr; } @@ -1066,7 +1066,7 @@ ASSERT_TRUE(LoadForm()); // This removes the entire <form> element for the first iframe. - ASSERT_TRUE(content::ExecuteScript(web_contents(), R"( + ASSERT_TRUE(content::ExecJs(web_contents(), R"( document.getElementsByTagName("IFRAME")[0] .contentWindow .deleteForm(); @@ -1086,7 +1086,7 @@ ASSERT_TRUE(LoadForm()); // This removes the entire <form> element for the first iframe. - ASSERT_TRUE(content::ExecuteScript(web_contents(), R"( + ASSERT_TRUE(content::ExecJs(web_contents(), R"( document.getElementsByTagName("IFRAME")[0] .contentWindow .deleteParentOfForm();
diff --git a/chrome/browser/autofill/autofill_autocomplete_browsertest.cc b/chrome/browser/autofill/autofill_autocomplete_browsertest.cc index 3f10e1b..a6a0049 100644 --- a/chrome/browser/autofill/autofill_autocomplete_browsertest.cc +++ b/chrome/browser/autofill/autofill_autocomplete_browsertest.cc
@@ -131,7 +131,7 @@ const std::string js = base::StringPrintf( js_format, kDefaultAutocompleteInputId, value.c_str()); - ASSERT_TRUE(content::ExecuteScript(web_contents(), js)); + ASSERT_TRUE(content::ExecJs(web_contents(), js)); // Set up observer for Autocomplete form submissions. TestAutofillAsyncObserver observer(
diff --git a/chrome/browser/autofill/autofill_browsertest.cc b/chrome/browser/autofill/autofill_browsertest.cc index ba1c710..99cdfbd1 100644 --- a/chrome/browser/autofill/autofill_browsertest.cc +++ b/chrome/browser/autofill/autofill_browsertest.cc
@@ -205,8 +205,8 @@ // Shortcut explicit save prompts and automatically accept. personal_data_manager()->set_auto_accept_address_imports_for_testing(true); WindowedPersonalDataManagerObserver observer(browser()); - ASSERT_TRUE(content::ExecuteScript(web_contents(), - GetJSToFillForm(data) + submit_js)); + ASSERT_TRUE( + content::ExecJs(web_contents(), GetJSToFillForm(data) + submit_js)); if (simulate_click) { // Simulate a mouse click to submit the form because form submissions not // triggered by user gestures are ignored. @@ -619,7 +619,7 @@ // Remove one field via JavaScript and expect that the AutofillManager learns // about this. - ASSERT_TRUE(content::ExecuteScript(web_contents(), "RemoveCity();")); + ASSERT_TRUE(content::ExecJs(web_contents(), "RemoveCity();")); EXPECT_TRUE(WaitForFormWithNFields(2)) << "Waiting for after before field removal"; } @@ -669,7 +669,7 @@ // Focus target form field. const std::string focus_name_first_js = "document.getElementById('NAME_FIRST').focus();"; - ASSERT_TRUE(content::ExecuteScript(web_contents(), focus_name_first_js)); + ASSERT_TRUE(content::ExecJs(web_contents(), focus_name_first_js)); // Assert that autofill is not yet available for target form field. // Loop while criteria is not met. @@ -707,7 +707,7 @@ ASSERT_TRUE(layout_waiter_two.WaitForNotification()); // Focus target form field. - ASSERT_TRUE(content::ExecuteScript(web_contents(), focus_name_first_js)); + ASSERT_TRUE(content::ExecJs(web_contents(), focus_name_first_js)); // Assert that autofill is now available for target form field. // Loop while criteria is not met. @@ -740,7 +740,7 @@ // Focus target form field. const std::string focus_name_first_js = "document.getElementById('NAME_FIRST').focus();"; - ASSERT_TRUE(content::ExecuteScript(web_contents(), focus_name_first_js)); + ASSERT_TRUE(content::ExecJs(web_contents(), focus_name_first_js)); // Assert that autocomplete is not yet available for target form field. // Loop while criteria is not met. @@ -774,7 +774,7 @@ ASSERT_TRUE(layout_waiter_two.WaitForNotification()); // Focus target form field. - ASSERT_TRUE(content::ExecuteScript(web_contents(), focus_name_first_js)); + ASSERT_TRUE(content::ExecJs(web_contents(), focus_name_first_js)); // Assert that autocomplete is now available for target form field. // Loop while criteria is not met. @@ -944,7 +944,7 @@ // Simulate a mouse click to submit the form because form submissions not // triggered by user gestures are ignored. std::string onclick_js = "document.onclick = function() { " + js + "; };"; - ASSERT_TRUE(content::ExecuteScript(web_contents(), onclick_js)); + ASSERT_TRUE(content::ExecJs(web_contents(), onclick_js)); content::SimulateMouseClick(web_contents(), 0, blink::WebMouseEvent::Button::kLeft); }
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc index 36447e1..93bc3640 100644 --- a/chrome/browser/autofill/autofill_interactive_uitest.cc +++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -1875,15 +1875,15 @@ SetTestUrlResponse(kTestForm); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetTestUrl())); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( GetWebContents(), "document.getElementById('firstname').type = 'password';")); // At this point, the IsPasswordFieldForAutofill() function returns true and // will continue to return true for the field, even when the type is changed // back to 'search'. - ASSERT_TRUE(content::ExecuteScript( - GetWebContents(), - "document.getElementById('firstname').type = 'search';")); + ASSERT_TRUE( + content::ExecJs(GetWebContents(), + "document.getElementById('firstname').type = 'search';")); // Regression test for crbug.com/918351 whether the datalist becomes available // again. @@ -2230,7 +2230,7 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GetTestUrl())); // Dynamically construct the form. - ASSERT_TRUE(content::ExecuteScript(GetWebContents(), "BuildForm();")); + ASSERT_TRUE(content::ExecJs(GetWebContents(), "BuildForm();")); ASSERT_TRUE(AutofillFlow(GetElementById("firstname"), this, {.show_method = ShowMethod::ByChar('M'), @@ -2578,8 +2578,8 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); ASSERT_TRUE(AutofillFlow(GetElementById("NAME_FIRST"), this)); - ASSERT_TRUE(content::ExecuteScript( - GetWebContents(), "document.getElementById('testform').reset()")); + ASSERT_TRUE(content::ExecJs(GetWebContents(), + "document.getElementById('testform').reset()")); ASSERT_TRUE(AutofillFlow(GetElementById("NAME_FIRST"), this)); @@ -2678,8 +2678,8 @@ content::LoadStopObserver load_stop_observer(GetWebContents()); - ASSERT_TRUE(content::ExecuteScript( - GetWebContents(), "document.getElementById('testform').submit();")); + ASSERT_TRUE(content::ExecJs(GetWebContents(), + "document.getElementById('testform').submit();")); // This will ensure the test didn't hang. load_stop_observer.Wait(); } @@ -2695,7 +2695,7 @@ // When suggestions are shown, disable autocomplete for the active field. auto SetAutocompleteOff = [this]() { - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( GetWebContents(), "document.querySelector('input').autocomplete = 'off';")); }; @@ -3090,7 +3090,7 @@ // We need the fencedframe element to have id set to a known value if (GetParam() != FrameType::kIFrame) { - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( GetWebContents(), "document.getElementsByTagName('fencedframe')[0].id = 'crossFF';")); } @@ -3115,7 +3115,7 @@ std::string script_delete = base::StringPrintf( "document.body.removeChild(document.getElementById('%s'))", GetParam() == FrameType::kIFrame ? "crossFrame" : "crossFF"); - ASSERT_TRUE(content::ExecuteScript(GetWebContents(), script_delete)); + ASSERT_TRUE(content::ExecJs(GetWebContents(), script_delete)); // The popup should have disappeared with the iframe. EXPECT_FALSE(IsPopupShown()); @@ -3729,8 +3729,8 @@ // the browser by a lot. AdvanceClock(base::Minutes(10)); content::LoadStopObserver load_stop_observer(GetWebContents()); - ASSERT_TRUE(content::ExecuteScript( - GetWebContents(), "document.getElementById('testform').submit();")); + ASSERT_TRUE(content::ExecJs(GetWebContents(), + "document.getElementById('testform').submit();")); load_stop_observer.Wait(); // Short hand for ExpectbucketCount:
diff --git a/chrome/browser/autofill/captured_sites_test_utils.cc b/chrome/browser/autofill/captured_sites_test_utils.cc index 2296658..43a4f64 100644 --- a/chrome/browser/autofill/captured_sites_test_utils.cc +++ b/chrome/browser/autofill/captured_sites_test_utils.cc
@@ -1284,9 +1284,9 @@ } // Navigate to the starting URL, wait for the page to complete loading. - if (!content::ExecuteScript(GetWebContents(), - base::StringPrintf("window.location.href = '%s';", - starting_url->c_str()))) { + if (!content::ExecJs(GetWebContents(), + base::StringPrintf("window.location.href = '%s';", + starting_url->c_str()))) { ADD_FAILURE() << "Failed to navigate Chrome to '" << *starting_url << "!"; return false; } @@ -1508,7 +1508,7 @@ // Execute the commands. for (const std::string& command : commands) { - if (!content::ExecuteScript(frame, command)) { + if (!content::ExecJs(frame, command)) { ADD_FAILURE() << "Failed to execute JavaScript command `" << command << "`!"; return false; @@ -2051,7 +2051,7 @@ " (function(target) { %s })(element);" "} catch(ex) {}", element_xpath.c_str(), execute_function_body.c_str())); - return ExecuteScript(frame, js); + return ExecJs(frame, js); } bool TestRecipeReplayer::GetElementProperty(
diff --git a/chrome/browser/autofill/test/BUILD.gn b/chrome/browser/autofill/test/BUILD.gn index 0e1e1f7..8da7a6e 100644 --- a/chrome/browser/autofill/test/BUILD.gn +++ b/chrome/browser/autofill/test/BUILD.gn
@@ -15,10 +15,10 @@ "//base:base_java", "//chrome/browser/autofill/test:test_support_java", "//chrome/browser/flags:java", - "//chrome/browser/video_tutorials:test_support_java", "//chrome/test/android:chrome_java_integration_test_support", "//components/autofill/android:autofill_java_resources", "//components/autofill/android:autofill_payments_java_resources", + "//components/image_fetcher:test_support_java", "//third_party/androidx:androidx_appcompat_appcompat_resources_java", "//third_party/androidx:androidx_test_runner_java", "//third_party/google-truth:google_truth_java",
diff --git a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java b/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java index ea08d5e..51ef4ab9 100644 --- a/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java +++ b/chrome/browser/autofill/test/android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
@@ -34,9 +34,9 @@ import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard; import org.chromium.chrome.browser.autofill.PersonalDataManager.ValueWithStatus; import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.video_tutorials.test.TestImageFetcher; import org.chromium.chrome.test.ChromeBrowserTestRule; import org.chromium.chrome.test.util.browser.Features; +import org.chromium.components.image_fetcher.test.TestImageFetcher; import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.url.GURL;
diff --git a/chrome/browser/banners/app_banner_manager_browsertest.cc b/chrome/browser/banners/app_banner_manager_browsertest.cc index da329809..6262b06 100644 --- a/chrome/browser/banners/app_banner_manager_browsertest.cc +++ b/chrome/browser/banners/app_banner_manager_browsertest.cc
@@ -582,10 +582,10 @@ IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, WebAppBannerNeedsEngagement) { - base::AutoReset<double> scoped_engagement = - AppBannerSettingsHelper::ScopeTotalEngagementForTesting(1); std::unique_ptr<AppBannerManagerTest> manager( CreateAppBannerManager(browser())); + base::AutoReset<double> scoped_engagement = + AppBannerSettingsHelper::ScopeTotalEngagementForTesting(1); base::HistogramTester histograms; site_engagement::SiteEngagementService* service =
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index ffc4a917..82fbdec 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd
@@ -252,9 +252,6 @@ <include name="IDR_OFFLINE_INTERNALS_CSS" file="resources\offline_pages\offline_internals.css" type="BINDATA" /> <include name="IDR_OFFLINE_INTERNALS_JS" file="${root_gen_dir}\chrome\browser\resources\offline_pages\tsc\offline_internals.js" use_base_dir="false" type="BINDATA" /> <include name="IDR_OFFLINE_INTERNALS_BROWSER_PROXY_JS" file="${root_gen_dir}\chrome\browser\resources\offline_pages\tsc\offline_internals_browser_proxy.js" use_base_dir="false" type="BINDATA" /> - <include name="IDR_VIDEO_PLAYER_HTML" file="resources\video_tutorials\video_player.html" type="BINDATA" /> - <include name="IDR_VIDEO_PLAYER_CSS" file="resources\video_tutorials\video_player.css" type="BINDATA" /> - <include name="IDR_VIDEO_PLAYER_JS" file="${root_gen_dir}\chrome\browser\resources\video_tutorials\tsc\video_player.js" use_base_dir="false" type="BINDATA" /> </if> <if expr="enable_hangout_services_extension">
diff --git a/chrome/browser/browsing_topics/browsing_topics_service_browsertest.cc b/chrome/browser/browsing_topics/browsing_topics_service_browsertest.cc index 5db071a..b2bf502 100644 --- a/chrome/browser/browsing_topics/browsing_topics_service_browsertest.cc +++ b/chrome/browser/browsing_topics/browsing_topics_service_browsertest.cc
@@ -1233,9 +1233,8 @@ // away later. content::TestNavigationObserver popup_observer(main_frame_url); popup_observer.StartWatchingNewWebContents(); - EXPECT_TRUE( - ExecuteScript(web_contents()->GetPrimaryMainFrame(), - content::JsReplace("window.open($1)", main_frame_url))); + EXPECT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(), + content::JsReplace("window.open($1)", main_frame_url))); popup_observer.Wait(); GURL new_url =
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 360065f2..7b839a3 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1441,31 +1441,6 @@ !IsTopChromeRendererPresent(profile); } -bool DoesGaiaOriginRequireDedicatedProcess() { -#if !BUILDFLAG(IS_ANDROID) - return true; -#else - // Sign-in process isolation is not strictly needed on Android, see - // https://crbug.com/739418. On Android, it's more optional but it does - // improve security generally and specifically it allows the exposure of - // certain optional privileged APIs. - - // Kill switch that falls back to the legacy behavior. - if (!base::FeatureList::IsEnabled(kAllowGaiaOriginIsolationOnAndroid)) { - return false; - } - - if (site_isolation::SiteIsolationPolicy:: - ShouldDisableSiteIsolationDueToMemoryThreshold( - content::SiteIsolationMode::kPartialSiteIsolation)) { - // Insufficient memory to isolate Gaia's origin. - return false; - } - - return true; -#endif // !BUILDFLAG(IS_ANDROID) -} - #if BUILDFLAG(FULL_SAFE_BROWSING) void HandleExpandedPaths( @@ -7759,3 +7734,29 @@ return nullptr; #endif } + +// static +bool ChromeContentBrowserClient::DoesGaiaOriginRequireDedicatedProcess() { +#if !BUILDFLAG(IS_ANDROID) + return true; +#else + // Sign-in process isolation is not strictly needed on Android, see + // https://crbug.com/739418. On Android, it's more optional but it does + // improve security generally and specifically it allows the exposure of + // certain optional privileged APIs. + + // Kill switch that falls back to the legacy behavior. + if (!base::FeatureList::IsEnabled(kAllowGaiaOriginIsolationOnAndroid)) { + return false; + } + + if (site_isolation::SiteIsolationPolicy:: + ShouldDisableSiteIsolationDueToMemoryThreshold( + content::SiteIsolationMode::kPartialSiteIsolation)) { + // Insufficient memory to isolate Gaia's origin. + return false; + } + + return true; +#endif // !BUILDFLAG(IS_ANDROID) +}
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 6c2ecc5..5fdef60 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -896,6 +896,9 @@ friend class DisableWebRtcEncryptionFlagTest; friend class InProcessBrowserTest; + FRIEND_TEST_ALL_PREFIXES(ChromeSiteIsolationPolicyTest, + IsolatedOriginsContainChromeOrigins); + // Initializes `network_contexts_parent_directory_` and // `safe_browsing_service_` on the UI thread. void InitOnUIThread(); @@ -967,6 +970,9 @@ std::unique_ptr<ScopedKeepAlive> keep_alive_handle); #endif + // True if the Gaia origin should be isolated in a dedicated process. + static bool DoesGaiaOriginRequireDedicatedProcess(); + // Vector of additional ChromeContentBrowserClientParts. // Parts are deleted in the reverse order they are added. std::vector<std::unique_ptr<ChromeContentBrowserClientParts>> extra_parts_;
diff --git a/chrome/browser/chrome_content_browser_client_browsertest.cc b/chrome/browser/chrome_content_browser_client_browsertest.cc index d5db63b..170ad8e 100644 --- a/chrome/browser/chrome_content_browser_client_browsertest.cc +++ b/chrome/browser/chrome_content_browser_client_browsertest.cc
@@ -307,8 +307,7 @@ GURL generic_url(https_test_server().GetURL("ntp.com", "/title1.html")); content::TestNavigationObserver opened_tab_observer(nullptr); opened_tab_observer.StartWatchingNewWebContents(); - EXPECT_TRUE( - ExecuteScript(ntp_tab, "window.open('" + generic_url.spec() + "');")); + EXPECT_TRUE(ExecJs(ntp_tab, "window.open('" + generic_url.spec() + "');")); opened_tab_observer.Wait(); ASSERT_EQ(2, browser()->tab_strip_model()->count());
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc index 1004d89..25475263 100644 --- a/chrome/browser/chrome_navigation_browsertest.cc +++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -140,7 +140,7 @@ browser()->tab_strip_model()->GetActiveWebContents(); content::TestNavigationObserver observer(web_contents); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( web_contents->GetPrimaryMainFrame(), base::StringPrintf("var iframe = document.getElementById('test');\n" "iframe.setAttribute('src', '%s');\n", @@ -198,7 +198,7 @@ #endif std::string new_tab_click_script = base::StringPrintf( new_tab_click_script_template, id_of_anchor_to_click); - EXPECT_TRUE(ExecuteScript(main_contents, new_tab_click_script)); + EXPECT_TRUE(ExecJs(main_contents, new_tab_click_script)); // Wait for a new tab to appear (the whole point of this test). new_contents = new_tab_observer.GetWebContents(); @@ -397,7 +397,7 @@ // WebContentsImpl::DidAccessInitialDocument detects that the initial, empty // document was accessed. EXPECT_EQ(pending_entry, navigation_controller.GetVisibleEntry()); - EXPECT_TRUE(content::ExecuteScript(new_web_contents, "window.x=3")); + EXPECT_TRUE(content::ExecJs(new_web_contents, "window.x=3")); EXPECT_NE(pending_entry, navigation_controller.GetVisibleEntry()); } @@ -433,12 +433,12 @@ anchor.target = 'target_name: ' + url; anchor.href = url; )"; - EXPECT_TRUE(ExecuteScript( - main_contents, content::JsReplace(kUrlSettingTemplate, kTestUrl))); + EXPECT_TRUE(ExecJs(main_contents, + content::JsReplace(kUrlSettingTemplate, kTestUrl))); // Simulate a click on the link and wait for the new window. content::WebContentsAddedObserver new_tab_observer; - EXPECT_TRUE(ExecuteScript(main_contents, "simulateClick()")); + EXPECT_TRUE(ExecJs(main_contents, "simulateClick()")); content::WebContents* new_contents = new_tab_observer.GetWebContents(); // Verify that the invalid URL was not committed. @@ -492,7 +492,7 @@ kPushStateURL); std::string push_state = "history.pushState({}, \"title 1\", \"" + kPushStateURL.spec() + "\");"; - EXPECT_TRUE(ExecuteScript(web_contents, push_state)); + EXPECT_TRUE(ExecJs(web_contents, push_state)); content::NavigationEntry* last_committed = web_contents->GetController().GetLastCommittedEntry(); EXPECT_TRUE(last_committed); @@ -534,7 +534,7 @@ // The error page should not inherit the CSP directive that blocks all // scripts from the parent frame, so this script should be allowed to - // execute. Since ExecuteScript will execute the passed-in script regardless + // execute. Since ExecJs will execute the passed-in script regardless // of CSP, use a javascript: URL which does go through the CSP checks. content::RenderFrameHost* error_host = ChildFrameAt(web_contents->GetPrimaryMainFrame(), 0); @@ -563,16 +563,18 @@ // Try navigating to the error page URL and make sure it is canceled and the // old URL remains the last committed one. GURL error_url(content::kUnreachableWebDataURL); - EXPECT_TRUE(ExecuteScript(web_contents, - "location.href = '" + error_url.spec() + "';")); + EXPECT_TRUE( + ExecJs(web_contents, "location.href = '" + error_url.spec() + "';")); EXPECT_TRUE(content::WaitForLoadStop(web_contents)); EXPECT_EQ(url, web_contents->GetLastCommittedURL()); // Also ensure that a page can't embed an iframe for an error page URL. - EXPECT_TRUE(ExecuteScript(web_contents, - "var frame = document.createElement('iframe');\n" - "frame.src = '" + error_url.spec() + "';\n" - "document.body.appendChild(frame);")); + EXPECT_TRUE(ExecJs(web_contents, + "var frame = document.createElement('iframe');\n" + "frame.src = '" + + error_url.spec() + + "';\n" + "document.body.appendChild(frame);")); EXPECT_TRUE(content::WaitForLoadStop(web_contents)); content::RenderFrameHost* subframe_host = ChildFrameAt(web_contents->GetPrimaryMainFrame(), 0); @@ -585,7 +587,7 @@ GURL redirect_to_error_url( embedded_test_server()->GetURL("/server-redirect?" + error_url.spec())); content::TestNavigationObserver observer(web_contents); - EXPECT_TRUE(ExecuteScript( + EXPECT_TRUE(ExecJs( web_contents, "location.href = '" + redirect_to_error_url.spec() + "';")); observer.Wait(); EXPECT_EQ(url, web_contents->GetLastCommittedURL()); @@ -609,8 +611,7 @@ // loading of the 404 error page, so check that the last committed entry was // indeed for the error page. content::TestNavigationObserver observer(web_contents); - EXPECT_TRUE( - ExecuteScript(web_contents, "location.href = '" + url.spec() + "';")); + EXPECT_TRUE(ExecJs(web_contents, "location.href = '" + url.spec() + "';")); observer.Wait(); EXPECT_FALSE(observer.last_navigation_succeeded()); EXPECT_EQ(url, web_contents->GetLastCommittedURL()); @@ -689,7 +690,7 @@ url_interceptor.reset(); { content::TestNavigationObserver observer(web_contents); - EXPECT_TRUE(ExecuteScript(web_contents, "location.reload();")); + EXPECT_TRUE(ExecJs(web_contents, "location.reload();")); observer.Wait(); EXPECT_TRUE(observer.last_navigation_succeeded()); EXPECT_EQ(GURL(url::kAboutBlankURL), observer.last_navigation_url()); @@ -1141,8 +1142,7 @@ // Make sure that a renderer-initiated navigation to the sign-in page swaps // processes. content::TestNavigationManager manager(web_contents, signin_url); - EXPECT_TRUE( - ExecuteScript(web_contents, "location = '" + signin_url.spec() + "';")); + EXPECT_TRUE(ExecJs(web_contents, "location = '" + signin_url.spec() + "';")); ASSERT_TRUE(manager.WaitForNavigationFinished()); EXPECT_NE(web_contents->GetPrimaryMainFrame()->GetSiteInstance(), first_instance); @@ -1480,8 +1480,8 @@ content::WebContents* main_contents = browser()->tab_strip_model()->GetActiveWebContents(); content::TestNavigationObserver observer(main_contents); - ASSERT_TRUE(ExecuteScript(main_contents, - "document.getElementById('title1').click();")); + ASSERT_TRUE( + ExecJs(main_contents, "document.getElementById('title1').click();")); observer.Wait(); // Make sure popup attempt fails due to lack of transient user activation. @@ -1523,7 +1523,7 @@ content::WebContentsConsoleObserver console_observer(opener); console_observer.SetPattern( "Navigating a cross-origin opener to a download (*) is deprecated*"); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( popup, "window.opener.location ='data:html/text;base64,'+btoa('payload');")); @@ -1570,7 +1570,7 @@ content::DownloadTestObserverInProgress observer( browser()->profile()->GetDownloadManager(), 1 /* wait_count */); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( popup, "window.opener.location ='data:html/text;base64,'+btoa('payload');")); observer.WaitForFinished(); @@ -1910,8 +1910,8 @@ { content::TestNavigationObserver new_tab_observer(nullptr, 1); new_tab_observer.StartWatchingNewWebContents(); - ASSERT_TRUE(ExecuteScript( - opener, "document.getElementsByTagName('a')[0].click();")); + ASSERT_TRUE( + ExecJs(opener, "document.getElementsByTagName('a')[0].click();")); new_tab_observer.Wait(); } @@ -1924,8 +1924,8 @@ EXPECT_EQ(opener, browser()->tab_strip_model()->GetActiveWebContents()); { content::TestNavigationObserver new_tab_observer(new_contents, 1); - ASSERT_TRUE(ExecuteScript( - opener, "document.getElementsByTagName('a')[0].click();")); + ASSERT_TRUE( + ExecJs(opener, "document.getElementsByTagName('a')[0].click();")); new_tab_observer.Wait(); } EXPECT_EQ(new_contents, browser()->tab_strip_model()->GetActiveWebContents()); @@ -2011,7 +2011,7 @@ content::WebContents* main_contents = browser()->tab_strip_model()->GetActiveWebContents(); content::TestNavigationObserver observer(main_contents); - EXPECT_TRUE(ExecuteScript(main_contents, "location = '" + url.spec() + "';")); + EXPECT_TRUE(ExecJs(main_contents, "location = '" + url.spec() + "';")); observer.Wait(); EXPECT_EQ(url, main_contents->GetLastCommittedURL()); @@ -2457,7 +2457,7 @@ content::WebContentsAddedObserver web_contents_added_observer; content::TestNavigationObserver navigation_observer(nullptr, 1); navigation_observer.StartWatchingNewWebContents(); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( browser()->tab_strip_model()->GetActiveWebContents(), content::JsReplace( "window.open($1, 'oauth_window', 'width=10,height=10');",
diff --git a/chrome/browser/chrome_render_widget_host_browsertests.cc b/chrome/browser/chrome_render_widget_host_browsertests.cc index 77683e7..00b6e88c 100644 --- a/chrome/browser/chrome_render_widget_host_browsertests.cc +++ b/chrome/browser/chrome_render_widget_host_browsertests.cc
@@ -110,7 +110,7 @@ // After focusing child_frame_b, document.hasFocus() should return // true for child_frame_b and all its ancestor frames. - EXPECT_TRUE(ExecuteScript(child_frame_b, "window.focus();")); + EXPECT_TRUE(ExecJs(child_frame_b, "window.focus();")); EXPECT_EQ(child_frame_b, web_contents->GetFocusedFrame()); EXPECT_TRUE(document_is_active_and_focused(main_frame_a)); EXPECT_TRUE(document_is_active_and_focused(child_frame_b)); @@ -122,7 +122,7 @@ // After focusing child_frame_c, document.hasFocus() should return // true for child_frame_c and all its ancestor frames. - EXPECT_TRUE(ExecuteScript(child_frame_c, "window.focus();")); + EXPECT_TRUE(ExecJs(child_frame_c, "window.focus();")); EXPECT_EQ(child_frame_c, web_contents->GetFocusedFrame()); EXPECT_TRUE(document_is_active_and_focused(main_frame_a)); EXPECT_TRUE(document_is_active_and_focused(child_frame_b)); @@ -139,7 +139,7 @@ // After focusing child_frame_d, document.hasFocus() should return // true for child_frame_d and all its ancestor frames. - EXPECT_TRUE(ExecuteScript(child_frame_d, "window.focus();")); + EXPECT_TRUE(ExecJs(child_frame_d, "window.focus();")); EXPECT_EQ(child_frame_d, web_contents->GetFocusedFrame()); EXPECT_TRUE(document_is_active_and_focused(main_frame_a)); EXPECT_FALSE(document_is_active_and_focused(child_frame_b)); @@ -154,7 +154,7 @@ // descendants should return false. On the renderer side, both the // 'active' and 'focus' states for blink::FocusController will be // true. - EXPECT_TRUE(ExecuteScript(main_frame_a, "window.focus();")); + EXPECT_TRUE(ExecJs(main_frame_a, "window.focus();")); EXPECT_EQ(main_frame_a, web_contents->GetFocusedFrame()); EXPECT_TRUE(document_is_active_and_focused(main_frame_a)); EXPECT_FALSE(document_is_active_and_focused(child_frame_b));
diff --git a/chrome/browser/chrome_security_exploit_browsertest.cc b/chrome/browser/chrome_security_exploit_browsertest.cc index e89c2b6..51faa2a 100644 --- a/chrome/browser/chrome_security_exploit_browsertest.cc +++ b/chrome/browser/chrome_security_exploit_browsertest.cc
@@ -518,10 +518,9 @@ content::RenderProcessHostBadMojoMessageWaiter crash_observer( rfh->GetProcess()); - // The renderer should always get killed, but sometimes ExecuteScript returns + // The renderer should always get killed, but sometimes ExecJs returns // true anyway, so just ignore the result. - std::ignore = - content::ExecuteScript(rfh, "URL.createObjectURL(new Blob(['foo']))"); + std::ignore = content::ExecJs(rfh, "URL.createObjectURL(new Blob(['foo']))"); // If the process is killed, this test passes. EXPECT_EQ( @@ -572,10 +571,9 @@ content::RenderProcessHostBadMojoMessageWaiter crash_observer( rfh->GetProcess()); - // The renderer should always get killed, but sometimes ExecuteScript returns + // The renderer should always get killed, but sometimes ExecJs returns // true anyway, so just ignore the result. - std::ignore = - content::ExecuteScript(rfh, "URL.createObjectURL(new Blob(['foo']))"); + std::ignore = content::ExecJs(rfh, "URL.createObjectURL(new Blob(['foo']))"); // If the process is killed, this test passes. EXPECT_EQ(
diff --git a/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_dialog.cc b/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_dialog.cc index 8cfd70f7..e27c1fa 100644 --- a/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_dialog.cc +++ b/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_dialog.cc
@@ -39,18 +39,6 @@ } DlpWarnDialog::DlpWarnDialogOptions::DlpWarnDialogOptions( - Restriction restriction, - const std::vector<DlpConfidentialFile>& confidential_files, - absl::optional<DlpFileDestination> files_destination, - DlpFilesController::FileAction files_action) - : restriction(restriction), - confidential_files(confidential_files), - files_destination(files_destination), - files_action(files_action) { - DCHECK(restriction == Restriction::kFiles); -} - -DlpWarnDialog::DlpWarnDialogOptions::DlpWarnDialogOptions( const DlpWarnDialogOptions& other) = default; DlpWarnDialog::DlpWarnDialogOptions&
diff --git a/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_dialog.h b/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_dialog.h index de4e43b9..5dcbca7 100644 --- a/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_dialog.h +++ b/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_dialog.h
@@ -27,7 +27,6 @@ // A structure to keep track of optional and configurable parameters of a // DlpWarnDialog. - // TODO(b/278046656): Clean this up. struct DlpWarnDialogOptions { DlpWarnDialogOptions() = delete; explicit DlpWarnDialogOptions(Restriction restriction); @@ -36,11 +35,6 @@ DlpWarnDialogOptions(Restriction restriction, DlpConfidentialContents confidential_contents, const std::u16string& application_title); - DlpWarnDialogOptions( - Restriction restriction, - const std::vector<DlpConfidentialFile>& confidential_files, - absl::optional<DlpFileDestination> files_destination, - DlpFilesController::FileAction files_action); DlpWarnDialogOptions(const DlpWarnDialogOptions& other); DlpWarnDialogOptions& operator=(const DlpWarnDialogOptions& other); ~DlpWarnDialogOptions(); @@ -52,11 +46,7 @@ const DlpWarnDialogOptions& b) { return a.restriction == b.restriction && a.application_title == b.application_title && - a.files_destination == b.files_destination && - a.files_action == b.files_action && - EqualWithTitles(a.confidential_contents, - b.confidential_contents) && - a.confidential_files == b.confidential_files; + EqualWithTitles(a.confidential_contents, b.confidential_contents); } friend bool operator!=(const DlpWarnDialogOptions& a, const DlpWarnDialogOptions& b) { @@ -69,11 +59,6 @@ // Non-empty only if the |restriction| is one of kScreenCapture, // kVideoCapture, or kScreenshare. DlpConfidentialContents confidential_contents; - - // Have value only if the |restriction| is kFiles: - std::vector<DlpConfidentialFile> confidential_files; - absl::optional<DlpFileDestination> files_destination; - absl::optional<DlpFilesController::FileAction> files_action; }; DlpWarnDialog() = delete;
diff --git a/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_notifier.cc b/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_notifier.cc index a92c44f..512b124 100644 --- a/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_notifier.cc +++ b/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_notifier.cc
@@ -12,6 +12,7 @@ #include "chrome/browser/chromeos/policy/dlp/dialogs/files_policy_dialog.h" #include "chrome/browser/chromeos/policy/dlp/dialogs/policy_dialog_base.h" #include "chrome/browser/chromeos/policy/dlp/dlp_file_destination.h" +#include "chrome/browser/chromeos/policy/dlp/dlp_files_controller.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" #include "ui/gfx/native_widget_types.h" @@ -57,20 +58,6 @@ DlpWarnDialog::Restriction::kVideoCapture, confidential_contents)); } -base::WeakPtr<views::Widget> DlpWarnNotifier::ShowDlpFilesWarningDialog( - OnDlpRestrictionCheckedCallback callback, - const std::vector<DlpConfidentialFile>& confidential_files, - const DlpFileDestination& files_destination, - DlpFilesController::FileAction files_action, - gfx::NativeWindow modal_parent) { - return ShowDlpWarningDialog( - std::move(callback), - DlpWarnDialog::DlpWarnDialogOptions(DlpWarnDialog::Restriction::kFiles, - confidential_files, files_destination, - files_action), - modal_parent); -} - base::WeakPtr<views::Widget> DlpWarnNotifier::ShowDlpScreenShareWarningDialog( OnDlpRestrictionCheckedCallback callback, const DlpConfidentialContents& confidential_contents, @@ -81,6 +68,21 @@ confidential_contents, application_title)); } +base::WeakPtr<views::Widget> DlpWarnNotifier::ShowDlpFilesWarningDialog( + OnDlpRestrictionCheckedCallback callback, + const std::vector<DlpConfidentialFile>& confidential_files, + const DlpFileDestination& destination, + DlpFilesController::FileAction action, + gfx::NativeWindow modal_parent) { + views::Widget* widget = views::DialogDelegate::CreateDialogWidget( + std::make_unique<FilesPolicyDialog>(std::move(callback), + confidential_files, destination, + action, modal_parent), + /*context=*/nullptr, /*parent=*/modal_parent); + ShowWidget(widget); + return widget->GetWeakPtr(); +} + int DlpWarnNotifier::ActiveWarningDialogsCountForTesting() const { return widgets_.size(); } @@ -89,20 +91,14 @@ OnDlpRestrictionCheckedCallback callback, DlpWarnDialog::DlpWarnDialogOptions options, gfx::NativeWindow modal_parent) { - views::Widget* widget; - if (options.restriction == PolicyDialogBase::Restriction::kFiles) { - widget = views::DialogDelegate::CreateDialogWidget( - std::make_unique<FilesPolicyDialog>( - std::move(callback), options.confidential_files, - options.files_destination.value(), options.files_action.value(), - modal_parent), - /*context=*/nullptr, /*parent=*/modal_parent); - } else { // on-screen restriction - widget = views::DialogDelegate::CreateDialogWidget( - std::make_unique<DlpWarnDialog>(std::move(callback), options), - /*context=*/nullptr, /*parent=*/nullptr); - } + views::Widget* widget = views::DialogDelegate::CreateDialogWidget( + std::make_unique<DlpWarnDialog>(std::move(callback), options), + /*context=*/nullptr, /*parent=*/nullptr); + ShowWidget(widget); + return widget->GetWeakPtr(); +} +void DlpWarnNotifier::ShowWidget(views::Widget* widget) { widget->Show(); // We disable the dialog's hide animations after showing it so that it doesn't // end up showing in the screenshots, video recording, or screen share. @@ -113,7 +109,6 @@ widget->GetNativeWindow()->SetCapture(); widget->AddObserver(this); widgets_.push_back(widget); - return widget->GetWeakPtr(); } void DlpWarnNotifier::RemoveWidget(views::Widget* widget) {
diff --git a/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_notifier.h b/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_notifier.h index 8fd6814..8051c91 100644 --- a/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_notifier.h +++ b/chrome/browser/chromeos/policy/dlp/dialogs/dlp_warn_notifier.h
@@ -33,37 +33,26 @@ void OnWidgetDestroying(views::Widget* widget) override; // Shows a warning dialog that informs the user that printing is not - // recommended. Calls |callback| and passes user's choice of whether to + // recommended. Calls `callback` and passes user's choice of whether to // proceed or not. void ShowDlpPrintWarningDialog(OnDlpRestrictionCheckedCallback callback); // Shows a warning dialog that informs the user that screen capture is not - // recommended due to |confidential_contents| visible. Calls |callback| and + // recommended due to `confidential_contents` visible. Calls `callback` and // passes user's choice of whether to proceed or not. void ShowDlpScreenCaptureWarningDialog( OnDlpRestrictionCheckedCallback callback, const DlpConfidentialContents& confidential_contents); // Shows a warning dialog that informs the user that video capture is not - // recommended due to |confidential_contents| visible. Calls |callback| and + // recommended due to `confidential_contents` visible. Calls `callback` and // passes user's choice of whether to proceed or not. void ShowDlpVideoCaptureWarningDialog( OnDlpRestrictionCheckedCallback callback, const DlpConfidentialContents& confidential_contents); - // Shows a warning dialog that informs the user that |files_action| to - // |files_destination| on selected |confidential_files| is not recommended. - // Calls |callback| and passes user's choice of whether to proceed or not. - // Returns a pointer to the widget that owns the created dialog. - base::WeakPtr<views::Widget> ShowDlpFilesWarningDialog( - OnDlpRestrictionCheckedCallback callback, - const std::vector<DlpConfidentialFile>& confidential_files, - const DlpFileDestination& files_destination, - DlpFilesController::FileAction files_action, - gfx::NativeWindow modal_parent); - // Shows a warning dialog that informs the user that screen sharing is not - // recommended due to |confidential_contents| visible. Calls |callback| and + // recommended due to `confidential_contents` visible. Calls `callback` and // passes user's choice of whether to proceed or not. // Returns a pointer to the widget that owns the created dialog. base::WeakPtr<views::Widget> ShowDlpScreenShareWarningDialog( @@ -71,6 +60,18 @@ const DlpConfidentialContents& confidential_contents, const std::u16string& application_title); + // Shows a warning dialog that informs the user that `action` to + // `destination` on selected `confidential_files` is not recommended. + // Calls `callback` and passes user's choice of whether to proceed or not. + // Returns a pointer to the widget that owns the created dialog. + // Virtual to allow overrides in tests. + virtual base::WeakPtr<views::Widget> ShowDlpFilesWarningDialog( + OnDlpRestrictionCheckedCallback callback, + const std::vector<DlpConfidentialFile>& confidential_files, + const DlpFileDestination& destination, + DlpFilesController::FileAction action, + gfx::NativeWindow modal_parent); + // Returns the number of active widgets, which equals the number of warning // dialogs shown conucrrently. Useful for testing to verify that the dialogs // are shown/closed when expected. @@ -85,7 +86,10 @@ DlpWarnDialog::DlpWarnDialogOptions options, gfx::NativeWindow modal_parent = nullptr); - // Removes the |widget| from widgets_ and stops observing it. + // Helper method to show the `widget`. + virtual void ShowWidget(views::Widget* widget); + + // Removes the `widget` from widgets_ and stops observing it. void RemoveWidget(views::Widget* widget); // List of active widgets. Used in tests to verify that the dialog has or
diff --git a/chrome/browser/chromeos/policy/dlp/dialogs/mock_dlp_warn_notifier.cc b/chrome/browser/chromeos/policy/dlp/dialogs/mock_dlp_warn_notifier.cc index a063b75..20d6d11 100644 --- a/chrome/browser/chromeos/policy/dlp/dialogs/mock_dlp_warn_notifier.cc +++ b/chrome/browser/chromeos/policy/dlp/dialogs/mock_dlp_warn_notifier.cc
@@ -21,6 +21,18 @@ return this->DlpWarnNotifier::ShowDlpWarningDialog( std::move(callback), options, modal_parent); }); + + ON_CALL(*this, ShowDlpFilesWarningDialog) + .WillByDefault( + [this](OnDlpRestrictionCheckedCallback callback, + const std::vector<DlpConfidentialFile>& confidential_files, + const DlpFileDestination& destination, + DlpFilesController::FileAction action, + gfx::NativeWindow modal_parent) { + return this->DlpWarnNotifier::ShowDlpFilesWarningDialog( + std::move(callback), confidential_files, destination, action, + modal_parent); + }); } MockDlpWarnNotifier::MockDlpWarnNotifier(bool should_proceed)
diff --git a/chrome/browser/chromeos/policy/dlp/dialogs/mock_dlp_warn_notifier.h b/chrome/browser/chromeos/policy/dlp/dialogs/mock_dlp_warn_notifier.h index f813ca02..e6f7a4f 100644 --- a/chrome/browser/chromeos/policy/dlp/dialogs/mock_dlp_warn_notifier.h +++ b/chrome/browser/chromeos/policy/dlp/dialogs/mock_dlp_warn_notifier.h
@@ -37,6 +37,15 @@ gfx::NativeWindow modal_parent), (override)); + MOCK_METHOD(base::WeakPtr<views::Widget>, + ShowDlpFilesWarningDialog, + (OnDlpRestrictionCheckedCallback callback, + const std::vector<DlpConfidentialFile>& confidential_files, + const DlpFileDestination& destination, + DlpFilesController::FileAction action, + gfx::NativeWindow modal_parent), + (override)); + private: const bool should_proceed_; };
diff --git a/chrome/browser/chromeos/reporting/user_reporting_settings.cc b/chrome/browser/chromeos/reporting/user_reporting_settings.cc index 0a979239..ec202a0 100644 --- a/chrome/browser/chromeos/reporting/user_reporting_settings.cc +++ b/chrome/browser/chromeos/reporting/user_reporting_settings.cc
@@ -4,6 +4,8 @@ #include "chrome/browser/chromeos/reporting/user_reporting_settings.h" +#include <memory> + #include "base/callback_list.h" #include "base/functional/bind.h" #include "base/functional/callback_forward.h" @@ -11,14 +13,18 @@ #include "base/sequence_checker.h" #include "base/values.h" #include "chrome/browser/profiles/profile.h" +#include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" namespace reporting { UserReportingSettings::UserReportingSettings(base::WeakPtr<Profile> profile) : profile_(profile) { - DCHECK(profile_); - pref_change_registrar_.Init(profile_->GetPrefs()); + if (profile_) { + pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); + pref_change_registrar_->Init(profile_->GetPrefs()); + scoped_profile_observer_.Observe(profile_.get()); + } } UserReportingSettings::~UserReportingSettings() = default; @@ -30,12 +36,13 @@ DCHECK(profile_); DCHECK(profile_->GetPrefs()->FindPreference(path)); DCHECK(callback); + DCHECK(pref_change_registrar_); auto [iterator, added_element] = settings_observers_.emplace( path, std::make_unique<base::RepeatingClosureList>()); if (added_element) { // Initialize the pref change registrar for the specified path. - pref_change_registrar_.Add( + pref_change_registrar_->Add( path, base::BindRepeating(&UserReportingSettings::OnPrefChanged, weak_ptr_factory_.GetWeakPtr(), path)); } @@ -106,6 +113,23 @@ return false; } +bool UserReportingSettings::IsObservingSettingsForTest( + const std::string& path) { + if (!pref_change_registrar_) { + return false; + } + return pref_change_registrar_->IsObserved(path); +} + +void UserReportingSettings::OnProfileWillBeDestroyed(Profile* profile) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // Dispose the change registrar on profile destruction to prevent dangling + // pointer references to the user pref store. + pref_change_registrar_.reset(); + scoped_profile_observer_.Reset(); +} + void UserReportingSettings::OnPrefChanged(const std::string& path) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(settings_observers_.contains(path));
diff --git a/chrome/browser/chromeos/reporting/user_reporting_settings.h b/chrome/browser/chromeos/reporting/user_reporting_settings.h index 27065be..f0cd8a00 100644 --- a/chrome/browser/chromeos/reporting/user_reporting_settings.h +++ b/chrome/browser/chromeos/reporting/user_reporting_settings.h
@@ -11,10 +11,12 @@ #include "base/callback_list.h" #include "base/functional/callback_forward.h" #include "base/memory/weak_ptr.h" +#include "base/scoped_observation.h" #include "base/sequence_checker.h" #include "base/thread_annotations.h" #include "base/values.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_observer.h" #include "components/prefs/pref_change_registrar.h" #include "components/reporting/metrics/reporting_settings.h" @@ -25,7 +27,7 @@ // use to access reporting settings and subscribe to reporting setting updates. // Needs to be accessed from the main thread given its dependency on user // profiles and the user pref store. -class UserReportingSettings : public ReportingSettings { +class UserReportingSettings : public ReportingSettings, public ProfileObserver { public: explicit UserReportingSettings(base::WeakPtr<Profile> profile); UserReportingSettings(const UserReportingSettings& other) = delete; @@ -46,20 +48,32 @@ bool GetReportingEnabled(const std::string& path, bool* out_value) const override; + // Returns whether the specified setting is being observed for testing + // purposes. + bool IsObservingSettingsForTest(const std::string& path); + private: + // ProfileObserver: + void OnProfileWillBeDestroyed(Profile* profile) override; + // Internal callback triggered when the setting value is updated. void OnPrefChanged(const std::string& path); SEQUENCE_CHECKER(sequence_checker_); const base::WeakPtr<Profile> profile_; - PrefChangeRegistrar pref_change_registrar_; + std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_; // A map of setting names to a list of observers. Observers are triggered in // the order they are added. std::map<std::string, std::unique_ptr<base::RepeatingClosureList>> settings_observers_ GUARDED_BY_CONTEXT(sequence_checker_); + // Observer that is used to track profile lifecycle so we can perform + // cleanup tasks on destruction. + base::ScopedObservation<Profile, ProfileObserver> scoped_profile_observer_ + GUARDED_BY_CONTEXT(sequence_checker_){this}; + base::WeakPtrFactory<UserReportingSettings> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/chromeos/reporting/user_reporting_settings_unittest.cc b/chrome/browser/chromeos/reporting/user_reporting_settings_unittest.cc index b431277..473e0193 100644 --- a/chrome/browser/chromeos/reporting/user_reporting_settings_unittest.cc +++ b/chrome/browser/chromeos/reporting/user_reporting_settings_unittest.cc
@@ -7,6 +7,7 @@ #include <memory> #include "base/callback_list.h" +#include "base/functional/callback_helpers.h" #include "base/test/bind.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" @@ -241,5 +242,20 @@ ASSERT_THAT(callback_trigger_count, Eq(2)); } +TEST_F(UserReportingSettingsTest, OnProfileDestruction) { + profile_->GetTestingPrefService()->registry()->RegisterBooleanPref( + kSettingPath, /*default_value=*/false); + const auto callback_subscription = + user_reporting_settings_->AddSettingsObserver(kSettingPath, + base::DoNothing()); + ASSERT_TRUE( + user_reporting_settings_->IsObservingSettingsForTest(kSettingPath)); + + // Delete profile and ensure the setting is no longer observed. + profile_manager_.DeleteAllTestingProfiles(); + EXPECT_FALSE( + user_reporting_settings_->IsObservingSettingsForTest(kSettingPath)); +} + } // namespace } // namespace reporting
diff --git a/chrome/browser/companion/core/features.cc b/chrome/browser/companion/core/features.cc index eeb1489..c6444eb 100644 --- a/chrome/browser/companion/core/features.cc +++ b/chrome/browser/companion/core/features.cc
@@ -29,6 +29,9 @@ constexpr base::FeatureParam<bool> kEnableOpenCompanionForWebSearch{ &kSidePanelCompanion, "open-companion-for-web-search", true}; +constexpr base::FeatureParam<bool> kOpenLinksInCurrentTab{ + &kSidePanelCompanion, "open-links-in-current-tab", true}; + } // namespace features namespace switches {
diff --git a/chrome/browser/companion/core/features.h b/chrome/browser/companion/core/features.h index 9badb60..974e795 100644 --- a/chrome/browser/companion/core/features.h +++ b/chrome/browser/companion/core/features.h
@@ -17,6 +17,7 @@ extern const base::FeatureParam<std::string> kImageUploadURLForCompanion; extern const base::FeatureParam<bool> kEnableOpenCompanionForImageSearch; extern const base::FeatureParam<bool> kEnableOpenCompanionForWebSearch; +extern const base::FeatureParam<bool> kOpenLinksInCurrentTab; } // namespace features
diff --git a/chrome/browser/download/download_item_model_unittest.cc b/chrome/browser/download/download_item_model_unittest.cc index 42a4a562..86be074 100644 --- a/chrome/browser/download/download_item_model_unittest.cc +++ b/chrome/browser/download/download_item_model_unittest.cc
@@ -537,7 +537,7 @@ EXPECT_CALL(item(), GetDangerType()) .WillRepeatedly(Return(download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE)); - EXPECT_EQ("2 B \xE2\x80\xA2 Done, no issues found", + EXPECT_EQ("2 B \xE2\x80\xA2 Scan is done", base::UTF16ToUTF8(model().GetStatusText())); #if BUILDFLAG(IS_MAC)
diff --git a/chrome/browser/enterprise/connectors/reporting/metrics_utils.cc b/chrome/browser/enterprise/connectors/reporting/metrics_utils.cc new file mode 100644 index 0000000..8637b136 --- /dev/null +++ b/chrome/browser/enterprise/connectors/reporting/metrics_utils.cc
@@ -0,0 +1,16 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/enterprise/connectors/reporting/metrics_utils.h" + +namespace enterprise_connectors { + +EnterpriseReportingEventType GetUmaEnumFromEventName( + const base::StringPiece& eventName) { + auto* it = kEventNameToUmaEnumMap.find(eventName); + return it != kEventNameToUmaEnumMap.end() + ? it->second + : EnterpriseReportingEventType::kUnknownEvent; +} +} // namespace enterprise_connectors
diff --git a/chrome/browser/enterprise/connectors/reporting/metrics_utils.h b/chrome/browser/enterprise/connectors/reporting/metrics_utils.h new file mode 100644 index 0000000..a18a712 --- /dev/null +++ b/chrome/browser/enterprise/connectors/reporting/metrics_utils.h
@@ -0,0 +1,65 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_ENTERPRISE_CONNECTORS_REPORTING_METRICS_UTILS_H_ +#define CHROME_BROWSER_ENTERPRISE_CONNECTORS_REPORTING_METRICS_UTILS_H_ + +#include "base/containers/fixed_flat_map.h" +#include "chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h" + +namespace enterprise_connectors { +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. Keep this enum in sync with +// EnterpriseReportingEventType in enums.xml. +enum class EnterpriseReportingEventType { + kUnknownEvent = 0, + kPasswordReuseEvent = 1, + kPasswordChangedEvent = 2, + kDangerousDownloadEvent = 3, + kInterstitialEvent = 4, + kSensitiveDataEvent = 5, + kUnscannedFileEvent = 6, + kLoginEvent = 7, + kPasswordBreachEvent = 8, + kUrlFilteringInterstitialEvent = 9, + kExtensionInstallEvent = 10, + kBrowserCrashEvent = 11, + kMaxValue = kBrowserCrashEvent, +}; + +// Mapping from event name to UMA enum for logging histogram. +constexpr auto kEventNameToUmaEnumMap = + base::MakeFixedFlatMap<base::StringPiece, EnterpriseReportingEventType>({ + {extensions::SafeBrowsingPrivateEventRouter::kKeyPasswordReuseEvent, + EnterpriseReportingEventType::kPasswordReuseEvent}, + {extensions::SafeBrowsingPrivateEventRouter::kKeyPasswordChangedEvent, + EnterpriseReportingEventType::kPasswordChangedEvent}, + {extensions::SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent, + EnterpriseReportingEventType::kDangerousDownloadEvent}, + {extensions::SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent, + EnterpriseReportingEventType::kInterstitialEvent}, + {extensions::SafeBrowsingPrivateEventRouter::kKeySensitiveDataEvent, + EnterpriseReportingEventType::kSensitiveDataEvent}, + {extensions::SafeBrowsingPrivateEventRouter::kKeyUnscannedFileEvent, + EnterpriseReportingEventType::kUnscannedFileEvent}, + {extensions::SafeBrowsingPrivateEventRouter::kKeyLoginEvent, + EnterpriseReportingEventType::kLoginEvent}, + {extensions::SafeBrowsingPrivateEventRouter::kKeyPasswordBreachEvent, + EnterpriseReportingEventType::kPasswordBreachEvent}, + {extensions::SafeBrowsingPrivateEventRouter:: + kKeyUrlFilteringInterstitialEvent, + EnterpriseReportingEventType::kUrlFilteringInterstitialEvent}, + {ReportingServiceSettings::kExtensionInstallEvent, + EnterpriseReportingEventType::kExtensionInstallEvent}, + {ReportingServiceSettings::kBrowserCrashEvent, + EnterpriseReportingEventType::kBrowserCrashEvent}, + }); + +// Return the UMA EnterpriseReportingEventType enum for the given event name. +EnterpriseReportingEventType GetUmaEnumFromEventName( + const base::StringPiece& eventName); + +} // namespace enterprise_connectors + +#endif // CHROME_BROWSER_ENTERPRISE_CONNECTORS_REPORTING_METRICS_UTILS_H_
diff --git a/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.cc b/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.cc index 7d097a52..44e4194 100644 --- a/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.cc +++ b/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.cc
@@ -9,6 +9,7 @@ #include "base/files/file_path.h" #include "base/functional/bind.h" +#include "base/metrics/histogram_functions.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "build/build_config.h" @@ -16,6 +17,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/enterprise/connectors/common.h" #include "chrome/browser/enterprise/connectors/connectors_service.h" +#include "chrome/browser/enterprise/connectors/reporting/metrics_utils.h" #include "chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h" #include "chrome/browser/enterprise/identifiers/profile_id_service_factory.h" #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h" @@ -385,6 +387,7 @@ auto upload_callback = base::BindOnce( [](base::Value::Dict wrapper, bool per_profile, std::string dm_token, + EnterpriseReportingEventType eventType, policy::CloudPolicyClient::Result upload_result) { // TODO(b/256553070): Do not crash if the client is unregistered. CHECK(!upload_result.IsClientNotRegisteredError()); @@ -395,8 +398,17 @@ std::move(dm_token)); safe_browsing::WebUIInfoSingleton::GetInstance()->AddToReportingEvents( std::move(wrapper)); + + if (upload_result.IsSuccess()) { + base::UmaHistogramEnumeration( + "Enterprise.ReportingEventUploadSuccess", eventType); + } else { + base::UmaHistogramEnumeration( + "Enterprise.ReportingEventUploadFailure", eventType); + } }, - wrapper.Clone(), settings.per_profile, client->dm_token()); + wrapper.Clone(), settings.per_profile, client->dm_token(), + GetUmaEnumFromEventName(name)); base::Value::List event_list; event_list.Append(std::move(wrapper));
diff --git a/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_unittest.cc b/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_unittest.cc index d7286b4..912cbb2e 100644 --- a/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_unittest.cc +++ b/chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_unittest.cc
@@ -8,11 +8,17 @@ #include <string> #include <utility> +#include "base/test/gmock_move_support.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" #include "build/branding_buildflags.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/enterprise/connectors/connectors_service.h" +#include "chrome/browser/enterprise/connectors/reporting/metrics_utils.h" +#include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client.h" +#include "chrome/browser/enterprise/connectors/reporting/realtime_reporting_client_factory.h" +#include "chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h" #include "chrome/browser/policy/dm_token_utils.h" #include "chrome/browser/profiles/profiles_state.h" #include "chrome/test/base/testing_browser_process.h" @@ -22,6 +28,7 @@ #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" #include "content/public/test/browser_task_environment.h" #include "extensions/browser/test_event_router.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #if !BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS_ASH) @@ -41,7 +48,7 @@ #include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h" #endif -using ::testing::Mock; +using testing::_; namespace enterprise_connectors { @@ -68,6 +75,15 @@ profile_ = profile_manager_.CreateTestingProfile("test-user"); policy::SetDMTokenForTesting( policy::DMToken::CreateValidToken("fake-token")); + + if (!client_) { + // Set a mock cloud policy client in the router. + client_ = std::make_unique<policy::MockCloudPolicyClient>(); + client_->SetDMToken("fake-token"); + } + + RealtimeReportingClientFactory::GetInstance()->SetTestingFactory( + profile_, base::BindRepeating(&BuildRealtimeReportingClient)); } protected: @@ -76,11 +92,6 @@ TestingProfileManager profile_manager_; raw_ptr<TestingProfile> profile_ = nullptr; raw_ptr<extensions::TestEventRouter> event_router_ = nullptr; - - private: -#if !BUILDFLAG(IS_CHROMEOS_ASH) - policy::FakeBrowserDMTokenStorage dm_token_storage_; -#endif // !BUILDFLAG(IS_CHROMEOS_ASH) }; // Tests to make sure the feature flag and policy control real-time reporting @@ -162,4 +173,76 @@ RealtimeReportingClientIsRealtimeReportingEnabledTest, testing::Combine(testing::Bool(), testing::Bool())); +class RealtimeReportingClientUmaTest : public RealtimeReportingClientTestBase { + public: + void SetUp() override { + RealtimeReportingClientTestBase::SetUp(); + reporting_client_ = + enterprise_connectors::RealtimeReportingClientFactory::GetForProfile( + profile_); + reporting_client_->SetBrowserCloudPolicyClientForTesting(client_.get()); + } + + protected: + base::HistogramTester histogram_; + raw_ptr<RealtimeReportingClient> reporting_client_ = nullptr; + policy::CloudPolicyClient::ResultCallback upload_callback; +}; + +TEST_F(RealtimeReportingClientUmaTest, TestUmaEventUploadSucceeds) { + ReportingSettings settings; + base::Value::Dict event; + + EXPECT_CALL(*client_.get(), UploadSecurityEventReport(_, _, _, _)) + .WillOnce(MoveArg<3>(&upload_callback)); + + reporting_client_->ReportRealtimeEvent( + ReportingServiceSettings::kExtensionInstallEvent, std::move(settings), + std::move(event)); + + std::move(upload_callback) + .Run(policy::CloudPolicyClient::Result(policy::DM_STATUS_SUCCESS)); + + histogram_.ExpectUniqueSample( + "Enterprise.ReportingEventUploadSuccess", + EnterpriseReportingEventType::kExtensionInstallEvent, 1); + histogram_.ExpectTotalCount("Enterprise.ReportingEventUploadFailure", 0); +} + +TEST_F(RealtimeReportingClientUmaTest, TestUmaEventUploadFails) { + ReportingSettings settings; + base::Value::Dict event; + + EXPECT_CALL(*client_.get(), UploadSecurityEventReport(_, _, _, _)) + .WillOnce(MoveArg<3>(&upload_callback)); + + reporting_client_->ReportRealtimeEvent( + ReportingServiceSettings::kExtensionInstallEvent, std::move(settings), + std::move(event)); + + std::move(upload_callback) + .Run(policy::CloudPolicyClient::Result(policy::DM_STATUS_REQUEST_FAILED)); + + histogram_.ExpectUniqueSample( + "Enterprise.ReportingEventUploadFailure", + EnterpriseReportingEventType::kExtensionInstallEvent, 1); + histogram_.ExpectTotalCount("Enterprise.ReportingEventUploadSuccess", 0); +} + +TEST_F(RealtimeReportingClientTestBase, + TestEventNameToUmaEnumMapIncludesAllEvents) { + EXPECT_EQ(sizeof(ReportingServiceSettings::kAllReportingEvents) / + sizeof(ReportingServiceSettings::kAllReportingEvents[0]), + kEventNameToUmaEnumMap.size()); + for (const char* eventName : ReportingServiceSettings::kAllReportingEvents) { + EXPECT_TRUE(kEventNameToUmaEnumMap.contains(eventName)); + } +} + +TEST_F(RealtimeReportingClientTestBase, + TestUnknownEventNameMapsTokUnknownEvent) { + EXPECT_EQ(GetUmaEnumFromEventName("non-existent-event-name"), + EnterpriseReportingEventType::kUnknownEvent); +} + } // namespace enterprise_connectors
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc index 62b8ce1..f58dfce 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
@@ -8,6 +8,7 @@ #include <utility> +#include "base/functional/bind.h" #include "base/metrics/user_metrics.h" #include "base/strings/utf_string_conversions.h" #include "base/uuid.h" @@ -17,6 +18,7 @@ #include "chrome/browser/extensions/api/autofill_private/autofill_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/api/autofill_private.h" +#include "components/autofill/content/browser/content_autofill_client.h" #include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/content/browser/content_autofill_driver_factory.h" #include "components/autofill/core/browser/autofill_address_util.h" @@ -30,6 +32,8 @@ #include "components/autofill/core/browser/payments/virtual_card_enrollment_manager.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/common/autofill_features.h" +#include "components/autofill/core/common/autofill_payments_features.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/signin/public/identity_manager/account_info.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/extension_function.h" @@ -47,6 +51,7 @@ static const char kSettingsOrigin[] = "Chrome settings"; static const char kErrorDataUnavailable[] = "Autofill data unavailable."; +static const char kErrorDeviceAuthUnavailable[] = "Device auth is unvailable"; // Constant to assign a user-verified verification status to the autofill // profile. @@ -838,4 +843,56 @@ return RespondNow(NoArguments()); } +//////////////////////////////////////////////////////////////////////////////// +// AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction + +ExtensionFunction::ResponseAction +AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction::Run() { +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + // If `client` is not available, then don't do anything. + autofill::ContentAutofillClient* client = + autofill::ContentAutofillClient::FromWebContents(GetSenderWebContents()); + if (!client) { + return RespondNow(Error(kErrorDeviceAuthUnavailable)); + } + + // If `device_authenticator` is not available, then don't do anything. + auto device_authenticator = client->GetDeviceAuthenticator(); + if (!device_authenticator) { + return RespondNow(Error(kErrorDeviceAuthUnavailable)); + } + + // We will be modifying the pref `kAutofillPaymentMethodsMandatoryReauth` + // asynchronously. The pref value directly correlates to the mandatory auth + // toggle. + autofill_util::AuthenticateUserOnMandatoryReauthToggled( + device_authenticator, + base::BindOnce( + &AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction:: + UpdateMandatoryAuthTogglePref, + this)); + base::RecordAction(base::UserMetricsAction( + "PaymentsUserAuthTriggeredForMandatoryAuthToggle")); + return RespondNow(NoArguments()); +#else + return RespondNow(Error(kErrorDeviceAuthUnavailable)); +#endif // BUILDFLAG (IS_MAC) || BUILDFLAG(IS_WIN) +} + +// Update the Mandatory auth toggle pref after a successful user auth. +void AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction:: + UpdateMandatoryAuthTogglePref(bool reauth_succeeded) { +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + if (reauth_succeeded && browser_context()) { + PrefService* prefs = + Profile::FromBrowserContext(browser_context())->GetPrefs(); + autofill::prefs::SetAutofillPaymentMethodsMandatoryReauth( + prefs, !prefs->GetBoolean( + autofill::prefs::kAutofillPaymentMethodsMandatoryReauth)); + base::RecordAction(base::UserMetricsAction( + "PaymentsUserAuthSuccessfulForMandatoryAuthToggle")); + } +#endif +} + } // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.h b/chrome/browser/extensions/api/autofill_private/autofill_private_api.h index 1ab817f2..c8a8761 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.h +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_API_H_ #define CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_API_H_ +#include "components/prefs/pref_service.h" #include "extensions/browser/extension_function.h" #include "extensions/browser/extension_function_histogram_value.h" @@ -336,6 +337,31 @@ ResponseAction Run() override; }; +class AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction + : public ExtensionFunction { + public: + AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction() = default; + AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction( + const AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction&) = + delete; + AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction& operator=( + const AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction&) = + delete; + DECLARE_EXTENSION_FUNCTION( + "autofillPrivate.authenticateUserAndFlipMandatoryAuthToggle", + AUTOFILLPRIVATE_AUTHENTICATEUSERANDFLIPMANDATORYAUTHTOGGLE) + + protected: + ~AutofillPrivateAuthenticateUserAndFlipMandatoryAuthToggleFunction() + override = default; + + // ExtensionFunction overrides. + ResponseAction Run() override; + + private: + void UpdateMandatoryAuthTogglePref(bool reauth_succeeded); +}; + } // namespace extensions #endif // CHROME_BROWSER_EXTENSIONS_API_AUTOFILL_PRIVATE_AUTOFILL_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc index 5d530012..a150b6a8 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc
@@ -9,8 +9,12 @@ #include "chrome/browser/autofill/autofill_uitest_util.h" #include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/browser/ui/autofill/chrome_autofill_client.h" #include "chrome/common/extensions/api/autofill_private.h" +#include "components/autofill/content/browser/test_autofill_client_injector.h" +#include "components/autofill/content/browser/test_content_autofill_client.h" #include "components/autofill/core/browser/personal_data_manager.h" +#include "components/device_reauth/mock_device_authenticator.h" #include "components/keyed_service/core/keyed_service.h" #include "content/public/test/browser_test.h" #include "content/public/test/test_utils.h" @@ -20,6 +24,27 @@ namespace { +class TestChromeAutofillClient : public autofill::ChromeAutofillClient { + public: + explicit TestChromeAutofillClient(content::WebContents* web_contents) + : ChromeAutofillClient(web_contents) {} + +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + scoped_refptr<device_reauth::DeviceAuthenticator> GetDeviceAuthenticator() + const override { + return mock_device_authenticator_; + } + + void SetDeviceAuthenticator( + scoped_refptr<device_reauth::MockDeviceAuthenticator> mock_auth) { + mock_device_authenticator_ = mock_auth; + } + + scoped_refptr<device_reauth::MockDeviceAuthenticator> + mock_device_authenticator_; +#endif +}; + class AutofillPrivateApiTest : public ExtensionApiTest { public: AutofillPrivateApiTest() = default; @@ -45,6 +70,15 @@ {.extension_url = extension_url.c_str()}, {.load_as_component = true}); } + + TestChromeAutofillClient* autofill_client() { + return test_autofill_client_injector_ + [browser()->tab_strip_model()->GetActiveWebContents()]; + } + + private: + autofill::TestAutofillClientInjector<TestChromeAutofillClient> + test_autofill_client_injector_; }; } // namespace @@ -126,4 +160,32 @@ EXPECT_TRUE(RunAutofillSubtest("isValidIban")) << message_; } +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) +IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, + authenticateUserAndFlipMandatoryAuthToggle) { + base::UserActionTester user_action_tester; + scoped_refptr<device_reauth::MockDeviceAuthenticator> + mock_device_authenticator = + base::MakeRefCounted<device_reauth::MockDeviceAuthenticator>(); + TestChromeAutofillClient* test_client = autofill_client(); + test_client->SetDeviceAuthenticator(mock_device_authenticator); + + ON_CALL(*mock_device_authenticator, AuthenticateWithMessage) + .WillByDefault( + testing::WithArg<1>([](base::OnceCallback<void(bool)> callback) { + std::move(callback).Run(true); + })); + + EXPECT_CALL(*mock_device_authenticator, + AuthenticateWithMessage(testing::_, testing::_)) + .Times(1); + EXPECT_TRUE(RunAutofillSubtest("authenticateUserAndFlipMandatoryAuthToggle")) + << message_; + EXPECT_EQ(1, user_action_tester.GetActionCount( + "PaymentsUserAuthTriggeredForMandatoryAuthToggle")); + EXPECT_EQ(1, user_action_tester.GetActionCount( + "PaymentsUserAuthSuccessfulForMandatoryAuthToggle")); +} +#endif + } // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc index bf1b6f5..565d594 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc +++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/api/autofill_private.h" #include "chrome/common/pref_names.h" +#include "chrome/grit/chromium_strings.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/data_model/autofill_profile.h" #include "components/autofill/core/browser/data_model/credit_card.h" @@ -25,6 +26,7 @@ #include "components/autofill/core/browser/geo/autofill_country.h" #include "components/autofill/core/browser/ui/country_combobox_model.h" #include "components/autofill/core/common/autofill_payments_features.h" +#include "components/autofill/core/common/autofill_prefs.h" #include "components/prefs/pref_service.h" #include "components/strings/grit/components_strings.h" #include "components/sync/base/user_selectable_type.h" @@ -347,4 +349,15 @@ return std::move(api_account); } +void AuthenticateUserOnMandatoryReauthToggled( + scoped_refptr<device_reauth::DeviceAuthenticator> device_authenticator, + CallbackAfterSuccessfulUserAuth callback) { +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + CHECK(device_authenticator); + const std::u16string& message = + l10n_util::GetStringUTF16(IDS_PAYMENTS_AUTOFILL_MANDATORY_REAUTH_PROMPT); + device_authenticator->AuthenticateWithMessage(message, std::move(callback)); +#endif +} + } // namespace extensions::autofill_util
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.h b/chrome/browser/extensions/api/autofill_private/autofill_util.h index 96e28689..ef527b59 100644 --- a/chrome/browser/extensions/api/autofill_private/autofill_util.h +++ b/chrome/browser/extensions/api/autofill_private/autofill_util.h
@@ -8,8 +8,10 @@ #include <map> #include <memory> +#include "base/functional/callback_forward.h" #include "chrome/common/extensions/api/autofill_private.h" #include "components/autofill/core/browser/personal_data_manager.h" +#include "components/device_reauth/device_authenticator.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace extensions { @@ -20,6 +22,7 @@ using CountryEntryList = std::vector<api::autofill_private::CountryEntry>; using CreditCardEntryList = std::vector<api::autofill_private::CreditCardEntry>; using IbanEntryList = std::vector<api::autofill_private::IbanEntry>; +using CallbackAfterSuccessfulUserAuth = base::OnceCallback<void(bool)>; // Uses |personal_data| to generate a list of up-to-date AddressEntry objects. AddressEntryList GenerateAddressList( @@ -43,6 +46,12 @@ absl::optional<api::autofill_private::AccountInfo> GetAccountInfo( const autofill::PersonalDataManager& personal_data); +// Use the available device authentication to auth the user and flip the +// mandatory auth pref value if successful. +void AuthenticateUserOnMandatoryReauthToggled( + scoped_refptr<device_reauth::DeviceAuthenticator> device_authenticator, + CallbackAfterSuccessfulUserAuth callback); + } // namespace autofill_util } // namespace extensions
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util_unittest.cc b/chrome/browser/extensions/api/autofill_private/autofill_util_unittest.cc new file mode 100644 index 0000000..a5dfe61 --- /dev/null +++ b/chrome/browser/extensions/api/autofill_private/autofill_util_unittest.cc
@@ -0,0 +1,73 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/autofill_private/autofill_util.h" + +#include <memory> + +#include "base/functional/callback_forward.h" +#include "base/test/mock_callback.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "components/device_reauth/mock_device_authenticator.h" +#include "content/public/test/browser_task_environment.h" +#include "content/public/test/browser_test.h" + +using testing::Return; + +namespace extensions::autofill_util { + +class AutofillUtilTest : public InProcessBrowserTest { + public: + AutofillUtilTest() = default; + + AutofillUtilTest(const AutofillUtilTest&) = delete; + AutofillUtilTest& operator=(const AutofillUtilTest&) = delete; + + void SetUpOnMainThread() override { + mock_device_authenticator_ = + base::MakeRefCounted<device_reauth::MockDeviceAuthenticator>(); + } + + protected: + scoped_refptr<device_reauth::MockDeviceAuthenticator> + mock_device_authenticator_; +}; + +IN_PROC_BROWSER_TEST_F( + AutofillUtilTest, + AuthenticateUserOnMandatoryReuathToggled_SuccessfulAuth) { +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + base::MockCallback<base::OnceCallback<void(bool)>> result_callback; + + ON_CALL(*mock_device_authenticator_, AuthenticateWithMessage) + .WillByDefault( + testing::WithArg<1>([](base::OnceCallback<void(bool)> callback) { + std::move(callback).Run(true); + })); + EXPECT_CALL(result_callback, Run(true)); + + AuthenticateUserOnMandatoryReauthToggled(mock_device_authenticator_, + result_callback.Get()); +#endif +} + +IN_PROC_BROWSER_TEST_F( + AutofillUtilTest, + AuthenticateUserOnMandatoryReuathToggled_UnSuccessfulAuth) { +#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) + base::MockCallback<base::OnceCallback<void(bool)>> result_callback; + + ON_CALL(*mock_device_authenticator_, AuthenticateWithMessage) + .WillByDefault( + testing::WithArg<1>([](base::OnceCallback<void(bool)> callback) { + std::move(callback).Run(false); + })); + EXPECT_CALL(result_callback, Run(false)); + + AuthenticateUserOnMandatoryReauthToggled(mock_device_authenticator_, + result_callback.Get()); +#endif +} + +} // namespace extensions::autofill_util
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc index 5c835376..3e172422 100644 --- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc +++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -544,7 +544,7 @@ const char* referrer_policy = use_frame_referrer ? "origin" : "no-referrer"; - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( GetPrimaryMainFrame(), base::StringPrintf(R"( document.getElementsByName('%s')[0].referrerPolicy = '%s';
diff --git a/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc b/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc index aae7ddf7..2325d388 100644 --- a/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc +++ b/chrome/browser/extensions/api/offscreen/offscreen_apitest.cc
@@ -27,6 +27,13 @@ #include "extensions/test/test_extension_dir.h" #include "testing/gmock/include/gmock/gmock.h" +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "base/test/gtest_tags.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/chrome_content_browser_client.h" +#include "content/public/common/content_client.h" +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + namespace extensions { namespace { @@ -95,6 +102,16 @@ run_loop.Run(); } +#if BUILDFLAG(IS_CHROMEOS_ASH) +class ContentBrowserClientMock : public ChromeContentBrowserClient { + public: + MOCK_METHOD(bool, + IsGetAllScreensMediaAllowed, + (content::BrowserContext * context, const url::Origin& origin), + (override)); +}; +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + } // namespace class OffscreenApiTest : public ExtensionApiTest { @@ -414,6 +431,152 @@ EXPECT_FALSE(manager->GetOffscreenDocumentForExtension(*extension)); } +#if BUILDFLAG(IS_CHROMEOS_ASH) +class GetAllScreensMediaOffscreenApiTest : public OffscreenApiTest { + public: + GetAllScreensMediaOffscreenApiTest() = default; + ~GetAllScreensMediaOffscreenApiTest() override = default; + + void SetUpOnMainThread() override { + OffscreenApiTest::SetUpOnMainThread(); + browser_client_ = std::make_unique<ContentBrowserClientMock>(); + content::SetBrowserClientForTesting(browser_client_.get()); + } + + void SetUpCommandLine(base::CommandLine* command_line) override { + OffscreenApiTest::SetUpCommandLine(command_line); + scoped_feature_list_.InitFromCommandLine( + /*enable_features=*/ + "GetAllScreensMedia", + /*disable_features=*/""); + } + + protected: + ContentBrowserClientMock& content_browser_client() { + return *browser_client_; + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; + std::unique_ptr<ContentBrowserClientMock> browser_client_; +}; + +// This test checks if the `getAllScreensMedia` API is available and fully +// functional in offscreen documents on ChromeOS ash. +IN_PROC_BROWSER_TEST_F(GetAllScreensMediaOffscreenApiTest, + GetAllScreensMediaAllowed) { + // This test corresponds to a critical user journey (CUJ) + // (go/cros-cuj-tracker) for ChromeOS commercial. + // This tag links the test to a CUJ and allows close tracking whether a user + // journey is fully functional. + base::AddTagToTestResult("feature_id", + "screenplay-f3601ae4-bff7-495a-a51f-3c0997a46445"); + EXPECT_CALL(content_browser_client(), + IsGetAllScreensMediaAllowed(testing::_, testing::_)) + .WillOnce(testing::Return(true)); + + static constexpr char kManifest[] = + R"({ + "name": "Offscreen Document Test", + "manifest_version": 3, + "version": "0.1", + "background": {"service_worker": "background.js"}, + "permissions": ["offscreen"] + })"; + // An offscreen document that knows how to capture all screens. + static constexpr char kOffscreenJs[] = + R"( + let streams; + + async function captureAllScreens() { + try { + streams = await navigator.mediaDevices.getAllScreensMedia(); + if (streams === null || streams.length == 0) { + return false; + } + + let allStreamsOk = true; + streams.forEach((stream) => { + const videoTracks = stream.getVideoTracks(); + if (videoTracks.length == 0) { + allStreamsOk = false; + return; + } + + const videoTrack = videoTracks[0]; + if (typeof videoTrack.screenDetailed !== "function") { + allStreamsOk = false; + return; + } + }); + + chrome.test.sendScriptResult(allStreamsOk); + return; + } catch(e) { + console.error('Unexcpected exception: ' + e); + chrome.test.sendScriptResult(false); + } + } + + function stopCapture() { + streams.forEach((stream) => { + stream.getVideoTracks()[0].stop(); + }); + } + + chrome.runtime.onMessage.addListener(async (msg) => { + if (msg == 'capture') { + await captureAllScreens(); + } else if (msg == 'stop') { + stopCapture(); + } else { + console.error('Unexpected message: ' + msg); + } + }))"; + TestExtensionDir test_dir; + test_dir.WriteManifest(kManifest); + test_dir.WriteFile(FILE_PATH_LITERAL("background.js"), "// Blank."); + test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.html"), + R"(<html><script src="offscreen.js"></script></html>)"); + test_dir.WriteFile(FILE_PATH_LITERAL("offscreen.js"), kOffscreenJs); + + scoped_refptr<const Extension> extension = + LoadExtension(test_dir.UnpackedPath()); + ASSERT_TRUE(extension); + + // Create a new offscreen document for audio playback and wait for it to load. + OffscreenDocumentManager* manager = OffscreenDocumentManager::Get(profile()); + ProgrammaticallyCreateOffscreenDocument(*extension, *profile(), + "DISPLAY_MEDIA"); + OffscreenDocumentHost* document = + manager->GetOffscreenDocumentForExtension(*extension); + ASSERT_TRUE(document); + content::WaitForLoadStop(document->host_contents()); + + // Begin the screen capture. + { + base::Value result = BackgroundScriptExecutor::ExecuteScript( + profile(), extension->id(), "chrome.runtime.sendMessage('capture');", + BackgroundScriptExecutor::ResultCapture::kSendScriptResult); + ASSERT_TRUE(result.is_bool()); + EXPECT_TRUE(result.GetBool()); + } + + // The document should be kept alive. + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(manager->GetOffscreenDocumentForExtension(*extension)); + + // Now, stop the capture. + { + BackgroundScriptExecutor::ExecuteScriptAsync( + profile(), extension->id(), "chrome.runtime.sendMessage('stop');"); + } + + // TODO(crbug.com/1443432): Add check if document gets shut down after the + // screen capture with `getAllScreensMedia` is stopped. +} +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + class OffscreenApiTestWithoutCommandLineFlag : public OffscreenApiTest { public: OffscreenApiTestWithoutCommandLineFlag() = default;
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc index c161ca3..67062a80 100644 --- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc +++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.cc
@@ -265,27 +265,6 @@ const char SafeBrowsingPrivateEventRouter::kKeyUrlCategory[] = "urlCategory"; const char SafeBrowsingPrivateEventRouter::kKeyAction[] = "action"; -// All new event names should be added to the array -// `enterprise_connectors::ReportingServiceSettings::kAllReportingEvents` in -// `chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h` -const char SafeBrowsingPrivateEventRouter::kKeyUrlFilteringInterstitialEvent[] = - "urlFilteringInterstitialEvent"; -const char SafeBrowsingPrivateEventRouter::kKeyPasswordReuseEvent[] = - "passwordReuseEvent"; -const char SafeBrowsingPrivateEventRouter::kKeyPasswordChangedEvent[] = - "passwordChangedEvent"; -const char SafeBrowsingPrivateEventRouter::kKeyDangerousDownloadEvent[] = - "dangerousDownloadEvent"; -const char SafeBrowsingPrivateEventRouter::kKeyInterstitialEvent[] = - "interstitialEvent"; -const char SafeBrowsingPrivateEventRouter::kKeySensitiveDataEvent[] = - "sensitiveDataEvent"; -const char SafeBrowsingPrivateEventRouter::kKeyUnscannedFileEvent[] = - "unscannedFileEvent"; -const char SafeBrowsingPrivateEventRouter::kKeyLoginEvent[] = "loginEvent"; -const char SafeBrowsingPrivateEventRouter::kKeyPasswordBreachEvent[] = - "passwordBreachEvent"; - const char SafeBrowsingPrivateEventRouter::kKeyUnscannedReason[] = "unscannedReason";
diff --git a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h index 64540f3..bb68898 100644 --- a/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h +++ b/chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h
@@ -83,15 +83,19 @@ static const char kKeyUrlCategory[]; static const char kKeyAction[]; - static const char kKeyUrlFilteringInterstitialEvent[]; - static const char kKeyPasswordReuseEvent[]; - static const char kKeyPasswordChangedEvent[]; - static const char kKeyDangerousDownloadEvent[]; - static const char kKeyInterstitialEvent[]; - static const char kKeySensitiveDataEvent[]; - static const char kKeyUnscannedFileEvent[]; - static const char kKeyLoginEvent[]; - static const char kKeyPasswordBreachEvent[]; + // All new event names should be added to the array + // `enterprise_connectors::ReportingServiceSettings::kAllReportingEvents` in + // chrome/browser/enterprise/connectors/reporting/reporting_service_settings.h + static constexpr char kKeyUrlFilteringInterstitialEvent[] = + "urlFilteringInterstitialEvent"; + static constexpr char kKeyPasswordReuseEvent[] = "passwordReuseEvent"; + static constexpr char kKeyPasswordChangedEvent[] = "passwordChangedEvent"; + static constexpr char kKeyDangerousDownloadEvent[] = "dangerousDownloadEvent"; + static constexpr char kKeyInterstitialEvent[] = "interstitialEvent"; + static constexpr char kKeySensitiveDataEvent[] = "sensitiveDataEvent"; + static constexpr char kKeyUnscannedFileEvent[] = "unscannedFileEvent"; + static constexpr char kKeyLoginEvent[] = "loginEvent"; + static constexpr char kKeyPasswordBreachEvent[] = "passwordBreachEvent"; static const char kKeyUnscannedReason[];
diff --git a/chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.cc b/chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.cc index 4e8c743..a005800 100644 --- a/chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.cc +++ b/chrome/browser/extensions/api/web_authentication_proxy/web_authentication_proxy_service.cc
@@ -226,7 +226,12 @@ // as Guest. So while we do return a `WebAuthenticationProxyRegistrar` // for those profile types `IsActive()` will always return false // there. - ProfileSelections::BuildRedirectedToOriginal()) { + ProfileSelections::Builder() + .WithRegular(ProfileSelection::kRedirectedToOriginal) + // TODO(crbug.com/1418376): Check if this service is needed in + // Guest mode. + .WithGuest(ProfileSelection::kRedirectedToOriginal) + .Build()) { DependsOn(ExtensionRegistryFactory::GetInstance()); }
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewTest.java index 5eba9b88..8448df92 100644 --- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewTest.java +++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sections/SectionHeaderViewTest.java
@@ -69,7 +69,6 @@ private void setFeatureOverridesForIPH() { FeatureList.TestValues testValues = new FeatureList.TestValues(); - testValues.addFeatureFlagOverride(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); testValues.addFeatureFlagOverride(ChromeFeatureList.WEB_FEED, true); testValues.addFeatureFlagOverride(ChromeFeatureList.WEB_FEED_ONBOARDING, true); testValues.addFieldTrialParamOverride(
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java index a52d173bb..355035d2 100644 --- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java +++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroControllerTest.java
@@ -227,8 +227,6 @@ public void meetsShowingRequirements_showsIntro_IPH() { mBaseTestValues.addFieldTrialParamOverride( ChromeFeatureList.WEB_FEED, "intro_style", "IPH"); - mBaseTestValues.addFeatureFlagOverride( - ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); FeatureList.setTestValues(mBaseTestValues); resetWebFeedFollowIntroController(); @@ -256,8 +254,6 @@ public void sameWebFeedIsNotShownMoreThan3Times() { mBaseTestValues.addFieldTrialParamOverride( ChromeFeatureList.WEB_FEED, "intro_style", "IPH"); - mBaseTestValues.addFeatureFlagOverride( - ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); FeatureList.setTestValues(mBaseTestValues); resetWebFeedFollowIntroController();
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroViewTest.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroViewTest.java index 770aaaf..0735d3da 100644 --- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroViewTest.java +++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/webfeed/WebFeedFollowIntroViewTest.java
@@ -27,7 +27,6 @@ import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.JniMocker; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.user_education.UserEducationHelper; import org.chromium.components.feature_engagement.Tracker; @@ -87,8 +86,6 @@ @SmallTest public void showIPHTest() { FeatureList.TestValues baseTestValues = new FeatureList.TestValues(); - baseTestValues.addFeatureFlagOverride( - ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS, false); FeatureList.setTestValues(baseTestValues); mWebFeedFollowIntroView.showIPH(mHelper, () -> {}, () -> {});
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index 5ce90605..151322c 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -1108,6 +1108,11 @@ "expiry_milestone": 120 }, { + "name": "cloud-ap-auth-attach-as-header", + "owners": [ "igorruvinov", "zmin" ], + "expiry_milestone": 120 + }, + { "name": "cmd-decoder-always-get-size-from-source-texture", "owners": [ "blundell" ], "expiry_milestone": 128 @@ -2738,7 +2743,7 @@ { "name": "enable-lens-context-menu-alt-text", "owners": [ "apalanki", "schechter", "hujasonx" ], - "expiry_milestone": 114 + "expiry_milestone": 116 }, { "name": "enable-lens-image-format-optimizations", @@ -5995,6 +6000,11 @@ "expiry_milestone": 120 }, { + "name": "password-generation-experiment", + "owners": ["rgod@google.com", "chrome-password-manager-team@google.com"], + "expiry_milestone": 117 + }, + { "name": "password-manager-redesign", "owners": ["vsemeniuk@google.com", "vasilii", "chrome-password-manager-team@google.com"], "expiry_milestone": 117 @@ -7494,11 +7504,6 @@ "expiry_milestone": 120 }, { - "name": "video-tutorials", - "owners": [ "shaktisahu"], - "expiry_milestone": 102 - }, - { "name": "view-transition", "owners": [ "khushalsagar", "vmpstr", "chrishtr" ], "expiry_milestone" : 118
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index b82e6096c..8653876 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2600,6 +2600,12 @@ const char kParallelDownloadingDescription[] = "Enable parallel downloading to accelerate download speed."; +const char kPasswordGenerationExperimentName[] = + "Password generation experiment"; +const char kPasswordGenerationExperimentDescription[] = + "Enables different experiments that modify content and behavior of the " + "existing generated password suggestion dropdown."; + const char kPasswordsImportM2Name[] = "Passwords Import M2"; const char kPasswordsImportM2Description[] = "Extends passwords import flow in password settings with conflict " @@ -4734,6 +4740,13 @@ "the CloudAP framework. Credentials are retrieved from accounts signed " "into the operating system."; +const char kCloudApAuthAttachAsHeaderName[] = + "CloudAP authentication data headers"; +const char kCloudApAuthAttachAsHeaderDescription[] = + "Allows certain ambient authentication data to be added to HTTP requests " + "as separate headers instead of being appended to the cookie " + "header."; + const char kEnableMediaFoundationVideoCaptureName[] = "MediaFoundation Video Capture"; const char kEnableMediaFoundationVideoCaptureDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index eb9cf6d7..82071b2a 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1460,6 +1460,9 @@ extern const char kParallelDownloadingName[]; extern const char kParallelDownloadingDescription[]; +extern const char kPasswordGenerationExperimentName[]; +extern const char kPasswordGenerationExperimentDescription[]; + extern const char kPasswordsImportM2Name[]; extern const char kPasswordsImportM2Description[]; @@ -2721,6 +2724,9 @@ extern const char kCloudApAuthName[]; extern const char kCloudApAuthDescription[]; +extern const char kCloudApAuthAttachAsHeaderName[]; +extern const char kCloudApAuthAttachAsHeaderDescription[]; + extern const char kEnableMediaFoundationVideoCaptureName[]; extern const char kEnableMediaFoundationVideoCaptureDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 47e6af9..821d5ab 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -8,6 +8,7 @@ #include <string> +#include "base/android/feature_map.h" #include "base/android/jni_array.h" #include "base/android/jni_string.h" #include "base/containers/flat_map.h" @@ -26,7 +27,6 @@ #include "chrome/browser/signin/signin_features.h" #include "chrome/browser/thumbnail/cc/features.h" #include "chrome/browser/ui/ui_features.h" -#include "chrome/browser/video_tutorials/switches.h" #include "chrome/common/chrome_features.h" #include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_payments_features.h" @@ -170,7 +170,6 @@ &kAddToHomescreenIPH, &kAllowNewIncognitoTabIntents, &kAndroidAppIntegration, - &kAndroidScrollOptimizations, &kAndroidSearchEngineChoiceNotification, &kAndroidWidgetFullscreenToast, &kAndroidImprovedBookmarks, @@ -402,7 +401,6 @@ &syncer::kSyncAndroidLimitNTPPromoImpressions, &subresource_filter::kSafeBrowsingSubresourceFilter, &thumbnail::kThumbnailCacheRefactor, - &video_tutorials::features::kVideoTutorials, &webapps::features::kInstallableAmbientBadgeInfoBar, &webapps::features::kInstallableAmbientBadgeMessage, &webapps::features::kWebApkInstallFailureNotification, @@ -411,23 +409,11 @@ &network::features::kPrivateStateTokens, }; -const base::Feature* FindFeatureExposedToJava(const std::string& feature_name) { - static auto kFeaturesExposedToJavaMap = base::NoDestructor( - base::MakeFlatMap<base::StringPiece, const base::Feature*>( - kFeaturesExposedToJava, {}, - [](const base::Feature* a) - -> std::pair<base::StringPiece, const base::Feature*> { - return std::make_pair(a->name, a); - })); - - auto it = kFeaturesExposedToJavaMap->find(base::StringPiece(feature_name)); - if (it != kFeaturesExposedToJavaMap->end()) { - return it->second; - } - - NOTREACHED() << "Queried feature cannot be found in ChromeFeatureList: " - << feature_name; - return nullptr; +// static +base::android::FeatureMap* GetFeatureMap() { + static base::NoDestructor<base::android::FeatureMap> kFeatureMap(std::vector( + std::begin(kFeaturesExposedToJava), std::end(kFeaturesExposedToJava))); + return kFeatureMap.get(); } } // namespace @@ -470,10 +456,6 @@ "AndroidAppIntegration", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kAndroidScrollOptimizations, - "AndroidScrollOptimizations", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kAndroidSearchEngineChoiceNotification, "AndroidSearchEngineChoiceNotification", base::FEATURE_ENABLED_BY_DEFAULT); @@ -1159,8 +1141,8 @@ static jboolean JNI_ChromeFeatureList_IsEnabled( JNIEnv* env, const JavaParamRef<jstring>& jfeature_name) { - const base::Feature* feature = - FindFeatureExposedToJava(ConvertJavaStringToUTF8(env, jfeature_name)); + const base::Feature* feature = GetFeatureMap()->FindFeatureExposedToJava( + base::StringPiece(ConvertJavaStringToUTF8(env, jfeature_name))); return base::FeatureList::IsEnabled(*feature); } @@ -1169,8 +1151,8 @@ JNIEnv* env, const JavaParamRef<jstring>& jfeature_name, const JavaParamRef<jstring>& jparam_name) { - const base::Feature* feature = - FindFeatureExposedToJava(ConvertJavaStringToUTF8(env, jfeature_name)); + const base::Feature* feature = GetFeatureMap()->FindFeatureExposedToJava( + base::StringPiece(ConvertJavaStringToUTF8(env, jfeature_name))); const std::string& param_name = ConvertJavaStringToUTF8(env, jparam_name); const std::string& param_value = base::GetFieldTrialParamValueByFeature(*feature, param_name); @@ -1182,8 +1164,8 @@ const JavaParamRef<jstring>& jfeature_name, const JavaParamRef<jstring>& jparam_name, const jint jdefault_value) { - const base::Feature* feature = - FindFeatureExposedToJava(ConvertJavaStringToUTF8(env, jfeature_name)); + const base::Feature* feature = GetFeatureMap()->FindFeatureExposedToJava( + base::StringPiece(ConvertJavaStringToUTF8(env, jfeature_name))); const std::string& param_name = ConvertJavaStringToUTF8(env, jparam_name); return base::GetFieldTrialParamByFeatureAsInt(*feature, param_name, jdefault_value); @@ -1194,8 +1176,8 @@ const JavaParamRef<jstring>& jfeature_name, const JavaParamRef<jstring>& jparam_name, const jdouble jdefault_value) { - const base::Feature* feature = - FindFeatureExposedToJava(ConvertJavaStringToUTF8(env, jfeature_name)); + const base::Feature* feature = GetFeatureMap()->FindFeatureExposedToJava( + base::StringPiece(ConvertJavaStringToUTF8(env, jfeature_name))); const std::string& param_name = ConvertJavaStringToUTF8(env, jparam_name); return base::GetFieldTrialParamByFeatureAsDouble(*feature, param_name, jdefault_value); @@ -1206,8 +1188,8 @@ const JavaParamRef<jstring>& jfeature_name, const JavaParamRef<jstring>& jparam_name, const jboolean jdefault_value) { - const base::Feature* feature = - FindFeatureExposedToJava(ConvertJavaStringToUTF8(env, jfeature_name)); + const base::Feature* feature = GetFeatureMap()->FindFeatureExposedToJava( + base::StringPiece(ConvertJavaStringToUTF8(env, jfeature_name))); const std::string& param_name = ConvertJavaStringToUTF8(env, jparam_name); return base::GetFieldTrialParamByFeatureAsBool(*feature, param_name, jdefault_value); @@ -1216,11 +1198,11 @@ static ScopedJavaLocalRef<jobjectArray> JNI_ChromeFeatureList_GetFlattedFieldTrialParamsForFeature( JNIEnv* env, - const JavaParamRef<jstring>& feature_name) { + const JavaParamRef<jstring>& jfeature_name) { base::FieldTrialParams params; std::vector<std::string> keys_and_values; - const base::Feature* feature = - FindFeatureExposedToJava(ConvertJavaStringToUTF8(env, feature_name)); + const base::Feature* feature = GetFeatureMap()->FindFeatureExposedToJava( + base::StringPiece(ConvertJavaStringToUTF8(env, jfeature_name))); if (feature && base::GetFieldTrialParamsByFeature(*feature, ¶ms)) { for (const auto& param_pair : params) { keys_and_values.push_back(param_pair.first);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index 223c336..4b13355 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -21,7 +21,6 @@ BASE_DECLARE_FEATURE(kAddToHomescreenIPH); BASE_DECLARE_FEATURE(kAllowNewIncognitoTabIntents); BASE_DECLARE_FEATURE(kAndroidAppIntegration); -BASE_DECLARE_FEATURE(kAndroidScrollOptimizations); BASE_DECLARE_FEATURE(kAndroidWidgetFullscreenToast); BASE_DECLARE_FEATURE(kAndroidSearchEngineChoiceNotification); BASE_DECLARE_FEATURE(kAndroidImprovedBookmarks);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index d82ec23..dbe6fb13 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -172,7 +172,6 @@ public static final String ADD_TO_HOMESCREEN_IPH = "AddToHomescreenIPH"; public static final String ALLOW_NEW_INCOGNITO_TAB_INTENTS = "AllowNewIncognitoTabIntents"; public static final String ANDROID_APP_INTEGRATION = "AndroidAppIntegration"; - public static final String ANDROID_SCROLL_OPTIMIZATIONS = "AndroidScrollOptimizations"; public static final String ANDROID_SEARCH_ENGINE_CHOICE_NOTIFICATION = "AndroidSearchEngineChoiceNotification"; public static final String ANDROID_IMPROVED_BOOKMARKS = "AndroidImprovedBookmarks"; @@ -518,7 +517,6 @@ public static final String USE_CHIME_ANDROID_SDK = "UseChimeAndroidSdk"; public static final String USE_LIBUNWINDSTACK_NATIVE_UNWINDER_ANDROID = "UseLibunwindstackNativeUnwinderAndroid"; - public static final String VIDEO_TUTORIALS = "VideoTutorials"; public static final String VOICE_BUTTON_IN_TOP_TOOLBAR = "VoiceButtonInTopToolbar"; public static final String VOICE_SEARCH_AUDIO_CAPTURE_POLICY = "VoiceSearchAudioCapturePolicy"; public static final String WEBNOTES_STYLIZE = "WebNotesStylize";
diff --git a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc index 1ded55d..e911abc 100644 --- a/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc +++ b/chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_browsertest.cc
@@ -376,9 +376,9 @@ // handle the "beforeunload" dialog. content::PrepContentsForBeforeUnloadTest( browser()->tab_strip_model()->GetWebContentsAt(0)); - ASSERT_TRUE(content::ExecuteScript(main_frame, - "object.data = './testEmbedded.csv';" - "object.type = 'text/csv';")); + ASSERT_TRUE(content::ExecJs(main_frame, + "object.data = './testEmbedded.csv';" + "object.type = 'text/csv';")); javascript_dialogs::AppModalDialogController* alert = ui_test_utils::WaitForAppModalDialog(); ASSERT_TRUE(alert->is_before_unload_dialog()); @@ -705,10 +705,10 @@ // Verify that print dialog comes up. auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); auto* main_frame = web_contents->GetPrimaryMainFrame(); - // Use setTimeout() to prevent ExecuteScript() from blocking on the print + // Use setTimeout() to prevent ExecJs() from blocking on the print // dialog. - ASSERT_TRUE(content::ExecuteScript( - main_frame, "setTimeout(function() { window.print(); }, 0)")); + ASSERT_TRUE(content::ExecJs(main_frame, + "setTimeout(function() { window.print(); }, 0)")); print_preview_delegate.WaitUntilPreviewIsReady(); } #endif
diff --git a/chrome/browser/history/history_browsertest.cc b/chrome/browser/history/history_browsertest.cc index b5d6bf6..9669bb1 100644 --- a/chrome/browser/history/history_browsertest.cc +++ b/chrome/browser/history/history_browsertest.cc
@@ -570,7 +570,7 @@ // history. std::string script = "location.replace('form.html')"; content::TestFrameNavigationObserver observer(frame); - EXPECT_TRUE(ExecuteScript(frame, script)); + EXPECT_TRUE(ExecJs(frame, script)); observer.Wait(); GURL auto_subframe = ui_test_utils::GetTestUrl(base::FilePath().AppendASCII("History"), @@ -696,8 +696,8 @@ std::u16string title = web_contents->GetTitle(); // Do a pushState to create a new navigation entry and a new history entry. - ASSERT_TRUE(content::ExecuteScript(web_contents, - "history.pushState({},'','test.html')")); + ASSERT_TRUE( + content::ExecJs(web_contents, "history.pushState({},'','test.html')")); EXPECT_TRUE(content::WaitForLoadStop(web_contents)); // This should result in two history entries. @@ -726,10 +726,10 @@ // Create a beforeunload handler that does a replaceState during navigation, // unrelated to the destination URL (similar to Twitter). - ASSERT_TRUE(content::ExecuteScript(web_contents, - "window.onbeforeunload = function() {" - "history.replaceState({},'','test.html');" - "};")); + ASSERT_TRUE(content::ExecJs(web_contents, + "window.onbeforeunload = function() {" + "history.replaceState({},'','test.html');" + "};")); GURL url2(embedded_test_server()->GetURL("foo.com", "/test.html")); // Start a cross-site navigation to trigger the beforeunload, but don't let @@ -788,8 +788,8 @@ std::u16string expected_title(u"Target Page"); content::TitleWatcher title_watcher( browser()->tab_strip_model()->GetActiveWebContents(), expected_title); - ASSERT_TRUE(content::ExecuteScript( - web_contents, "document.getElementById('form').submit()")); + ASSERT_TRUE(content::ExecJs(web_contents, + "document.getElementById('form').submit()")); EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle()); std::vector<GURL> urls(GetHistoryContents()); @@ -842,8 +842,8 @@ browser()->tab_strip_model()->GetActiveWebContents(); // Do a replaceState() to create a new navigation entry. - ASSERT_TRUE(content::ExecuteScript(web_contents, - "history.replaceState({foo: 'bar'},'')")); + ASSERT_TRUE( + content::ExecJs(web_contents, "history.replaceState({foo: 'bar'},'')")); content::WaitForLoadStop(web_contents); // Because there was no user gesture and the url did not change, there should
diff --git a/chrome/browser/iframe_browsertest.cc b/chrome/browser/iframe_browsertest.cc index 847a087..c8699cc 100644 --- a/chrome/browser/iframe_browsertest.cc +++ b/chrome/browser/iframe_browsertest.cc
@@ -72,11 +72,10 @@ EXPECT_TRUE(frame); EXPECT_EQ(frame->GetSiteInstance(), tab->GetPrimaryMainFrame()->GetSiteInstance()); - EXPECT_TRUE( - ExecuteScript(frame, "document.getElementById('fileinput').click();")); - EXPECT_TRUE(ExecuteScript(tab->GetPrimaryMainFrame(), - "document.body.removeChild(" - "document.querySelectorAll('iframe')[0])")); + EXPECT_TRUE(ExecJs(frame, "document.getElementById('fileinput').click();")); + EXPECT_TRUE(ExecJs(tab->GetPrimaryMainFrame(), + "document.body.removeChild(" + "document.querySelectorAll('iframe')[0])")); ASSERT_EQ(nullptr, ChildFrameAt(tab->GetPrimaryMainFrame(), 0)); // On ASan bots, this test should succeed without reporting use-after-free
diff --git a/chrome/browser/loadtimes_extension_bindings_browsertest.cc b/chrome/browser/loadtimes_extension_bindings_browsertest.cc index b515283..2345a1ec 100644 --- a/chrome/browser/loadtimes_extension_bindings_browsertest.cc +++ b/chrome/browser/loadtimes_extension_bindings_browsertest.cc
@@ -21,12 +21,11 @@ // zero it out so the test is stable. content::WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); - ASSERT_TRUE(content::ExecuteScript( - contents, - "window.before.firstPaintAfterLoadTime = 0;" - "window.before.firstPaintTime = 0;" - "window.after.firstPaintAfterLoadTime = 0;" - "window.after.firstPaintTime = 0;")); + ASSERT_TRUE(content::ExecJs(contents, + "window.before.firstPaintAfterLoadTime = 0;" + "window.before.firstPaintTime = 0;" + "window.after.firstPaintAfterLoadTime = 0;" + "window.after.firstPaintTime = 0;")); std::string before = content::EvalJs(contents, "JSON.stringify(before)").ExtractString(); @@ -43,12 +42,12 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), plain_url)); content::WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); - ASSERT_TRUE(content::ExecuteScript( - contents, "window.before = window.chrome.loadTimes()")); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE( + content::ExecJs(contents, "window.before = window.chrome.loadTimes()")); + ASSERT_TRUE(content::ExecJs( contents, "window.location.href = window.location + \"#\"")); - ASSERT_TRUE(content::ExecuteScript( - contents, "window.after = window.chrome.loadTimes()")); + ASSERT_TRUE( + content::ExecJs(contents, "window.after = window.chrome.loadTimes()")); CompareBeforeAndAfter(); } @@ -60,10 +59,10 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), plain_url)); content::WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); - ASSERT_TRUE(content::ExecuteScript( - contents, "window.before = window.chrome.loadTimes()")); + ASSERT_TRUE( + content::ExecJs(contents, "window.before = window.chrome.loadTimes()")); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), hash_url)); - ASSERT_TRUE(content::ExecuteScript( - contents, "window.after = window.chrome.loadTimes()")); + ASSERT_TRUE( + content::ExecJs(contents, "window.after = window.chrome.loadTimes()")); CompareBeforeAndAfter(); }
diff --git a/chrome/browser/login_detection/login_detection_browsertest.cc b/chrome/browser/login_detection/login_detection_browsertest.cc index bcfae3c..574e81c8 100644 --- a/chrome/browser/login_detection/login_detection_browsertest.cc +++ b/chrome/browser/login_detection/login_detection_browsertest.cc
@@ -76,7 +76,7 @@ // Create a popup for the navigation flow. content::WebContentsAddedObserver web_contents_added_observer; - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( browser()->tab_strip_model()->GetActiveWebContents(), content::JsReplace( "window.open($1, 'oauth_window', 'width=10,height=10');",
diff --git a/chrome/browser/media/defer_background_media_browsertest.cc b/chrome/browser/media/defer_background_media_browsertest.cc index f67d46a..b07804a 100644 --- a/chrome/browser/media/defer_background_media_browsertest.cc +++ b/chrome/browser/media/defer_background_media_browsertest.cc
@@ -36,14 +36,14 @@ // be attached too late to catch the event, and subsequently the test will hit // the ended event before the play event. EXPECT_TRUE( - content::ExecuteScript(background_contents, - "var video = document.querySelector('video');" - "video.addEventListener('ended', function(event) {" - " document.title = 'ended';" - "}, false);" - "video.addEventListener('play', function(event) {" - " document.title = 'playing';" - "}, false);")); + content::ExecJs(background_contents, + "var video = document.querySelector('video');" + "video.addEventListener('ended', function(event) {" + " document.title = 'ended';" + "}, false);" + "video.addEventListener('play', function(event) {" + " document.title = 'playing';" + "}, false);")); // Make the background tab w/ our video the active tab. browser()->tab_strip_model()->SelectNextTab();
diff --git a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc index 28bdf3b..b14dd26 100644 --- a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc +++ b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
@@ -329,7 +329,7 @@ content::TitleWatcher title_watcher(contents, kSuccessResult16); title_watcher.AlsoWaitForTitle(kUnsupportedResult16); title_watcher.AlsoWaitForTitle(kUnexpectedResult16); - EXPECT_TRUE(content::ExecuteScript(contents, command)); + EXPECT_TRUE(content::ExecJs(contents, command)); std::u16string result = title_watcher.WaitAndGetTitle(); return base::UTF16ToASCII(result); }
diff --git a/chrome/browser/media/media_engagement_browsertest.cc b/chrome/browser/media/media_engagement_browsertest.cc index 66f7eb2..ae897a8 100644 --- a/chrome/browser/media/media_engagement_browsertest.cc +++ b/chrome/browser/media/media_engagement_browsertest.cc
@@ -232,7 +232,7 @@ } void ExecuteScript(const std::string& script) { - EXPECT_TRUE(content::ExecuteScript(GetWebContents(), script)); + EXPECT_TRUE(content::ExecJs(GetWebContents(), script)); } void OpenTabAsLink() {
diff --git a/chrome/browser/media/router/discovery/BUILD.gn b/chrome/browser/media/router/discovery/BUILD.gn index 2363eff..df7ec8b 100644 --- a/chrome/browser/media/router/discovery/BUILD.gn +++ b/chrome/browser/media/router/discovery/BUILD.gn
@@ -98,6 +98,7 @@ if (is_mac) { sources += [ "discovery_network_list_wifi_mac.mm" ] + configs += [ "//build/config/compiler:enable_arc" ] frameworks = [ "CoreWLAN.framework" ] }
diff --git a/chrome/browser/media/router/discovery/discovery_network_list_wifi_mac.mm b/chrome/browser/media/router/discovery/discovery_network_list_wifi_mac.mm index b4d4daf..cb31ae5 100644 --- a/chrome/browser/media/router/discovery/discovery_network_list_wifi_mac.mm +++ b/chrome/browser/media/router/discovery/discovery_network_list_wifi_mac.mm
@@ -12,6 +12,10 @@ #include "base/check.h" #include "base/strings/sys_string_conversions.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + // TODO(crbug.com/841631): This file uses the deprecated CWInterface interface; // it needs to be migrated to CWWiFiClient, which is unfortunately not // compatible. @@ -26,7 +30,7 @@ if (interface == nil) { return false; } - std::string ssid(base::SysNSStringToUTF8([interface ssid])); + std::string ssid(base::SysNSStringToUTF8(interface.ssid)); if (ssid.empty()) { return false; }
diff --git a/chrome/browser/metrics/power/battery_discharge_reporter.cc b/chrome/browser/metrics/power/battery_discharge_reporter.cc index d77426f..346312e 100644 --- a/chrome/browser/metrics/power/battery_discharge_reporter.cc +++ b/chrome/browser/metrics/power/battery_discharge_reporter.cc
@@ -47,29 +47,53 @@ base::TimeTicks now_ticks = base::TimeTicks::Now(); // First sampling event. Remember the time and skip. - if (!last_event_time_ticks_) { - last_event_time_ticks_ = now_ticks; - last_battery_state_ = battery_state; + if (!one_minute_interval_start_time_) { + one_minute_interval_start_time_ = now_ticks; + one_minute_interval_start_battery_state_ = battery_state; +#if BUILDFLAG(IS_WIN) + ten_minutes_interval_start_time_ = now_ticks; + ten_minutes_interval_start_battery_state_ = battery_state; +#endif // BUILDFLAG(IS_WIN) return; } - base::TimeDelta sampling_event_delta = now_ticks - *last_event_time_ticks_; - *last_event_time_ticks_ = now_ticks; - + // One minute interval. + base::TimeDelta one_minute_interval_duration = + now_ticks - *one_minute_interval_start_time_; #if BUILDFLAG(IS_MAC) - RecordIOPMPowerSourceSampleEventDelta(sampling_event_delta); + RecordIOPMPowerSourceSampleEventDelta(one_minute_interval_duration); #endif + ReportOneMinuteInterval(one_minute_interval_duration, battery_state); + one_minute_interval_start_time_ = now_ticks; + one_minute_interval_start_battery_state_ = battery_state; + is_initial_interval_ = false; +#if BUILDFLAG(IS_WIN) + // Ten minutes interval. + base::TimeDelta ten_minutes_interval_duration = + now_ticks - *ten_minutes_interval_start_time_; + if (ten_minutes_interval_duration >= base::Minutes(10)) { + ReportTenMinutesInterval(ten_minutes_interval_duration, battery_state); + ten_minutes_interval_start_time_ = now_ticks; + ten_minutes_interval_start_battery_state_ = battery_state; + } +#endif // BUILDFLAG(IS_WIN) +} + +void BatteryDischargeReporter::ReportOneMinuteInterval( + base::TimeDelta interval_duration, + const absl::optional<base::BatteryLevelProvider::BatteryState>& + battery_state) { // Evaluate battery discharge mode and rate. auto battery_discharge = GetBatteryDischargeDuringInterval( - last_battery_state_, battery_state, sampling_event_delta); - last_battery_state_ = battery_state; + one_minute_interval_start_battery_state_, battery_state, + interval_duration); // Intervals are expected to be approximately 1 minute long. Exclude samples // where the interval length deviate significantly from that value. 1 second // tolerance was chosen to include ~70% of all samples. if (battery_discharge.mode == BatteryDischargeMode::kDischarging && - !IsWithinTolerance(sampling_event_delta, base::Minutes(1), + !IsWithinTolerance(interval_duration, base::Minutes(1), base::Seconds(1))) { battery_discharge.mode = BatteryDischargeMode::kInvalidInterval; } @@ -107,11 +131,34 @@ // suffix. const std::vector<const char*> long_interval_suffixes{ "", long_interval_scenario_params.histogram_suffix}; - ReportBatteryHistograms(sampling_event_delta, battery_discharge, + ReportBatteryHistograms(interval_duration, battery_discharge, is_initial_interval_, long_interval_suffixes); - is_initial_interval_ = false; } +#if BUILDFLAG(IS_WIN) +void BatteryDischargeReporter::ReportTenMinutesInterval( + base::TimeDelta interval_duration, + const absl::optional<base::BatteryLevelProvider::BatteryState>& + battery_state) { + auto battery_discharge = GetBatteryDischargeDuringInterval( + ten_minutes_interval_start_battery_state_, battery_state, + interval_duration); + + // Intervals are expected to be approximately 10 minutes long. Exclude samples + // when the interval length deviates significantly from that value, as that + // could indicate that the system went to sleep. The tolerance is the same as + // the one used for 1 minute intervals. + if (battery_discharge.mode == BatteryDischargeMode::kDischarging && + !IsWithinTolerance(interval_duration, base::Minutes(10), + base::Seconds(1))) { + battery_discharge.mode = BatteryDischargeMode::kInvalidInterval; + } + + ReportBatteryHistogramsTenMinutesInterval(interval_duration, + battery_discharge); +} +#endif // BUILDFLAG(IS_WIN) + #if BUILDFLAG(IS_MAC) void BatteryDischargeReporter::RecordIOPMPowerSourceSampleEventDelta( base::TimeDelta sampling_event_delta) {
diff --git a/chrome/browser/metrics/power/battery_discharge_reporter.h b/chrome/browser/metrics/power/battery_discharge_reporter.h index 611ea93..b285044 100644 --- a/chrome/browser/metrics/power/battery_discharge_reporter.h +++ b/chrome/browser/metrics/power/battery_discharge_reporter.h
@@ -35,6 +35,26 @@ battery_state) override; private: + // Reports battery discharge histograms for a 1 minute interval. + void ReportOneMinuteInterval( + base::TimeDelta interval_duration, + const absl::optional<base::BatteryLevelProvider::BatteryState>& + battery_state); + +#if BUILDFLAG(IS_WIN) + // Reports battery discharge histograms for a 10 minutes interval. + // + // On Windows, the reported battery discharge over a 1 minute interval is + // frequently zero. This could be explained by some systems having a battery + // level granularity insufficient to measure the typical discharge over a + // 1 minute interval or by a refresh rate lower than once per minute. We'll + // verify if using a longer interval alleviates the problem. + void ReportTenMinutesInterval( + base::TimeDelta interval_duration, + const absl::optional<base::BatteryLevelProvider::BatteryState>& + battery_state); +#endif // BUILDFLAG(IS_WIN) + #if BUILDFLAG(IS_MAC) // Records the time delta between two events received from IOPMPowerSource. void RecordIOPMPowerSourceSampleEventDelta( @@ -49,11 +69,19 @@ std::unique_ptr<UsageScenarioTracker> battery_usage_scenario_tracker_; raw_ptr<UsageScenarioDataStore> battery_usage_scenario_data_store_; - // The time ticks from when the last event was received from - // |sampling_event_source_|. - absl::optional<base::TimeTicks> last_event_time_ticks_; + // The time and battery state at the last event received from + // `sampling_event_source_`. + absl::optional<base::TimeTicks> one_minute_interval_start_time_; + absl::optional<base::BatteryLevelProvider::BatteryState> + one_minute_interval_start_battery_state_; - absl::optional<base::BatteryLevelProvider::BatteryState> last_battery_state_; +#if BUILDFLAG(IS_WIN) + // The time and battery state at an event received from + // `sampling_event_source_` up to 10 minutes in the past. + absl::optional<base::TimeTicks> ten_minutes_interval_start_time_; + absl::optional<base::BatteryLevelProvider::BatteryState> + ten_minutes_interval_start_battery_state_; +#endif // BUILDFLAG(IS_WIN) // The first battery sample is potentially outdated because it is not taken // upon receiving a notification from the OS. This is used to differentiate
diff --git a/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc b/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc index e9004b8..613976a 100644 --- a/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc +++ b/chrome/browser/metrics/power/battery_discharge_reporter_unittest.cc
@@ -20,8 +20,12 @@ constexpr const char* kBatteryDischargeModeHistogramName = "Power.BatteryDischargeMode5"; +constexpr const char* kBatteryDischargeModeTenMinutesHistogramName = + "Power.BatteryDischargeMode5.TenMinutes"; constexpr const char* kBatteryDischargeRateMilliwattsHistogramName = "Power.BatteryDischargeRateMilliwatts6"; +constexpr const char* kBatteryDischargeRateMilliwattsTenMinutesHistogramName = + "Power.BatteryDischargeRateMilliwatts6.TenMinutes"; constexpr const char* kBatteryDischargeRateRelativeHistogramName = "Power.BatteryDischargeRateRelative5"; @@ -129,6 +133,8 @@ ExpectHistogramSamples(&histogram_tester_, suffixes, {{kBatteryDischargeModeHistogramName, static_cast<int>(expected_mode)}}); + histogram_tester_.ExpectTotalCount( + kBatteryDischargeModeTenMinutesHistogramName, 0); } protected: @@ -172,6 +178,10 @@ ExpectHistogramSamples(&histogram_tester_, suffixes, {{kBatteryDischargeRateRelativeHistogramName, kExpectedDischargeRateRelative}}); + histogram_tester_.ExpectTotalCount( + kBatteryDischargeModeTenMinutesHistogramName, 0); + histogram_tester_.ExpectTotalCount( + kBatteryDischargeRateMilliwattsTenMinutesHistogramName, 0); } TEST_F(BatteryDischargeReporterTest, BatteryDischargeCaptureIsTooLate) { @@ -496,4 +506,73 @@ histogram_tester_.ExpectUniqueSample( "Power.BatteryDischargeGranularityRelative2", kGranularityRelative, 1); } + +TEST_F(BatteryDischargeReporterTest, TenMinutesInterval) { + TestUsageScenarioDataStoreImpl usage_scenario_data_store; + + base::BatteryStateSampler battery_state_sampler( + std::make_unique<NoopSamplingEventSource>(), + std::make_unique<NoopBatteryLevelProvider>()); + BatteryDischargeReporter battery_discharge_reporter( + &battery_state_sampler, &usage_scenario_data_store); + + { + base::HistogramTester tester; + + // t = 0: No 10-minutes histograms emitted. + battery_discharge_reporter.OnBatteryStateSampled( + MakeBatteryState(kHalfBatteryChargeLevel)); + + // t = 1 to 9 minutes: No 10-minutes histograms emitted. + for (int i = 0; i < 9; ++i) { + task_environment_.FastForwardBy(base::Minutes(1)); + battery_discharge_reporter.OnBatteryStateSampled( + MakeBatteryState(kHalfBatteryChargeLevel - 2)); + tester.ExpectTotalCount(kBatteryDischargeModeTenMinutesHistogramName, 0); + tester.ExpectTotalCount( + kBatteryDischargeRateMilliwattsTenMinutesHistogramName, 0); + } + + // t = 10 minutes: Expect 10-minutes histograms to be emitted. + task_environment_.FastForwardBy(base::Minutes(1)); + battery_discharge_reporter.OnBatteryStateSampled( + MakeBatteryState(kHalfBatteryChargeLevel - 100)); + // 100 mWh discharge over 10 minutes equals 600 mW. + const int64_t kExpectedDischargeRate_mW = 600; + tester.ExpectUniqueSample(kBatteryDischargeModeTenMinutesHistogramName, + BatteryDischargeMode::kDischarging, 1); + tester.ExpectUniqueSample( + kBatteryDischargeRateMilliwattsTenMinutesHistogramName, + kExpectedDischargeRate_mW, 1); + } + + { + base::HistogramTester tester; + + // t = 20 minutes: Expect 10-minutes histograms to be emitted again. + task_environment_.FastForwardBy(base::Minutes(10)); + battery_discharge_reporter.OnBatteryStateSampled( + MakeBatteryState(kHalfBatteryChargeLevel - 300)); + // 200 mWh discharge over 10 minutes equals 1200 mW. + const int64_t kExpectedDischargeRate_mW = 1200; + tester.ExpectUniqueSample(kBatteryDischargeModeTenMinutesHistogramName, + BatteryDischargeMode::kDischarging, 1); + tester.ExpectUniqueSample( + kBatteryDischargeRateMilliwattsTenMinutesHistogramName, + kExpectedDischargeRate_mW, 1); + } + + { + base::HistogramTester tester; + + // t = 31 minutes: The interval duration is invalid. + task_environment_.FastForwardBy(base::Minutes(11)); + battery_discharge_reporter.OnBatteryStateSampled( + MakeBatteryState(kHalfBatteryChargeLevel - 400)); + tester.ExpectUniqueSample(kBatteryDischargeModeTenMinutesHistogramName, + BatteryDischargeMode::kInvalidInterval, 1); + tester.ExpectTotalCount( + kBatteryDischargeRateMilliwattsTenMinutesHistogramName, 0); + } +} #endif // BUILDFLAG(IS_WIN)
diff --git a/chrome/browser/metrics/power/power_metrics.cc b/chrome/browser/metrics/power/power_metrics.cc index faef671..ec6ba333 100644 --- a/chrome/browser/metrics/power/power_metrics.cc +++ b/chrome/browser/metrics/power/power_metrics.cc
@@ -18,16 +18,20 @@ constexpr const char* kBatteryDischargeRateMilliwattsHistogramName = "Power.BatteryDischargeRateMilliwatts6"; +constexpr const char* kBatteryDischargeRateRelativeHistogramName = + "Power.BatteryDischargeRateRelative5"; +constexpr const char* kBatteryDischargeModeHistogramName = + "Power.BatteryDischargeMode5"; #if BUILDFLAG(IS_WIN) constexpr const char* kHasPreciseBatteryDischargeGranularity = "Power.HasPreciseBatteryDischargeGranularity"; constexpr const char* kBatteryDischargeRatePreciseMilliwattsHistogramName = "Power.BatteryDischargeRatePreciseMilliwatts"; +constexpr const char* kBatteryDischargeRateMilliwattsTenMinutesHistogramName = + "Power.BatteryDischargeRateMilliwatts6.TenMinutes"; +constexpr const char* kBatteryDischargeModeTenMinutesHistogramName = + "Power.BatteryDischargeMode5.TenMinutes"; #endif // BUILDFLAG(IS_WIN) -constexpr const char* kBatteryDischargeRateRelativeHistogramName = - "Power.BatteryDischargeRateRelative5"; -constexpr const char* kBatteryDischargeModeHistogramName = - "Power.BatteryDischargeMode5"; #if BUILDFLAG(IS_MAC) // Reports `proportion` of a time used to a histogram in permyriad (1/100 %). @@ -262,6 +266,21 @@ } } +#if BUILDFLAG(IS_WIN) +void ReportBatteryHistogramsTenMinutesInterval( + base::TimeDelta interval_duration, + BatteryDischarge battery_discharge) { + base::UmaHistogramEnumeration(kBatteryDischargeModeTenMinutesHistogramName, + battery_discharge.mode); + if (battery_discharge.mode == BatteryDischargeMode::kDischarging) { + DCHECK(battery_discharge.rate_milliwatts.has_value()); + base::UmaHistogramCounts100000( + kBatteryDischargeRateMilliwattsTenMinutesHistogramName, + *battery_discharge.rate_milliwatts); + } +} +#endif // BUILDFLAG(IS_WIN) + #if BUILDFLAG(IS_MAC) void ReportShortIntervalHistograms( const char* scenario_suffix,
diff --git a/chrome/browser/metrics/power/power_metrics.h b/chrome/browser/metrics/power/power_metrics.h index b0b448ba..3241e84 100644 --- a/chrome/browser/metrics/power/power_metrics.h +++ b/chrome/browser/metrics/power/power_metrics.h
@@ -83,6 +83,13 @@ bool is_initial_interval, const std::vector<const char*>& scenario_suffixes); +#if BUILDFLAG(IS_WIN) +// Report battery metrics captured over a >10 minutes interval. +void ReportBatteryHistogramsTenMinutesInterval( + base::TimeDelta interval_duration, + BatteryDischarge battery_discharge); +#endif // BUILDFLAG(IS_WIN) + #if BUILDFLAG(IS_MAC) void ReportShortIntervalHistograms( const char* scenario_suffix,
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc index 4f67f6c..077bb71 100644 --- a/chrome/browser/net/errorpage_browsertest.cc +++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -410,7 +410,7 @@ // Clicking the reload button should load the error page again. content::TestNavigationObserver nav_observer(web_contents, 1); - // Can't use content::ExecuteScript because it waits for scripts to send + // Can't use content::ExecJs because it waits for scripts to send // notification that they've run, and scripts that trigger a navigation may // not send that notification. web_contents->GetPrimaryMainFrame()->ExecuteJavaScriptForTests( @@ -443,7 +443,7 @@ // Clicking the reload button should load the error page again. content::TestNavigationObserver nav_observer2(web_contents); - // Can't use content::ExecuteScript because it waits for scripts to send + // Can't use content::ExecJs because it waits for scripts to send // notification that they've run, and scripts that trigger a navigation may // not send that notification. web_contents->GetPrimaryMainFrame()->ExecuteJavaScriptForTests(
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc index f21d52f..e04bb784 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -937,7 +937,7 @@ content::RenderFrameHost* ad_frame = ChildFrameAt(web_contents->GetPrimaryMainFrame(), 0); const std::string no_op_script = "// No-op script"; - EXPECT_TRUE(ExecuteScript(ad_frame, no_op_script)); + EXPECT_TRUE(ExecJs(ad_frame, no_op_script)); ASSERT_TRUE( ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL))); @@ -992,12 +992,12 @@ content::RenderFrameHost* ad_frame = ChildFrameAt(web_contents->GetPrimaryMainFrame(), 0); const std::string no_op_script = "// No-op script"; - EXPECT_TRUE(ExecuteScript(ad_frame, no_op_script)); + EXPECT_TRUE(ExecJs(ad_frame, no_op_script)); // Activate the other frame directly by executing a dummy script. content::RenderFrameHost* ad_frame_2 = ChildFrameAt(web_contents->GetPrimaryMainFrame(), 1); - EXPECT_TRUE(ExecuteScript(ad_frame_2, no_op_script)); + EXPECT_TRUE(ExecJs(ad_frame_2, no_op_script)); // Ensure both frames are marked active. ASSERT_TRUE(
diff --git a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendDispatcherBridgeImpl.java b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendDispatcherBridgeImpl.java index 5db5662..e07a9e0a 100644 --- a/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendDispatcherBridgeImpl.java +++ b/chrome/browser/password_manager/android/java/src/org/chromium/chrome/browser/password_manager/PasswordStoreAndroidBackendDispatcherBridgeImpl.java
@@ -5,23 +5,12 @@ package org.chromium.chrome.browser.password_manager; import android.accounts.Account; -import android.content.Context; -import org.chromium.base.ContextUtils; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskTraits; -import org.chromium.chrome.browser.notifications.NotificationConstants; -import org.chromium.chrome.browser.notifications.NotificationUmaTracker; -import org.chromium.chrome.browser.notifications.NotificationWrapperBuilderFactory; -import org.chromium.chrome.browser.notifications.channels.ChromeChannelDefinitions.ChannelId; import org.chromium.chrome.browser.password_manager.PasswordStoreAndroidBackendReceiverBridgeImpl.JobId; -import org.chromium.components.browser_ui.notifications.NotificationManagerProxy; -import org.chromium.components.browser_ui.notifications.NotificationManagerProxyImpl; -import org.chromium.components.browser_ui.notifications.NotificationMetadata; -import org.chromium.components.browser_ui.notifications.NotificationWrapper; -import org.chromium.components.browser_ui.notifications.NotificationWrapperBuilder; import org.chromium.components.signin.AccountUtils; import java.util.Optional; @@ -34,7 +23,6 @@ class PasswordStoreAndroidBackendDispatcherBridgeImpl { private final PasswordStoreAndroidBackend mBackend; private final PasswordStoreAndroidBackendReceiverBridgeImpl mBackendReceiverBridge; - PasswordStoreAndroidBackendDispatcherBridgeImpl( PasswordStoreAndroidBackendReceiverBridgeImpl backendReceiverBridge, PasswordStoreAndroidBackend backend) { @@ -116,37 +104,4 @@ if (syncingAccount == null) return Optional.empty(); return Optional.of(AccountUtils.createAccountFromName(syncingAccount)); } - - // This method interacts with the UI and should be executed on the UI thread. Native dispatcher - // bridge however does not have JNIEnv for UI thread and calls this method on background thread. - // Operation is reposted on the default UI sequence for execution. - @CalledByNative - private void showErrorUi() { - PostTask.postTask(TaskTraits.UI_USER_VISIBLE, () -> showErrorUiOnMainThread()); - } - - private void showErrorUiOnMainThread() { - Context context = ContextUtils.getApplicationContext(); - // The context can sometimes be null in tests. - if (context == null) return; - String title = context.getString(R.string.upm_error_notification_title); - String contents = context.getString(R.string.upm_error_notification_contents); - NotificationManagerProxy notificationManager = new NotificationManagerProxyImpl(context); - NotificationWrapperBuilder notificationWrapperBuilder = - NotificationWrapperBuilderFactory - .createNotificationWrapperBuilder(ChannelId.BROWSER, - new NotificationMetadata( - NotificationUmaTracker.SystemNotificationType.UPM_ERROR, - null, NotificationConstants.NOTIFICATION_ID_UPM)) - .setAutoCancel(false) - .setContentTitle(title) - .setContentText(contents) - .setSmallIcon(PasswordManagerResourceProviderFactory.create() - .getPasswordManagerIcon()) - .setTicker(contents) - .setLocalOnly(true); - NotificationWrapper notification = - notificationWrapperBuilder.buildWithBigTextStyle(contents); - notificationManager.notify(notification); - } }
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.cc b/chrome/browser/password_manager/android/password_store_android_backend.cc index f323793..f0911fe 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend.cc +++ b/chrome/browser/password_manager/android/password_store_android_backend.cc
@@ -1032,10 +1032,6 @@ if (password_manager::IsUnrecoverableBackendError(api_error_code, operation, prefs_)) { if (!password_manager_upm_eviction::IsCurrentUserEvicted(prefs_)) { - if (base::FeatureList::IsEnabled( - password_manager::features::kShowUPMErrorNotification)) { - bridge_helper_->ShowErrorNotification(); - } password_manager_upm_eviction::EvictCurrentUser(api_error, prefs_); } } else if (IsAuthenticationError(api_error_code)) {
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper.h b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper.h index 1e0e1e7..7523b83 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper.h +++ b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper.h
@@ -55,8 +55,6 @@ [[nodiscard]] virtual JobId RemoveLogin( const password_manager::PasswordForm& form, Account account) = 0; - - virtual void ShowErrorNotification() = 0; }; } // namespace password_manager
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.cc b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.cc index 695bdf44..123f52e0 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.cc +++ b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.cc
@@ -174,14 +174,4 @@ return last_job_id_; } -void PasswordStoreAndroidBackendBridgeHelperImpl::ShowErrorNotification() { - DCHECK_CALLED_ON_VALID_SEQUENCE(main_sequence_checker_); - DCHECK(dispatcher_bridge_); - background_task_runner_->PostTask( - FROM_HERE, - base::BindOnce( - &PasswordStoreAndroidBackendDispatcherBridge::ShowErrorNotification, - base::Unretained(dispatcher_bridge_.get()))); -} - } // namespace password_manager
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.h b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.h index ff97c65d..9d010e26 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.h +++ b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl.h
@@ -50,8 +50,6 @@ [[nodiscard]] JobId RemoveLogin(const password_manager::PasswordForm& form, Account account) override; - void ShowErrorNotification() override; - private: JobId GetNextJobId();
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl_unittest.cc b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl_unittest.cc index 14a6203..f451cebc 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl_unittest.cc +++ b/chrome/browser/password_manager/android/password_store_android_backend_bridge_helper_impl_unittest.cc
@@ -98,7 +98,6 @@ RemoveLogin, (JobId, const PasswordForm&, Account), (override)); - MOCK_METHOD(void, ShowErrorNotification, (), (override)); }; } // namespace
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge.h b/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge.h index e7cf7a09..38422bc0 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge.h +++ b/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge.h
@@ -90,14 +90,6 @@ const PasswordForm& form, Account account) = 0; - // Displays a notification when a store backend request finishes with an - // unrecoverable error. TODO(crbug.com/1344576) Remove when not required - // anymore. - // This method interacts with the UI but should also be called on the - // background thread as native bridge does not have JNIEnv for the UI thread. - // Operation will be actually be executed on the UI thread by the Java bridge. - virtual void ShowErrorNotification() = 0; - // Factory function for creating the bridge. Implementation is pulled in by // including an implementation or by defining it explicitly in tests. // Ensure `CanCreateBackend` returns true before calling this method.
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.cc b/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.cc index c1aaa94..c2811a8 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.cc +++ b/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.cc
@@ -139,10 +139,4 @@ GetJavaStringFromAccount(std::move(account))); } -void PasswordStoreAndroidBackendDispatcherBridgeImpl::ShowErrorNotification() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - Java_PasswordStoreAndroidBackendDispatcherBridgeImpl_showErrorUi( - base::android::AttachCurrentThread(), java_object_); -} - } // namespace password_manager
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.h b/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.h index 33fdd87..6fefa7e 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.h +++ b/chrome/browser/password_manager/android/password_store_android_backend_dispatcher_bridge_impl.h
@@ -55,8 +55,6 @@ const password_manager::PasswordForm& form, Account account) override; - void ShowErrorNotification() override; - // This member stores the unique ID last used for an API request. JobId last_job_id_{0};
diff --git a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc index 0ec3e5c..74a6c15 100644 --- a/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc +++ b/chrome/browser/password_manager/android/password_store_android_backend_unittest.cc
@@ -179,7 +179,6 @@ MOCK_METHOD(JobId, AddLogin, (const PasswordForm&, Account), (override)); MOCK_METHOD(JobId, UpdateLogin, (const PasswordForm&, Account), (override)); MOCK_METHOD(JobId, RemoveLogin, (const PasswordForm&, Account), (override)); - MOCK_METHOD(void, ShowErrorNotification, (), (override)); }; } // namespace @@ -1161,61 +1160,6 @@ RunUntilIdle(); } -TEST_F(PasswordStoreAndroidBackendTest, - OnUnrecoverablApiErrorShowsUIFlagEnabled) { - base::test::ScopedFeatureList scoped_feature_list{ - password_manager::features::kShowUPMErrorNotification}; - backend().InitBackend(PasswordStoreAndroidBackend::RemoteChangesReceived(), - base::RepeatingClosure(), base::DoNothing()); - backend().OnSyncServiceInitialized(sync_service()); - - base::MockCallback<LoginsOrErrorReply> mock_reply; - EXPECT_CALL(*bridge_helper(), GetAllLogins).WillOnce(Return(kJobId)); - backend().GetAllLoginsAsync(mock_reply.Get()); - EXPECT_CALL( - mock_reply, - Run(ExpectError(PasswordStoreBackendErrorType::kUncategorized, - PasswordStoreBackendErrorRecoveryType::kUnrecoverable))); - AndroidBackendError error{AndroidBackendErrorType::kExternalError}; - // Simulate receiving INTERNAL_ERROR code. - int kInternalErrorCode = - static_cast<int>(AndroidBackendAPIErrorCode::kInternalError); - error.api_error_code = absl::optional<int>(kInternalErrorCode); - - EXPECT_CALL(*bridge_helper(), ShowErrorNotification); - consumer().OnError(kJobId, std::move(error)); - - RunUntilIdle(); -} - -TEST_F(PasswordStoreAndroidBackendTest, - OnUnrecoverablApiErrorNoUIFlagDisabled) { - base::test::ScopedFeatureList scoped_feature_list; - scoped_feature_list.InitAndDisableFeature( - password_manager::features::kShowUPMErrorNotification); - backend().InitBackend(PasswordStoreAndroidBackend::RemoteChangesReceived(), - base::RepeatingClosure(), base::DoNothing()); - backend().OnSyncServiceInitialized(sync_service()); - - base::MockCallback<LoginsOrErrorReply> mock_reply; - EXPECT_CALL(*bridge_helper(), GetAllLogins).WillOnce(Return(kJobId)); - backend().GetAllLoginsAsync(mock_reply.Get()); - EXPECT_CALL( - mock_reply, - Run(ExpectError(PasswordStoreBackendErrorType::kUncategorized, - PasswordStoreBackendErrorRecoveryType::kUnrecoverable))); - AndroidBackendError error{AndroidBackendErrorType::kExternalError}; - // Simulate receiving INTERNAL_ERROR code. - int kInternalErrorCode = - static_cast<int>(AndroidBackendAPIErrorCode::kInternalError); - error.api_error_code = absl::optional<int>(kInternalErrorCode); - - EXPECT_CALL(*bridge_helper(), ShowErrorNotification).Times(0); - consumer().OnError(kJobId, std::move(error)); - - RunUntilIdle(); -} - TEST_F(PasswordStoreAndroidBackendTest, DisableAutoSignInForOrigins) { base::HistogramTester histogram_tester;
diff --git a/chrome/browser/password_manager/android/pwd_migration/BUILD.gn b/chrome/browser/password_manager/android/pwd_migration/BUILD.gn index 06a64cd..e9f9cda 100644 --- a/chrome/browser/password_manager/android/pwd_migration/BUILD.gn +++ b/chrome/browser/password_manager/android/pwd_migration/BUILD.gn
@@ -32,8 +32,10 @@ ":java_resources", "//base:base_java", "//base:jni_java", + "//chrome/browser/password_manager/android:password_manager_resource_provider_java", "//components/browser_ui/bottomsheet/android:java", "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_appcompat_appcompat_resources_java", "//ui/android:ui_java", ] @@ -76,14 +78,19 @@ # Consult izuzic@ before adding more tests to this target. # This target will exist only temporary. - sources = [ "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java" ] + sources = [ + "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java", + "java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningViewTest.java", + ] deps = [ ":java", + ":java_resources", "//base:base_java", "//base:base_java_test_support", "//chrome/android:chrome_java", "//chrome/browser/flags:java", + "//chrome/browser/ui/android/night_mode:night_mode_java_test_support", "//chrome/test/android:chrome_java_integration_test_support", "//chrome/test/android:chrome_java_test_support_common", "//components/browser_ui/bottomsheet/android:java", @@ -96,6 +103,7 @@ "//third_party/junit:junit", "//third_party/mockito:mockito_java", "//ui/android:ui_java", + "//ui/android:ui_java_test_support", ] }
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml index ea7c4f2..a0fa5d5 100644 --- a/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml +++ b/chrome/browser/password_manager/android/pwd_migration/java/res/layout/pwd_migration_warning.xml
@@ -10,4 +10,54 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_height="wrap_content" android:layout_width="match_parent" - android:orientation="vertical"/> + android:orientation="vertical" + android:id="@+id/pwd_migration_warning_sheet"> + + <ImageView + android:id="@+id/drag_handlebar" + android:layout_alignParentTop="true" + android:layout_centerHorizontal="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginEnd="16dp" + android:layout_marginStart="16dp" + android:layout_marginTop="6dp" + android:layout_marginBottom="6dp" + android:importantForAccessibility="no" + app:srcCompat="@drawable/drag_handlebar" /> + + <LinearLayout + android:id="@+id/sheet_item_list" + android:layout_below="@id/drag_handlebar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginEnd="16dp" + android:layout_marginStart="16dp" + android:layout_marginTop="16dp" + android:layout_marginBottom="15dp" + android:clipToPadding="false" + android:divider="@null" + tools:listitem="@layout/touch_to_fill_credential_item_modern" + android:orientation="vertical"> + + <ImageView + android:id="@+id/touch_to_fill_sheet_header_image" + android:layout_width="32dp" + android:layout_height="32dp" + android:layout_gravity="center_horizontal" + android:layout_marginBottom="8dp" + android:importantForAccessibility="no"/> + + <androidx.appcompat.widget.DialogTitle + android:id="@+id/touch_to_fill_sheet_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:paddingTop="10dp" + android:paddingBottom="10dp" + android:textAlignment="center" + android:textAppearance="@style/TextAppearance.AlertDialogTitleStyle" + android:text="@string/password_migration_warning_title"/> + </LinearLayout> +</RelativeLayout>
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java new file mode 100644 index 0000000..5d4f4f3 --- /dev/null +++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningRenderTest.java
@@ -0,0 +1,122 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.pwd_migration; + +import static org.chromium.chrome.browser.pwd_migration.PasswordMigrationWarningProperties.VISIBLE; +import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking; +import static org.chromium.ui.base.LocalizationUtils.setRtlForTesting; + +import android.view.View; + +import androidx.test.filters.MediumTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import org.chromium.base.Callback; +import org.chromium.base.test.params.ParameterAnnotations; +import org.chromium.base.test.params.ParameterSet; +import org.chromium.base.test.params.ParameterizedRunner; +import org.chromium.base.test.util.ApplicationTestUtils; +import org.chromium.base.test.util.Batch; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.browser.night_mode.ChromeNightModeTestUtils; +import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.chrome.test.util.ChromeRenderTestRule; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport; +import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModelChangeProcessor; +import org.chromium.ui.test.util.RenderTestRule.Component; + +import java.util.Arrays; +import java.util.List; + +/** + * These tests render screenshots of password migration warning sheet and compare them to a gold + * standard. + */ +@RunWith(ParameterizedRunner.class) +@Batch(Batch.PER_CLASS) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class PasswordMigrationWarningRenderTest { + @ParameterAnnotations.ClassParameter + private static List<ParameterSet> sClassParams = + Arrays.asList(new ParameterSet().value(false, false).name("Default"), + new ParameterSet().value(false, true).name("RTL"), + new ParameterSet().value(true, false).name("NightMode")); + + @Mock + private Callback<Integer> mDismissCallback; + + private BottomSheetController mBottomSheetController; + private PasswordMigrationWarningView mView; + private PropertyModel mModel; + + public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + + @Rule + public final ChromeRenderTestRule mRenderTestRule = + ChromeRenderTestRule.Builder.withPublicCorpus() + .setRevision(0) + .setBugComponent(Component.UI_BROWSER_AUTOFILL) + .build(); + + public PasswordMigrationWarningRenderTest(boolean nightModeEnabled, boolean useRtlLayout) { + setRtlForTesting(useRtlLayout); + ChromeNightModeTestUtils.setUpNightModeForChromeActivity(nightModeEnabled); + mRenderTestRule.setNightModeEnabled(nightModeEnabled); + mRenderTestRule.setVariantPrefix(useRtlLayout ? "RTL" : "LTR"); + } + + @Before + public void setUp() throws InterruptedException { + MockitoAnnotations.initMocks(this); + mActivityTestRule.startMainActivityOnBlankPage(); + mBottomSheetController = mActivityTestRule.getActivity() + .getRootUiCoordinatorForTesting() + .getBottomSheetController(); + runOnUiThreadBlocking(() -> { + mModel = PasswordMigrationWarningProperties.createDefaultModel(mDismissCallback); + mView = new PasswordMigrationWarningView( + mActivityTestRule.getActivity(), mBottomSheetController); + PropertyModelChangeProcessor.create(mModel, mView, + PasswordMigrationWarningViewBinder::bindPasswordMigrationWarningView); + }); + } + + @After + public void tearDown() { + setRtlForTesting(false); + try { + ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity()); + } catch (Exception e) { + // Activity was already closed (e.g. due to last test tearing down the suite). + } + runOnUiThreadBlocking(() -> { + ChromeNightModeTestUtils.tearDownNightModeAfterChromeActivityDestroyed(); + }); + } + + @Test + @MediumTest + @Feature({"RenderTest"}) + public void testShowsPasswordMigrationWwarningFirstPage() throws Exception { + runOnUiThreadBlocking(() -> mModel.set(VISIBLE, true)); + + BottomSheetTestSupport.waitForOpen(mBottomSheetController); + + View bottomSheetView = + mActivityTestRule.getActivity().findViewById(R.id.pwd_migration_warning_sheet); + mRenderTestRule.render(bottomSheetView, "pwd_migration_warning_first_page"); + } +}
diff --git a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java index 6749e9b..f92e017 100644 --- a/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java +++ b/chrome/browser/password_manager/android/pwd_migration/java/src/org/chromium/chrome/browser/pwd_migration/PasswordMigrationWarningView.java
@@ -7,11 +7,14 @@ import android.content.Context; import android.view.LayoutInflater; import android.view.View; +import android.widget.ImageView; import android.widget.RelativeLayout; import androidx.annotation.Nullable; +import androidx.appcompat.content.res.AppCompatResources; import org.chromium.base.Callback; +import org.chromium.chrome.browser.password_manager.PasswordManagerResourceProviderFactory; import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; import org.chromium.components.browser_ui.bottomsheet.BottomSheetObserver; @@ -49,6 +52,10 @@ mBottomSheetController = bottomSheetController; mContentView = (RelativeLayout) LayoutInflater.from(context).inflate( R.layout.pwd_migration_warning, null); + ImageView sheetHeaderImage = + mContentView.findViewById(R.id.touch_to_fill_sheet_header_image); + sheetHeaderImage.setImageDrawable(AppCompatResources.getDrawable( + context, PasswordManagerResourceProviderFactory.create().getPasswordManagerIcon())); } void setDismissHandler(Callback<Integer> dismissHandler) {
diff --git a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc index 7f9ff44..c739ba5 100644 --- a/chrome/browser/password_manager/android/save_update_password_message_delegate.cc +++ b/chrome/browser/password_manager/android/save_update_password_message_delegate.cc
@@ -421,8 +421,8 @@ kUnifiedPasswordManagerLocalPasswordsMigrationWarning)) { // TODO(crbug.com/439853): Check if the bottom sheet was shown a month ago // or more. - std::move(create_migration_warning_callback_) - .Run(web_contents_->GetTopLevelNativeWindow()); + create_migration_warning_callback_.Run( + web_contents_->GetTopLevelNativeWindow()); } }
diff --git a/chrome/browser/password_manager/credential_manager_browsertest.cc b/chrome/browser/password_manager/credential_manager_browsertest.cc index 3d8e7eb..c1307bb6 100644 --- a/chrome/browser/password_manager/credential_manager_browsertest.cc +++ b/chrome/browser/password_manager/credential_manager_browsertest.cc
@@ -86,7 +86,7 @@ content::WebContents* web_contents, const char* username, const char* password) { - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( web_contents, base::StringPrintf( "window.addEventListener(\"unload\", () => {" @@ -284,13 +284,14 @@ std::string fill_password = "document.getElementById('username_field').value = 'user';" "document.getElementById('password_field').value = 'password';"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_password)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_password)); // Call the API to trigger the notification to the client. - ASSERT_TRUE(content::ExecuteScript( - WebContents(), - "navigator.credentials.get({password: true})" - ".then(cred => window.location = '/password/done.html')")); + ASSERT_TRUE( + content::ExecJs(WebContents(), + "navigator.credentials.get({password: true})" + ".then(cred => window.location = '/password/done.html')", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); // Mojo calls from the renderer are asynchronous. BubbleObserver(WebContents()).WaitForAccountChooser(); PasswordsModelDelegateFromWebContents(WebContents()) @@ -361,11 +362,12 @@ NavigateToFile("/password/simple_password.html"); // Call the API to store 'user1' with the old password. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "navigator.credentials.store(" " new PasswordCredential({ id: 'user1', password: 'abcdef' }))" - ".then(cred => window.location = '/password/done.html');")); + ".then(cred => window.location = '/password/done.html');", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); PasswordsNavigationObserver observer(WebContents()); observer.SetPathToWaitFor("/password/done.html"); @@ -376,11 +378,12 @@ NavigateToFile("/password/simple_password.html"); // Call the API to store 'user2' with the old password. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "navigator.credentials.store(" " new PasswordCredential({ id: 'user2', password: '123456' }))" - ".then(cred => window.location = '/password/done.html');")); + ".then(cred => window.location = '/password/done.html');", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); PasswordsNavigationObserver observer(WebContents()); observer.SetPathToWaitFor("/password/done.html"); @@ -448,11 +451,12 @@ NavigateToFile("/password/simple_password.html"); // Call the API to store 'user1' with a new password. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "navigator.credentials.store(" " new PasswordCredential({ id: 'user1', password: 'ABCDEF' }))" - ".then(cred => window.location = '/password/done.html');")); + ".then(cred => window.location = '/password/done.html');", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); PasswordsNavigationObserver observer(WebContents()); observer.SetPathToWaitFor("/password/done.html"); @@ -463,11 +467,12 @@ NavigateToFile("/password/simple_password.html"); // Call the API to store 'user2' with a new password. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "navigator.credentials.store(" " new PasswordCredential({ id: 'user2', password: 'UVWXYZ' }))" - ".then(cred => window.location = '/password/done.html');")); + ".then(cred => window.location = '/password/done.html');", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); PasswordsNavigationObserver observer(WebContents()); observer.SetPathToWaitFor("/password/done.html"); @@ -546,11 +551,12 @@ NavigateToFile("/password/simple_password.html"); // Call the API to store 'user1' with a new password. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "navigator.credentials.store(" " new PasswordCredential({ id: 'user1', password: 'ABCDEF' }))" - ".then(cred => window.location = '/password/done.html');")); + ".then(cred => window.location = '/password/done.html');", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); PasswordsNavigationObserver observer(WebContents()); observer.SetPathToWaitFor("/password/done.html"); @@ -561,11 +567,12 @@ NavigateToFile("/password/simple_password.html"); // Call the API to store 'user2' with a new password. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "navigator.credentials.store(" " new PasswordCredential({ id: 'user2', password: 'UVWXYZ' }))" - ".then(cred => window.location = '/password/done.html');")); + ".then(cred => window.location = '/password/done.html');", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); PasswordsNavigationObserver observer(WebContents()); observer.SetPathToWaitFor("/password/done.html"); @@ -614,13 +621,13 @@ "/password/password_form.html"); // Call the API to trigger |get| and |store| and redirect. - ASSERT_TRUE( - content::ExecuteScript(WebContents(), - "navigator.credentials.get({password: true})" - ".then(cred => " - "navigator.credentials.store(cred)" - ".then(cred => " - "window.location = '/password/done.html'))")); + ASSERT_TRUE(content::ExecJs(WebContents(), + "navigator.credentials.get({password: true})" + ".then(cred => " + "navigator.credentials.store(cred)" + ".then(cred => " + "window.location = '/password/done.html'))", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); // Mojo calls from the renderer are asynchronous. BubbleObserver(WebContents()).WaitForAccountChooser(); @@ -671,11 +678,12 @@ "/password/password_form.html"); // Call the API to trigger |get| and |store| and redirect. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "navigator.credentials.store(" " new PasswordCredential({ id: 'user', password: 'P4SSW0RD' }))" - ".then(cred => window.location = '/password/done.html');")); + ".then(cred => window.location = '/password/done.html');", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); PasswordsNavigationObserver observer(WebContents()); observer.SetPathToWaitFor("/password/done.html"); @@ -729,8 +737,9 @@ browser(), https_test_server().GetURL("/password/done.html"))); // Call the API to trigger the account chooser. - ASSERT_TRUE(content::ExecuteScript( - WebContents(), "navigator.credentials.get({password: true})")); + ASSERT_TRUE(content::ExecJs(WebContents(), + "navigator.credentials.get({password: true})", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); BubbleObserver(WebContents()).WaitForAccountChooser(); // Wait for the migration logic to actually touch the password store. @@ -766,13 +775,14 @@ std::string fill_password = "document.getElementById('username_field').value = 'trash';" "document.getElementById('password_field').value = 'trash';"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_password)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_password)); // Call the API to trigger the notification to the client. - ASSERT_TRUE(content::ExecuteScript( - WebContents(), - "navigator.credentials.get({password: true})" - ".then(cred => window.location = '/password/done.html');")); + ASSERT_TRUE( + content::ExecJs(WebContents(), + "navigator.credentials.get({password: true})" + ".then(cred => window.location = '/password/done.html');", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); PasswordsNavigationObserver observer(WebContents()); observer.SetPathToWaitFor("/password/done.html"); @@ -833,10 +843,11 @@ EXPECT_FALSE(client->has_binding_for_credential_manager()); EXPECT_FALSE(client->was_store_ever_called()); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "var c = new PasswordCredential({ id: 'user', password: 'hunter2' });" - "navigator.credentials.store(c);")); + "navigator.credentials.store(c);", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); BubbleObserver prompt_observer(WebContents()); prompt_observer.WaitForAutomaticSavePrompt(); @@ -885,7 +896,7 @@ NavigateToFile("/password/password_form.html"); const GURL current_url = WebContents()->GetLastCommittedURL(); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "document.getElementById('input_submit_button').addEventListener('click'," "function(event) {" @@ -894,7 +905,7 @@ "});")); // Fill the password and click the button to submit the page. The API should // suppress the autofill password manager. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "document.getElementById('username_field').value = 'user';" "document.getElementById('password_field').value = 'autofill';" @@ -939,7 +950,7 @@ NavigateToFile("/password/password_form.html"); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "document.getElementById('input_submit_button').addEventListener('click'," "function(event) {" @@ -950,7 +961,7 @@ // API should suppress the autofill password manager and overwrite the // password. PasswordsNavigationObserver form_submit_observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "document.getElementById('username_field').value = 'user';" "document.getElementById('password_field').value = 'autofill';" @@ -987,10 +998,11 @@ IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, CredentialsAutofilled) { NavigateToFile("/password/password_form.html"); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( RenderFrameHost(), "var c = new PasswordCredential({ id: 'user', password: '12345' });" - "navigator.credentials.store(c);")); + "navigator.credentials.store(c);", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); BubbleObserver bubble_observer(WebContents()); bubble_observer.WaitForAutomaticSavePrompt(); bubble_observer.AcceptSavePrompt(); @@ -1170,8 +1182,9 @@ AddPasswordForURL(b_url); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), a_url)); - ASSERT_TRUE(content::ExecuteScript( - WebContents(), "navigator.credentials.get({password: true})")); + ASSERT_TRUE(content::ExecJs(WebContents(), + "navigator.credentials.get({password: true})", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); // The account chooser UI requested the avatar. BubbleObserver(WebContents()).WaitForAccountChooser(); @@ -1179,15 +1192,17 @@ // Navigate to the second site, the icon is requested again. ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), b_url)); - ASSERT_TRUE(content::ExecuteScript( - WebContents(), "navigator.credentials.get({password: true})")); + ASSERT_TRUE(content::ExecJs(WebContents(), + "navigator.credentials.get({password: true})", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); BubbleObserver(WebContents()).WaitForAccountChooser(); WaitForAvatarCounter(2u); // Navigate back to the first site, the icon is already cached. ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), a_url)); - ASSERT_TRUE(content::ExecuteScript( - WebContents(), "navigator.credentials.get({password: true})")); + ASSERT_TRUE(content::ExecJs(WebContents(), + "navigator.credentials.get({password: true})", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); BubbleObserver(WebContents()).WaitForAccountChooser(); EXPECT_EQ(avatar_request_counter(), 2u); }
diff --git a/chrome/browser/password_manager/password_generation_interactive_uitest.cc b/chrome/browser/password_manager/password_generation_interactive_uitest.cc index 5f633a6..603a4493 100644 --- a/chrome/browser/password_manager/password_generation_interactive_uitest.cc +++ b/chrome/browser/password_manager/password_generation_interactive_uitest.cc
@@ -106,12 +106,12 @@ } void FocusPasswordField() { - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "document.getElementById('password_field').focus()")); } void FocusUsernameField() { - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "document.getElementById('username_field').focus();")); } @@ -314,8 +314,7 @@ FocusPasswordField(); EXPECT_TRUE(GenerationPopupShowing()); - ASSERT_TRUE( - content::ExecuteScript(WebContents(), "window.scrollTo(100, 0);")); + ASSERT_TRUE(content::ExecJs(WebContents(), "window.scrollTo(100, 0);")); EXPECT_FALSE(GenerationPopupShowing()); } @@ -331,7 +330,7 @@ std::string focus_script = "document.getElementById('password_field').focus();"; - ASSERT_TRUE(content::ExecuteScript(child_frame, focus_script)); + ASSERT_TRUE(content::ExecJs(child_frame, focus_script)); EXPECT_TRUE(GenerationPopupShowing()); } @@ -406,7 +405,7 @@ PasswordsNavigationObserver observer(WebContents()); std::string submit_script = "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit_script)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit_script)); ASSERT_TRUE(observer.Wait()); WaitForPasswordStore();
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc index e86658b..ad5ff66 100644 --- a/chrome/browser/password_manager/password_manager_browsertest.cc +++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -260,7 +260,7 @@ "document.getElementById('password_failed').value = 'random';" "document.getElementById('failed_form').submit()"; - ASSERT_TRUE(content::ExecuteScript(web_contents, fill_and_submit)); + ASSERT_TRUE(content::ExecJs(web_contents, fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(BubbleObserver(web_contents).IsSavePromptShownAutomatically()); } @@ -285,8 +285,8 @@ "document.body.appendChild(frame);" "frame.contentDocument.body.innerHTML = \"" + form_html + "\""; - ASSERT_TRUE(content::ExecuteScript(web_contents, - inject_blank_frame_with_password_form)); + ASSERT_TRUE( + content::ExecJs(web_contents, inject_blank_frame_with_password_form)); } // Inject an iframe with a password form that uses the specified action URL into @@ -303,8 +303,8 @@ form_html + "\");" "ifr.contentWindow.document.close();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, - inject_blank_frame_with_password_form)); + ASSERT_TRUE( + content::ExecJs(web_contents, inject_blank_frame_with_password_form)); } // Fills in a fake password and submits the form in |frame|, waiting for the @@ -318,7 +318,7 @@ "document.getElementById('testform').submit();"; PasswordsNavigationObserver observer(web_contents); observer.SetPathToWaitFor(action_url.path()); - ASSERT_TRUE(content::ExecuteScript(frame, submit_form)); + ASSERT_TRUE(content::ExecJs(frame, submit_form)); ASSERT_TRUE(observer.Wait()); } @@ -334,7 +334,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); // Save the password and check the store. @@ -362,7 +362,7 @@ "document.getElementById('new_password_1').value = 'new_pass';" "document.getElementById('new_password_2').value = 'new_pass';" "document.getElementById('chg_submit_wo_username_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); } @@ -395,7 +395,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); BubbleObserver prompt_observer(WebContents()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); @@ -413,7 +413,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -431,7 +431,7 @@ "document.getElementById('username_unrelated').value = 'temp';" "document.getElementById('password_unrelated').value = 'random';" "document.getElementById('submit_unrelated').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -445,7 +445,7 @@ "document.getElementById('username_failed').value = 'temp';" "document.getElementById('password_failed').value = 'random';" "document.getElementById('submit_failed').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -463,7 +463,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -486,7 +486,7 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL( "example.com", "/password/dynamic_password_form.html"))); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "document.getElementById('create_form_button').click();")); // Blink has a timer for 0.3 seconds before it updates the browser with the @@ -501,7 +501,7 @@ "document.dynamic_form.username.value = 'tempro';" "document.dynamic_form.password.value = 'random';" "document.dynamic_form.submit()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); @@ -538,8 +538,8 @@ "var second_iframe = document.getElementById('second_frame');" "second_iframe.contentWindow.location.href = 'done.html';"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill)); - ASSERT_TRUE(content::ExecuteScript(WebContents(), navigate_frame)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill)); + ASSERT_TRUE(content::ExecJs(WebContents(), navigate_frame)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -557,7 +557,7 @@ "document.getElementById('username_different_action').value = 'temp';" "document.getElementById('password_different_action').value = 'random';" "document.getElementById('submit_different_action').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -573,7 +573,7 @@ "document.getElementById('username_action_mutation').value = 'temp';" "document.getElementById('password_action_mutation').value = 'random';" "document.getElementById('submit_action_mutation').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"XHR_FINISHED\"") @@ -595,7 +595,7 @@ "document.getElementById('username_contains_username').value = 'temp';" "document.getElementById('password_contains_username').value = 'random';" "document.getElementById('submit_contains_username').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -613,7 +613,7 @@ "document.getElementById('username').value = 'temp';" "document.getElementById('password').value = 'random';" "document.getElementById('submit-button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -637,8 +637,8 @@ "frame_doc.getElementById('password_field').value = 'random';" "frame_doc.getElementById('input_submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), navigate_frame)); - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), navigate_frame)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -657,7 +657,7 @@ "document.getElementById('password_failed').value = 'random';" "document.getElementById('submit_failed').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -678,7 +678,7 @@ "frame_doc.getElementById('password_failed').value = 'random';" "frame_doc.getElementById('submit_failed').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); observer.SetPathToWaitFor("/password/failed.html"); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); @@ -697,7 +697,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -721,7 +721,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"XHR_FINISHED\"") @@ -751,7 +751,7 @@ "document.getElementById('signup_password_field').value = 'random';" "document.getElementById('confirmation_password_field').value = 'random';" "document.getElementById('signup_submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"XHR_FINISHED\"") @@ -776,7 +776,7 @@ "navigate = false;" "document.getElementById('username_field').value = 'temp';" "document.getElementById('submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"XHR_FINISHED\"") @@ -802,7 +802,7 @@ "navigate = false;" "document.getElementById('signup_username_field').value = 'temp';" "document.getElementById('signup_submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"XHR_FINISHED\"") @@ -825,7 +825,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -849,7 +849,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"FETCH_FINISHED\"") @@ -879,7 +879,7 @@ "document.getElementById('signup_password_field').value = 'random';" "document.getElementById('confirmation_password_field').value = 'random';" "document.getElementById('signup_submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"FETCH_FINISHED\"") @@ -905,7 +905,7 @@ "navigate = false;" "document.getElementById('username_field').value = 'temp';" "document.getElementById('submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"FETCH_FINISHED\"") @@ -931,7 +931,7 @@ "navigate = false;" "document.getElementById('signup_username_field').value = 'temp';" "document.getElementById('signup_submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"FETCH_FINISHED\"") @@ -952,7 +952,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('link').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_click_link)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_click_link)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -974,7 +974,7 @@ "document.getElementById('username_field').value = 'my_username';" "document.getElementById('password_field').value = 'password';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(first_observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); @@ -996,7 +996,7 @@ BubbleObserver second_prompt_observer(WebContents()); std::string submit_form = "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit_form)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit_form)); ASSERT_TRUE(second_observer.Wait()); EXPECT_FALSE(second_prompt_observer.IsSavePromptShownAutomatically()); @@ -1031,7 +1031,7 @@ "iframe_doc.getElementById('password_field').value = 'random';" "iframe_doc.getElementById('submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1048,7 +1048,7 @@ "document.getElementById('username_field_no_name').value = 'temp';" "document.getElementById('password_field_no_name').value = 'random';" "document.getElementById('input_submit_button_no_name').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1065,7 +1065,7 @@ "document.getElementsByName('username_field_no_id')[0].value = 'temp';" "document.getElementsByName('password_field_no_id')[0].value = 'random';" "document.getElementsByName('input_submit_button_no_id')[0].click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1085,7 +1085,7 @@ "var password = form.children[1];" "password.value = 'random';" "form.children[2].click()"; // form.children[2] is the submit button. - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); prompt_observer.AcceptSavePrompt(); @@ -1106,7 +1106,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1123,7 +1123,7 @@ "document.getElementById('username_field_http_error').value = 'temp';" "document.getElementById('password_field_http_error').value = 'random';" "document.getElementById('input_submit_button_http_error').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1148,8 +1148,8 @@ "document.getElementById('input_submit_button').click();" "window.location.href = 'done.html';"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), save_and_remove)); - ASSERT_TRUE(content::ExecuteScript(WebContents(), navigate_frame)); + ASSERT_TRUE(content::ExecJs(WebContents(), save_and_remove)); + ASSERT_TRUE(content::ExecJs(WebContents(), navigate_frame)); ASSERT_TRUE(observer.Wait()); // The only thing we check here is that there is no use-after-free reported. } @@ -1338,7 +1338,7 @@ // Click on a link to open a new tab, then switch back to the first one. EXPECT_EQ(1, browser()->tab_strip_model()->count()); std::string click = "document.getElementById('testlink').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), click)); + ASSERT_TRUE(content::ExecJs(WebContents(), click)); EXPECT_EQ(2, browser()->tab_strip_model()->count()); browser()->tab_strip_model()->ActivateTabAt(0); @@ -1411,7 +1411,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1427,7 +1427,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1439,7 +1439,7 @@ std::string fill = "document.getElementById('username_redirect').value = 'temp';" "document.getElementById('password_redirect').value = 'random';"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill)); PasswordsNavigationObserver observer(WebContents()); BubbleObserver prompt_observer(WebContents()); @@ -1462,7 +1462,7 @@ "document.getElementById('username').value = 'temp';" "document.getElementById('password').value = 'random';" "document.getElementById('submit-button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); @@ -1489,7 +1489,7 @@ std::string show_form = "document.getElementsByTagName('form')[0].style.display = 'block'"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), show_form)); + ASSERT_TRUE(content::ExecJs(WebContents(), show_form)); // Wait until the username is filled, to make sure autofill kicked in. WaitForElementValue("username", "admin"); @@ -1529,7 +1529,7 @@ // Show the form and make sure that the password was autofilled. std::string show_form = "document.getElementsByTagName('form')[0].style.display = 'block'"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), show_form)); + ASSERT_TRUE(content::ExecJs(WebContents(), show_form)); CheckElementValue("username", "admin"); CheckElementValue("password", "12345"); @@ -1610,7 +1610,7 @@ "document.getElementById('username').value = 'overwrite_me';" "document.getElementById('password').value = 'random';" "document.getElementById('non-form-button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit)); ASSERT_TRUE(observer.Wait()); WaitForPasswordStore(); @@ -1634,7 +1634,7 @@ "document.getElementById('username_redirect').value = 'user';" "document.getElementById('password_redirect').value = 'password';" "document.getElementById('submit_redirect').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit_redirect)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit_redirect)); PasswordsNavigationObserver redirect_observer(WebContents()); redirect_observer.SetPathToWaitFor("/password/redirect.html"); @@ -1662,8 +1662,7 @@ "document.getElementById('username_field').value = 'attacker_username';" "document.getElementById('password_field').value = 'attacker_password';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE( - content::ExecuteScript(WebContents(), fill_and_submit_attacker_form)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit_attacker_form)); PasswordsNavigationObserver done_observer(WebContents()); done_observer.SetPathToWaitFor("/password/done.html"); @@ -1788,7 +1787,7 @@ std::string submit = "document.getElementById('password').value = 'password';" "document.getElementById('submit-button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); @@ -1817,7 +1816,7 @@ NavigateToFile("/password/dynamic_password_form.html"); const std::string create_form = "document.getElementById('create_form_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), create_form)); + ASSERT_TRUE(content::ExecJs(WebContents(), create_form)); // Wait until the username is filled, to make sure autofill kicked in. WaitForElementValue("username_id", "temp"); @@ -1826,8 +1825,8 @@ const std::string delete_form = "var form = document.getElementById('dynamic_form_id');" "form.parentNode.removeChild(form);"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), delete_form)); - ASSERT_TRUE(content::ExecuteScript(WebContents(), create_form)); + ASSERT_TRUE(content::ExecJs(WebContents(), delete_form)); + ASSERT_TRUE(content::ExecJs(WebContents(), create_form)); WaitForElementValue("username_id", "temp"); } @@ -1848,13 +1847,13 @@ password_store->AddLogin(signin_form); NavigateToFile("/password/recurring_dynamic_form.html"); - ASSERT_TRUE(content::ExecuteScript(WebContents(), "addForm();")); + ASSERT_TRUE(content::ExecJs(WebContents(), "addForm();")); // Wait until the username is filled, to make sure autofill kicked in. WaitForJsElementValue("document.body.children[0].children[0]", "temp"); WaitForJsElementValue("document.body.children[0].children[1]", "random"); // Add one more form. - ASSERT_TRUE(content::ExecuteScript(WebContents(), "addForm();")); + ASSERT_TRUE(content::ExecJs(WebContents(), "addForm();")); // Wait until the username is filled, to make sure autofill kicked in. WaitForJsElementValue("document.body.children[1].children[0]", "temp"); WaitForJsElementValue("document.body.children[1].children[1]", "random"); @@ -1892,7 +1891,7 @@ // Submit the form. It shouldn't revive the credential in the store. PasswordsNavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "document.getElementById('input_submit_button').click()")); ASSERT_TRUE(observer.Wait()); @@ -1918,7 +1917,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1940,7 +1939,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1959,7 +1958,7 @@ "document.getElementById('ea_username_field').value = 'temp';" "document.getElementById('ea_password_field').value = 'random';" "document.getElementById('ea_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -1979,7 +1978,7 @@ "document.getElementById('ea_username_field').value = 'temp';" "document.getElementById('ea_password_field').value = 'random';" "document.getElementById('ea_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -2000,7 +1999,7 @@ "document.getElementById('pa_username_field').value = 'temp';" "document.getElementById('pa_password_field').value = 'random';" "document.getElementById('pa_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -2022,7 +2021,7 @@ "document.getElementById('pa_username_field').value = 'temp';" "document.getElementById('pa_password_field').value = 'random';" "document.getElementById('pa_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -2078,7 +2077,7 @@ "document.getElementById('chg_new_password_1').value = 'random1';" "document.getElementById('chg_new_password_2').value = 'random1';" "document.getElementById('chg_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -2096,7 +2095,7 @@ "document.getElementById('chg_new_password_1').value = 'random1';" "document.getElementById('chg_new_password_2').value = 'random1';" "document.getElementById('chg_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -2110,7 +2109,7 @@ PasswordsNavigationObserver dummy_submit_observer(WebContents()); std::string just_submit = "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), just_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), just_submit)); ASSERT_TRUE(dummy_submit_observer.Wait()); // Now go to a page with a form again, fill the form, and go back instead of @@ -2127,7 +2126,7 @@ "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click();" "window.history.back();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_back)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_back)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -2147,7 +2146,7 @@ "document.getElementById('username_field').value = 'mypass';" "document.getElementById('password_field').value = 'mypass';" "document.getElementById('testform').submit();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), change_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), change_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -2170,7 +2169,7 @@ "document.getElementById('security_answer').value = 'hometown';" "document.getElementById('SSN').value = '1234';" "document.getElementById('testform').submit();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -2191,7 +2190,7 @@ "frame_doc.getElementById('password_field').value = 'random';" "frame_doc.getElementById('submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); std::string message; while (message_queue.WaitForMessage(&message)) { if (message == "\"SUBMISSION_FINISHED\"") @@ -2337,7 +2336,7 @@ "ifrmDoc.getElementById('username_field').value = 'temp';" "ifrmDoc.getElementById('password_field').value = 'pa55w0rd';" "ifrmDoc.getElementById('input_submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit)); ASSERT_TRUE(observer.Wait()); BubbleObserver prompt_observer(WebContents()); prompt_observer.WaitForAutomaticSavePrompt(); @@ -2392,7 +2391,7 @@ "document.getElementById('chg_new_password_wo_username_2').value = " "'new_pw';" "document.getElementById('chg_submit_wo_username_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); // No credentials stored before, so save bubble is shown. EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); @@ -2427,8 +2426,7 @@ "document.getElementById('chg_new_password_wo_username_2').value = " "'new_pw';" "document.getElementById('chg_submit_wo_username_button').click()"; - ASSERT_TRUE( - content::ExecuteScript(WebContents(), fill_and_submit_change_password)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit_change_password)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsUpdatePromptShownAutomatically()); @@ -2474,7 +2472,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'new_pw';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); // The stored password "pw" was overridden with "new_pw", so update prompt is // expected. @@ -2506,7 +2504,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'pw';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); // The stored password "pw" was not overridden, so update prompt is not // expected. @@ -2529,7 +2527,7 @@ "document.getElementById('chg_new_password_wo_username_2').value = " "'pass3';" "document.getElementById('chg_submit_wo_username_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); // 3 possible passwords are going to be shown in a dropdown when the password // selection feature is enabled. The first one will be selected as the main @@ -2585,8 +2583,7 @@ "document.getElementById('chg_new_password_withtext_username_2').value" " = 'new_pw';" "document.getElementById('chg_submit_withtext_button').click()"; - ASSERT_TRUE( - content::ExecuteScript(WebContents(), fill_and_submit_change_password)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit_change_password)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsUpdatePromptShownAutomatically()); @@ -3029,7 +3026,7 @@ std::string fill_and_submit = "document.getElementById('retry_password_field').value = 'pw';" "document.getElementById('retry_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); prompt_observer.AcceptSavePrompt(); @@ -3064,7 +3061,7 @@ std::string fill_and_submit = "document.getElementById('retry_password_field').value = 'pw';" "document.getElementById('retry_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); EXPECT_FALSE(prompt_observer.IsUpdatePromptShownAutomatically()); @@ -3092,7 +3089,7 @@ std::string fill_and_submit = "document.getElementById('retry_password_field').value = 'new_pw';" "document.getElementById('retry_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); // The new password "new_pw" is used, so update prompt is expected. EXPECT_TRUE(prompt_observer.IsUpdatePromptShownAutomatically()); @@ -3122,8 +3119,9 @@ // Call the API to trigger the notification to the client, which raises the // account picker dialog. - ASSERT_TRUE(content::ExecuteScript( - WebContents(), "navigator.credentials.get({password: true})")); + ASSERT_TRUE(content::ExecJs(WebContents(), + "navigator.credentials.get({password: true})", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); // Navigate while the picker is open. NavigateToFile("/password/password_form.html"); @@ -3143,7 +3141,7 @@ "document.getElementById('username').value = 'temp';" "document.getElementById('password').value = 'random';" "document.getElementById('submit').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); } @@ -3168,9 +3166,10 @@ NavigateToFile("/password/password_form.html"); // Call the API to trigger the notification to the client. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), - "navigator.credentials.get({password: true, unmediated: true })")); + "navigator.credentials.get({password: true, unmediated: true })", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); PasswordsNavigationObserver observer(WebContents()); BubbleObserver prompt_observer(WebContents()); @@ -3178,8 +3177,7 @@ "document.getElementById('username_field').value = 'user';" "document.getElementById('password_field').value = 'password';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE( - content::ExecuteScript(WebContents(), fill_and_submit_change_password)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit_change_password)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); @@ -3220,8 +3218,7 @@ "document.getElementById('username_field').value = 'user';" "document.getElementById('password_field').value = 'password';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE( - content::ExecuteScript(WebContents(), fill_and_submit_change_password)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit_change_password)); ASSERT_TRUE(observer.Wait()); EXPECT_FALSE(prompt_observer.IsSavePromptShownAutomatically()); @@ -3323,7 +3320,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); } }; @@ -3370,8 +3367,8 @@ "var w = window.open('about:blank');" "w.document.body.innerHTML = \"" + form_html + "\";"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), - open_blank_popup_with_password_form)); + ASSERT_TRUE( + content::ExecJs(WebContents(), open_blank_popup_with_password_form)); tab_add.Wait(); ASSERT_EQ(2, browser()->tab_strip_model()->count()); content::WebContents* newtab = @@ -3450,8 +3447,8 @@ form_html + "\";\n" "document.body.appendChild(frame);\n"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), - inject_data_frame_with_password_form)); + ASSERT_TRUE( + content::ExecJs(WebContents(), inject_data_frame_with_password_form)); EXPECT_TRUE(content::WaitForLoadStop(WebContents())); content::RenderFrameHost* frame = ChildFrameAt(WebContents()->GetPrimaryMainFrame(), 0); @@ -3482,7 +3479,7 @@ "location.href = URL.createObjectURL(new Blob([\"" + form_html + "\"], { type: 'text/html' }));"; PasswordsNavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(WebContents(), navigate_to_blob_url)); + ASSERT_TRUE(content::ExecJs(WebContents(), navigate_to_blob_url)); ASSERT_TRUE(observer.Wait()); // Fill in the password and submit the form. This shouldn't bring up a save @@ -3490,7 +3487,7 @@ std::string fill_and_submit = "document.getElementById('password_field').value = 'random';" "document.getElementById('testform').submit();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); EXPECT_FALSE(BubbleObserver(WebContents()).IsSavePromptAvailable()); } @@ -3621,7 +3618,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'pw';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); BubbleObserver bubble_observer(WebContents()); EXPECT_TRUE(bubble_observer.IsSavePromptShownAutomatically()); @@ -3648,7 +3645,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'pw';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); BubbleObserver bubble_observer(WebContents()); EXPECT_FALSE(bubble_observer.IsSavePromptShownAutomatically()); @@ -3871,7 +3868,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), kFillAndSubmit)); + ASSERT_TRUE(content::ExecJs(WebContents(), kFillAndSubmit)); ASSERT_TRUE(observer.Wait()); // Test if submission is properly recorded. @@ -3902,7 +3899,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); // Save the password and check the store. @@ -4010,7 +4007,7 @@ "document.getElementById('password_field').value = 'new_pw';" "document.getElementById('input_submit_button').click()", helper_.gaia_username().c_str()); - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); } @@ -4051,7 +4048,7 @@ std::string fill_and_submit = "document.getElementById('retry_password_field').value = 'new_pw';" "document.getElementById('retry_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(prompt_observer.IsUpdatePromptShownAutomatically()); @@ -4553,7 +4550,7 @@ "document.getElementById('username_field').value = 'temp';" "document.getElementById('password_field').value = 'random';" "document.getElementById('input_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(render_frame_host, fill_and_submit)); + ASSERT_TRUE(content::ExecJs(render_frame_host, fill_and_submit)); // Since navigation from a prerendering page is disallowed, prerendering is // canceled. This also means that we should never make any calls to the mocked // driver. Since we've already set an expectation of no calls, this will be @@ -4570,7 +4567,7 @@ // After loading the primary page, try to submit the password. PasswordsNavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(WebContents(), fill_and_submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), fill_and_submit)); ASSERT_TRUE(observer.Wait()); // Saves the password and checks the store.
diff --git a/chrome/browser/password_manager/password_manager_interactive_test_base.cc b/chrome/browser/password_manager/password_manager_interactive_test_base.cc index 6bd5add8..b44c4704 100644 --- a/chrome/browser/password_manager/password_manager_interactive_test_base.cc +++ b/chrome/browser/password_manager/password_manager_interactive_test_base.cc
@@ -30,7 +30,7 @@ const std::string& element_id, const std::string& value, const std::string& expected_value) { - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( RenderFrameHost(), base::StringPrintf("document.getElementById('%s').focus();", element_id.c_str()))); @@ -113,7 +113,7 @@ if (!username_id.empty()) FillElementWithValue(username_id, kUsername); FillElementWithValue(password_id, kPassword); - ASSERT_TRUE(content::ExecuteScript(RenderFrameHost(), submission_script)); + ASSERT_TRUE(content::ExecJs(RenderFrameHost(), submission_script)); ASSERT_TRUE(observer.Wait()); WaitForPasswordStore(); @@ -143,9 +143,9 @@ SCOPED_TRACE(::testing::Message() << "SimulateUserDeletingFieldContent " << field_id); std::string focus("document.getElementById('" + field_id + "').focus();"); - ASSERT_TRUE(content::ExecuteScript(WebContents(), focus)); + ASSERT_TRUE(content::ExecJs(WebContents(), focus)); std::string select("document.getElementById('" + field_id + "').select();"); - ASSERT_TRUE(content::ExecuteScript(WebContents(), select)); + ASSERT_TRUE(content::ExecJs(WebContents(), select)); content::SimulateKeyPress(WebContents(), ui::DomKey::BACKSPACE, ui::DomCode::BACKSPACE, ui::VKEY_BACK, false, false, false, false);
diff --git a/chrome/browser/password_manager/password_manager_interactive_uitest.cc b/chrome/browser/password_manager/password_manager_interactive_uitest.cc index b654750..1f364c4 100644 --- a/chrome/browser/password_manager/password_manager_interactive_uitest.cc +++ b/chrome/browser/password_manager/password_manager_interactive_uitest.cc
@@ -108,7 +108,7 @@ BubbleObserver prompt_observer(WebContents()); std::string submit = "document.getElementById('input_submit_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit)); ASSERT_TRUE(navigation_observer.Wait()); EXPECT_TRUE(prompt_observer.IsSavePromptShownAutomatically()); prompt_observer.AcceptSavePrompt(); @@ -218,7 +218,7 @@ FillElementWithValue("username_field", "user"); FillElementWithValue("password_field", "1234"); PasswordsNavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(WebContents(), "send_xhr()")); + ASSERT_TRUE(content::ExecJs(WebContents(), "send_xhr()")); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); } @@ -235,7 +235,7 @@ FillElementWithValue("signup_password_field", "1234"); FillElementWithValue("confirmation_password_field", "1234"); PasswordsNavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(WebContents(), "send_xhr()")); + ASSERT_TRUE(content::ExecJs(WebContents(), "send_xhr()")); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); } @@ -250,7 +250,7 @@ FillElementWithValue("password_field", "1234"); PasswordsNavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(WebContents(), "send_fetch()")); + ASSERT_TRUE(content::ExecJs(WebContents(), "send_fetch()")); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); } @@ -275,7 +275,7 @@ FillElementWithValue("signup_password_field", "1234"); FillElementWithValue("confirmation_password_field", "1234"); PasswordsNavigationObserver observer(WebContents()); - ASSERT_TRUE(content::ExecuteScript(WebContents(), "send_fetch()")); + ASSERT_TRUE(content::ExecJs(WebContents(), "send_fetch()")); ASSERT_TRUE(observer.Wait()); EXPECT_TRUE(BubbleObserver(WebContents()).IsSavePromptShownAutomatically()); } @@ -370,7 +370,7 @@ EXPECT_EQ(4, controller->GetLineCount()); // Trigger user gesture so that autofill happens. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( WebContents(), "document.getElementById('username_field').click();")); WaitForElementValue("username_field", "admin"); @@ -433,7 +433,7 @@ FillElementWithValue("chg_new_password_2", "new_pw", "new_pw"); std::string submit = "document.getElementById('chg_clear_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit)); EXPECT_TRUE(prompt_observer->IsUpdatePromptShownAutomatically()); @@ -484,7 +484,7 @@ ? "document.getElementById('chg_clear_all_fields_button').click();" : "document.getElementById('chg_clear_some_fields_button').click()" ";"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit)); if (all_fields_cleared) EXPECT_TRUE(prompt_observer->IsUpdatePromptShownAutomatically()); @@ -542,7 +542,7 @@ : "document.getElementById('chg_clear_some_" "formless_fields_button').click();"; - ASSERT_TRUE(content::ExecuteScript(WebContents(), submit)); + ASSERT_TRUE(content::ExecJs(WebContents(), submit)); if (relevant_fields_cleared) { prompt_observer->WaitForAutomaticUpdatePrompt();
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java index 456d0f3..d04a26e 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -925,8 +925,6 @@ public static final String VERIFIED_DIGITAL_ASSET_LINKS = "verified_digital_asset_links"; - public static final String VIDEO_TUTORIALS_SHARE_URL_SET = "Chrome.VideoTutorials.ShareUrls"; - /** Key for deferred recording of list of uninstalled WebAPK packages. */ public static final String WEBAPK_UNINSTALLED_PACKAGES = "webapk_uninstalled_packages"; @@ -1123,7 +1121,6 @@ UMA_ON_RESUME_COUNTER, USB_NOTIFICATION_IDS, USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY, - VIDEO_TUTORIALS_SHARE_URL_SET, WEB_FEED_INTRO_LAST_SHOWN_TIME_MS, WEB_FEED_INTRO_WEB_FEED_ID_SHOWN_TIME_MS_PREFIX.pattern(), WEB_FEED_INTRO_WEB_FEED_ID_SHOWN_COUNT_PREFIX.pattern(),
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java index 5d88607..e09fe61 100644 --- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DeprecatedChromePreferenceKeys.java
@@ -42,6 +42,7 @@ "Chrome.RequestDesktopSiteGlobalSetting.DefaultEnabledShowMessage", "Chrome.RequestDesktopSiteGlobalSetting.OptInMessageShown", "Chrome.SigninPromo.NTPImpressions", + "Chrome.VideoTutorials.ShareUrls", "PersistedNotificationId", "PhysicalWeb.ActivityReferral", "PhysicalWeb.HasDeferredMetrics",
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc index 7861303..433c6f8 100644 --- a/chrome/browser/prefs/browser_prefs.cc +++ b/chrome/browser/prefs/browser_prefs.cc
@@ -246,7 +246,6 @@ #include "chrome/browser/media/android/cdm/media_drm_origin_id_manager.h" #include "chrome/browser/notifications/notification_channels_provider_android.h" #include "chrome/browser/ssl/known_interception_disclosure_infobar_delegate.h" -#include "chrome/browser/video_tutorials/prefs.h" #include "components/cdm/browser/media_drm_storage_impl.h" // nogncheck crbug.com/1125897 #include "components/content_creation/notes/core/note_prefs.h" #include "components/ntp_snippets/register_prefs.h" @@ -808,6 +807,14 @@ const char kSmartLockSigninAllowed[] = "smart_lock_signin.allowed"; #endif // BUILDFLAG(IS_CHROMEOS_ASH) +// Deprecated 05/2023 +#if BUILDFLAG(IS_ANDROID) +const char kVideoTutorialsPreferredLocaleKey[] = + "video_tutorials.perferred_locale"; +const char kVideoTutorialsLastUpdatedTimeKey[] = + "video_tutorials.last_updated_time"; +#endif // BUILDFLAG(IS_ANDROID) + // Register local state used only for migration (clearing or moving to a new // key). void RegisterLocalStatePrefsForMigration(PrefRegistrySimple* registry) { @@ -1108,6 +1115,13 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) registry->RegisterBooleanPref(kSmartLockSigninAllowed, false); #endif // BUILDFLAG(IS_CHROMEOS_ASH) + + // Deprecated 05/2023. +#if BUILDFLAG(IS_ANDROID) + registry->RegisterStringPref(kVideoTutorialsPreferredLocaleKey, + std::string()); + registry->RegisterTimePref(kVideoTutorialsLastUpdatedTimeKey, base::Time()); +#endif // BUILDFLAG(IS_ANDROID) } } // namespace @@ -1508,7 +1522,6 @@ RecentTabsPagePrefs::RegisterProfilePrefs(registry); usage_stats::UsageStatsBridge::RegisterProfilePrefs(registry); variations::VariationsService::RegisterProfilePrefs(registry); - video_tutorials::RegisterPrefs(registry); webapps::InstallPromptPrefs::RegisterLocalPrefs(registry); #else // BUILDFLAG(IS_ANDROID) bookmarks_webui::RegisterProfilePrefs(registry); @@ -2145,6 +2158,12 @@ profile_prefs->ClearPref(kSmartLockSigninAllowed); #endif // BUILDFLAG(IS_CHROMEOS_ASH) +// Added 05/2023. +#if BUILDFLAG(IS_ANDROID) + profile_prefs->ClearPref(kVideoTutorialsPreferredLocaleKey); + profile_prefs->ClearPref(kVideoTutorialsLastUpdatedTimeKey); +#endif // BUILDFLAG(IS_ANDROID + // Please don't delete the following line. It is used by PRESUBMIT.py. // END_MIGRATE_OBSOLETE_PROFILE_PREFS
diff --git a/chrome/browser/privacy_budget/identifiability_study_state.cc b/chrome/browser/privacy_budget/identifiability_study_state.cc index 40201f4..fd1c81d 100644 --- a/chrome/browser/privacy_budget/identifiability_study_state.cc +++ b/chrome/browser/privacy_budget/identifiability_study_state.cc
@@ -624,12 +624,6 @@ return false; } - // Don't report actively sampled surfaces as encountered surfaces. - if (ukm::SourceIdObj::FromInt64(source_id).GetType() == - ukm::SourceIdType::NO_URL_ID) { - return false; - } - return surface_encounters_.IsNewEncounter(source_id, surface.ToUkmMetricHash()); }
diff --git a/chrome/browser/privacy_budget/identifiability_study_state_unittest.cc b/chrome/browser/privacy_budget/identifiability_study_state_unittest.cc index d050716a..a5c0f02 100644 --- a/chrome/browser/privacy_budget/identifiability_study_state_unittest.cc +++ b/chrome/browser/privacy_budget/identifiability_study_state_unittest.cc
@@ -479,8 +479,8 @@ // The specific surface doesn't matter. EXPECT_TRUE(state.ShouldReportEncounteredSurface(ukm::AssignNewSourceId(), kRegularSurface1)); - EXPECT_FALSE(state.ShouldReportEncounteredSurface(ukm::NoURLSourceId(), - kRegularSurface1)); + EXPECT_TRUE(state.ShouldReportEncounteredSurface(ukm::NoURLSourceId(), + kRegularSurface1)); } // Test the mode in which only the meta experiment (i.e. reporting encountered
diff --git a/chrome/browser/profiles/profile_keyed_service_browsertest.cc b/chrome/browser/profiles/profile_keyed_service_browsertest.cc index fa13b63..f75bd2a6 100644 --- a/chrome/browser/profiles/profile_keyed_service_browsertest.cc +++ b/chrome/browser/profiles/profile_keyed_service_browsertest.cc
@@ -307,7 +307,6 @@ #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) "AboutSigninInternals", "AboutThisSiteServiceFactory", - "AccountInvestigator", "AccountReconcilor", "ActivityLog", "ActivityLogPrivateAPI", @@ -453,7 +452,6 @@ "PowerBookmarkService", "PrefWatcher", "PreferenceAPI", - "PrimaryAccountPolicyManager", #if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CUPS) "PrintingMetricsService", #endif // BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CUPS) @@ -495,8 +493,6 @@ "ShoppingService", "SidePanelService", "SigninErrorController", - "SigninManager", - "SigninProfileAttributesUpdater", "SiteDataCacheFacadeFactory", "SiteEngagementService", "SocketManager",
diff --git a/chrome/browser/profiles/profile_selections.cc b/chrome/browser/profiles/profile_selections.cc index 725d7b3..7ecd897d 100644 --- a/chrome/browser/profiles/profile_selections.cc +++ b/chrome/browser/profiles/profile_selections.cc
@@ -69,15 +69,6 @@ ProfileSelections::~ProfileSelections() = default; ProfileSelections::ProfileSelections(const ProfileSelections& other) = default; -ProfileSelections ProfileSelections::BuildForAllProfiles() { - return ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOwnInstance) - .WithGuest(ProfileSelection::kOwnInstance) - .WithSystem(ProfileSelection::kOwnInstance) - .WithAshInternals(ProfileSelection::kOwnInstance) - .Build(); -} - ProfileSelections ProfileSelections::BuildNoProfilesSelected() { return ProfileSelections::Builder() .WithRegular(ProfileSelection::kNone) @@ -110,14 +101,6 @@ .Build(); } -ProfileSelections ProfileSelections::BuildRedirectedToOriginal() { - return ProfileSelections::Builder() - .WithRegular(ProfileSelection::kRedirectedToOriginal) - .WithGuest(ProfileSelection::kRedirectedToOriginal) - .WithSystem(ProfileSelection::kRedirectedToOriginal) - .Build(); -} - Profile* ProfileSelections::ApplyProfileSelection(Profile* profile) const { DCHECK(profile);
diff --git a/chrome/browser/profiles/profile_selections.h b/chrome/browser/profiles/profile_selections.h index bab827bb..8eb8362 100644 --- a/chrome/browser/profiles/profile_selections.h +++ b/chrome/browser/profiles/profile_selections.h
@@ -38,6 +38,10 @@ // Regular profile, the Guest user-visible profile is off-the-record, the // Profile Picker uses the off-the-record System Profile. // Maps Profile types to `ProfileSelection`. +// +// You can use predefined builders listed below for easier usages. +// If you need non trivial behavior (for Guest or System profiles for example), +// you should write your own expanded version of the builder. class ProfileSelections { public: ProfileSelections(const ProfileSelections& other); @@ -93,17 +97,6 @@ // +---------+------------+------------+ static ProfileSelections BuildForRegularProfile(); - // All Profiles are selected. - // +---------+------------+------------+ - // | | Original | OTR | - // +---------+------------+------------+ - // | Regular | self | self | - // | Guest | self | self | - // | System | self | self | - // | Ash Int.| self | self | - // +---------+------------+------------+ - static ProfileSelections BuildForAllProfiles(); - // No Profiles are selected. // +---------+------------+------------+ // | | Original | OTR | @@ -147,18 +140,6 @@ // +---------+------------+------------+ static ProfileSelections BuildRedirectedInIncognito(); - // Redirects all OTR profiles to their original profiles. - // Includes all profile types (Regular, Guest and System). - // +---------+------------+------------+ - // | | Original | OTR | - // +---------+------------+------------+ - // | Regular | self | original | - // | Guest | self | original | - // | System | self | original | - // | Ash Int.| self | original | - // +---------+------------+------------+ - static ProfileSelections BuildRedirectedToOriginal(); - // Given a Profile and a ProfileSelection enum, returns the right profile // (can potentially return nullptr). Profile* ApplyProfileSelection(Profile* profile) const;
diff --git a/chrome/browser/profiles/profile_selections_unittest.cc b/chrome/browser/profiles/profile_selections_unittest.cc index a18c395..71b8470 100644 --- a/chrome/browser/profiles/profile_selections_unittest.cc +++ b/chrome/browser/profiles/profile_selections_unittest.cc
@@ -173,64 +173,6 @@ #endif // BUILDFLAG(IS_CHROMEOS_ASH) } -TEST_F(ProfileSelectionsTest, RedirectedToOriginal) { - ProfileSelections selections = ProfileSelections::BuildRedirectedToOriginal(); - - TestProfileSelection(selections, regular_profile(), regular_profile()); - TestProfileSelection(selections, incognito_profile(), regular_profile()); - - TestProfileSelection(selections, guest_profile(), guest_profile()); - TestProfileSelection(selections, guest_profile_otr(), guest_profile()); - -#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) - TestProfileSelection(selections, system_profile(), system_profile()); - TestProfileSelection(selections, system_profile_otr(), system_profile()); -#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) - -#if BUILDFLAG(IS_CHROMEOS_ASH) - TestProfileSelection(selections, signin_profile(), signin_profile()); - TestProfileSelection(selections, signin_profile_otr(), signin_profile()); - - TestProfileSelection(selections, lockscreen_profile(), lockscreen_profile()); - TestProfileSelection(selections, lockscreen_profile_otr(), - lockscreen_profile()); - - TestProfileSelection(selections, lockscreenapp_profile(), - lockscreenapp_profile()); - TestProfileSelection(selections, lockscreenapp_profile_otr(), - lockscreenapp_profile()); -#endif // BUILDFLAG(IS_CHROMEOS_ASH) -} - -TEST_F(ProfileSelectionsTest, ForAllProfiles) { - ProfileSelections selections = ProfileSelections::BuildForAllProfiles(); - - TestProfileSelection(selections, regular_profile(), regular_profile()); - TestProfileSelection(selections, incognito_profile(), incognito_profile()); - - TestProfileSelection(selections, guest_profile(), guest_profile()); - TestProfileSelection(selections, guest_profile_otr(), guest_profile_otr()); - -#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) - TestProfileSelection(selections, system_profile(), system_profile()); - TestProfileSelection(selections, system_profile_otr(), system_profile_otr()); -#endif // !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_ANDROID) - -#if BUILDFLAG(IS_CHROMEOS_ASH) - TestProfileSelection(selections, signin_profile(), signin_profile()); - TestProfileSelection(selections, signin_profile_otr(), signin_profile_otr()); - - TestProfileSelection(selections, lockscreen_profile(), lockscreen_profile()); - TestProfileSelection(selections, lockscreen_profile_otr(), - lockscreen_profile_otr()); - - TestProfileSelection(selections, lockscreenapp_profile(), - lockscreenapp_profile()); - TestProfileSelection(selections, lockscreenapp_profile_otr(), - lockscreenapp_profile_otr()); -#endif // BUILDFLAG(IS_CHROMEOS_ASH) -} - TEST_F(ProfileSelectionsTest, NoProfiles) { ProfileSelections selections = ProfileSelections::BuildNoProfilesSelected();
diff --git a/chrome/browser/referrer_policy_browsertest.cc b/chrome/browser/referrer_policy_browsertest.cc index a3f9ced..3655948e 100644 --- a/chrome/browser/referrer_policy_browsertest.cc +++ b/chrome/browser/referrer_policy_browsertest.cc
@@ -659,7 +659,7 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), https_server_.GetURL("/referrer_policy/referrer-policy-iframe.html"))); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( tab, std::string("var frame = document.createElement('iframe');frame.src ='") + embedded_test_server() @@ -680,7 +680,7 @@ // Reload the iframe. expected_title = u"reset"; title_watcher = std::make_unique<content::TitleWatcher>(tab, expected_title); - EXPECT_TRUE(content::ExecuteScript(tab, "document.title = 'reset'")); + EXPECT_TRUE(content::ExecJs(tab, "document.title = 'reset'")); EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle()); frame = content::FrameMatchingPredicate( tab->GetPrimaryPage(), @@ -688,7 +688,7 @@ expected_title = u"loaded"; title_watcher = std::make_unique<content::TitleWatcher>(tab, expected_title); - EXPECT_TRUE(content::ExecuteScript(frame, "location.reload()")); + EXPECT_TRUE(content::ExecJs(frame, "location.reload()")); EXPECT_EQ(expected_title, title_watcher->WaitAndGetTitle()); frame = content::FrameMatchingPredicate( tab->GetPrimaryPage(),
diff --git a/chrome/browser/renderer_context_menu/link_to_text_menu_observer_interactive_uitest.cc b/chrome/browser/renderer_context_menu/link_to_text_menu_observer_interactive_uitest.cc index d83ec1a..f959aa2 100644 --- a/chrome/browser/renderer_context_menu/link_to_text_menu_observer_interactive_uitest.cc +++ b/chrome/browser/renderer_context_menu/link_to_text_menu_observer_interactive_uitest.cc
@@ -93,7 +93,7 @@ auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); menu()->set_web_contents(web_contents); content::RenderFrameHost* main_frame = web_contents->GetPrimaryMainFrame(); - EXPECT_TRUE(ExecuteScript(main_frame, "window.focus();")); + EXPECT_TRUE(ExecJs(main_frame, "window.focus();")); } void TearDownOnMainThread() override { observer_.reset(); @@ -234,7 +234,7 @@ browser()->tab_strip_model()->GetActiveWebContents(); content::RenderFrameHost* main_frame_a = web_contents->GetPrimaryMainFrame(); content::RenderFrameHost* child_frame_b = ChildFrameAt(main_frame_a, 0); - EXPECT_TRUE(ExecuteScript(child_frame_b, "window.focus();")); + EXPECT_TRUE(ExecJs(child_frame_b, "window.focus();")); EXPECT_EQ(child_frame_b, web_contents->GetFocusedFrame()); menu()->set_web_contents(web_contents);
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc index 8446f85..e609fb2 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -1988,7 +1988,9 @@ void RenderViewContextMenu::AppendReadAnythingItem() { menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPEN_IN_READING_MODE, IDS_CONTENT_CONTEXT_READING_MODE); - menu_model_.SetIsNewFeatureAt(menu_model_.GetItemCount() - 1, true); + menu_model_.SetIsNewFeatureAt( + menu_model_.GetItemCount() - 1, + !content_type_->SupportsGroup(ContextMenuContentType::ITEM_GROUP_LINK)); } #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc index 46067532..b8fa08a2 100644 --- a/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc +++ b/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
@@ -476,10 +476,9 @@ // Prepare to load a pdf plugin inside. TestMimeHandlerViewGuest::RegisterTestGuestViewType( test_guest_view_manager_); - ASSERT_TRUE( - content::ExecuteScript(web_contents, - "var l = document.getElementById('link1');" - "l.click();")); + ASSERT_TRUE(content::ExecJs(web_contents, + "var l = document.getElementById('link1');" + "l.click();")); // Wait for the guest view of the PDF plugin to be created. auto* guest_view =
diff --git a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc index 5ebc4216..25691195 100644 --- a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc +++ b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
@@ -746,9 +746,9 @@ // backgrounded. WaitUntilBackgrounded(no_audio_process_, true, audio_process_, false); // Pause the audio and immediately switch to the no audio tab. - ASSERT_TRUE(content::ExecuteScript( - audio_tab_web_contents_.get(), - "document.getElementById('audioPlayer').pause();")); + ASSERT_TRUE( + content::ExecJs(audio_tab_web_contents_.get(), + "document.getElementById('audioPlayer').pause();")); ShowSingletonTab(no_audio_url_); // Wait until the no audio page is not backgrounded and the audio page is @@ -767,9 +767,9 @@ // Wait until the two pages are not backgrounded. WaitUntilBackgrounded(audio_process_, false, no_audio_process_, false); // Stop the audio. - ASSERT_TRUE(content::ExecuteScript( - audio_tab_web_contents_.get(), - "document.getElementById('audioPlayer').pause();")); + ASSERT_TRUE( + content::ExecJs(audio_tab_web_contents_.get(), + "document.getElementById('audioPlayer').pause();")); // Wait until the no audio page is not backgrounded and the audio page is // backgrounded. @@ -786,16 +786,16 @@ return; // Stop the audio. - ASSERT_TRUE(content::ExecuteScript( - audio_tab_web_contents_.get(), - "document.getElementById('audioPlayer').pause();")); + ASSERT_TRUE( + content::ExecJs(audio_tab_web_contents_.get(), + "document.getElementById('audioPlayer').pause();")); WaitUntilBackgrounded(no_audio_process_, false, audio_process_, true); // Start the audio from the backgrounded tab. ASSERT_TRUE( - content::ExecuteScript(audio_tab_web_contents_.get(), - "document.getElementById('audioPlayer').play();")); + content::ExecJs(audio_tab_web_contents_.get(), + "document.getElementById('audioPlayer').play();")); // Wait until the two pages are not backgrounded. WaitUntilBackgrounded(no_audio_process_, false, audio_process_, false);
diff --git a/chrome/browser/resources/PRESUBMIT.py b/chrome/browser/resources/PRESUBMIT.py index 4503c67..eef16f224 100644 --- a/chrome/browser/resources/PRESUBMIT.py +++ b/chrome/browser/resources/PRESUBMIT.py
@@ -159,7 +159,6 @@ 'chrome/browser/resources/omnibox/', 'chrome/browser/resources/settings/', 'chrome/browser/resources/tools/', - 'chrome/browser/resources/video_tutorials/', ] normalized_excluded_paths = []
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js index 0ede0c7d3..ac4152c 100644 --- a/chrome/browser/resources/chromeos/login/oobe.js +++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. -import './test_api/test_api.js'; + import './components/common_styles/oobe_flex_layout_styles.css.js'; import './components/api_keys_notice.js'; // clang-format on @@ -16,6 +16,7 @@ import {Oobe} from './cr_ui.js'; import * as OobeDebugger from './debug/debug.js'; +import * as OobeTestApi from './test_api/test_api.js'; import {loadTimeData} from './i18n_setup.js'; import { addScreensToMainContainer } from './login_ui_tools.js'; import {MultiTapDetector} from './multi_tap_detector.js'; @@ -74,6 +75,11 @@ OobeDebugger.DebuggerUI.getInstance().register(document.body); } + // Add the OOBE Test API + if (OobeTestApi.OobeApiProvider) { + window.OobeAPI = new OobeTestApi.OobeApiProvider(); + } + Oobe.initialize(); Oobe.readyForTesting = true; traceExecution(TraceEvent.OOBE_INITIALIZED);
diff --git a/chrome/browser/resources/chromeos/login/test_api/test_api.js b/chrome/browser/resources/chromeos/login/test_api/test_api.js index a0b0704..2d21623 100644 --- a/chrome/browser/resources/chromeos/login/test_api/test_api.js +++ b/chrome/browser/resources/chromeos/login/test_api/test_api.js
@@ -997,5 +997,3 @@ }; } } - -window.OobeAPI = new OobeApiProvider();
diff --git a/chrome/browser/resources/intro/lacros_app.html b/chrome/browser/resources/intro/lacros_app.html index 623a1ac9..df37002 100644 --- a/chrome/browser/resources/intro/lacros_app.html +++ b/chrome/browser/resources/intro/lacros_app.html
@@ -5,46 +5,27 @@ display: block; } - #header-container { - height: 244px; + .main-container { + height: calc(100vh - (var(--action-container-padding) + + var(--cr-button-height))); + width: 100vw; + } + + .content-container { + left: 50%; position: relative; - width: 100%; - } - - .tangible-sync-style #header-container { - height: unset; - position: unset; - width: unset; - } - - #banner { - background-image: url(images/lacros_intro_banner.svg); - background-position: center; - background-repeat: no-repeat; - background-size: auto; - height: 100%; - position: absolute; - top: 0; - width: 100%; - z-index: 0; + top: 50%; + transform: translate(-50%, -50%); } #avatar-container { - --avatar-size: 100px; - bottom: calc(var(--avatar-size)/-2); - height: var(--avatar-size); + height: var(--tangible-sync-style-avatar-size); left: 0; margin: auto; - position: absolute; - right: 0; - width: var(--avatar-size); - z-index: 1; - } - - .tangible-sync-style #avatar-container { - --avatar-size: var(--tangible-sync-style-avatar-size); - bottom: unset; position: relative; + right: 0; + width: var(--tangible-sync-style-avatar-size); + z-index: 1; } #avatar { @@ -55,60 +36,20 @@ } .work-badge { - --badge-width: 30px; --badge-offset: -6px; - border: 3px solid white; - border-radius: 50%; bottom: var(--badge-offset); - height: var(--badge-width); - inset-inline-end: var(--badge-offset); position: absolute; - width: var(--badge-width); - } - - .work-badge>iron-icon { - --work-icon-size: 20px; - background-color: var(--md-background-color); - border-radius: 50%; - box-shadow: 0 0 2px rgba(60, 64, 67, 0.12), 0 0 6px rgba(60, 64, 67, 0.15); - color: var(--google-grey-700); - height: var(--work-icon-size); - padding: calc((var(--badge-width) - var(--work-icon-size)) / 2); - width: var(--work-icon-size); } #text-container { --footer-margin: 40px; - font-size: 14px; - line-height: 20px; - margin-bottom: calc(48px + var(--footer-margin)); margin-inline: auto; - margin-top: 72px; text-align: center; - width: 382px; - } - - .tangible-sync-style #text-container { - font-size: unset; - line-height: unset; - margin: unset; - width: unset; - } - - .title { - font-size: 24px; - font-weight: 500; - line-height: 32px; - margin-bottom: 8px; - } - - .secondary { - color: var(--cr-secondary-text-color); } #info-box { align-items: center; - border: none; + border: 1px solid var(--google-grey-200); bottom: 0; color: var(--google-grey-700); display: flex; @@ -118,16 +59,12 @@ margin-inline: auto; margin-top: 32px; max-width: calc(100% - var(--buttons-container-max-width)); - padding: 24px 8px; + padding-bottom: 12px; padding-inline-end: 18px; - position: absolute; - width: 530px; - } - - .tangible-sync-style #info-box { - border: 1px solid var(--google-grey-200); - padding: 12px 0; + padding-inline-start: 0; + padding-top: 12px; position: relative; + width: 530px; } /* info-box is displayed as a flex-box. Because of that, the hidden property @@ -163,7 +100,6 @@ align-items: flex-end; bottom: 0; box-sizing: border-box; - column-gap: 8px; display: flex; flex-wrap: wrap-reverse; justify-content: flex-end; @@ -172,16 +108,6 @@ width: 100%; } - cr-button { - font-size: 1.16em; - margin: 5px 0; - min-width: 111px; - } - - .tangible-sync-style cr-button { - margin: unset; - } - .tangible-sync-style-left-banner { content: url(images/left_illustration.svg); } @@ -190,29 +116,13 @@ content: url(images/right_illustration.svg); } - .main-container.tangible-sync-style { - height: calc(100vh - (var(--action-container-padding) + - var(--cr-button-height))); - width: 100vw; - } - - .tangible-sync-style .content-container { - left: 50%; - position: relative; - top: 50%; - transform: translate(-50%, -50%); - } - @media (prefers-color-scheme: dark) { - .work-badge { + .tangible-sync-style .work-badge { + /* ".tangible-sync-style" is explicitly added to the selector to take + precedence over the one set in the shared CSS file. */ border-color: var(--md-background-color); } - .work-badge>iron-icon { - box-shadow: 0 0 2px rgba(60, 64, 67, 0.12), 0 0 6px rgba(60, 64, 67, 0.15); - color: white; - } - #info-box { color: var(--google-grey-100); } @@ -235,27 +145,21 @@ } </style> -<div class$="main-container - [[getTangibleSyncStyleClass_(isTangibleSyncEnabled_)]]"> - <img class="tangible-sync-style-left-banner" alt="" - hidden="[[!isTangibleSyncEnabled_]]"> - <img class="tangible-sync-style-right-banner" alt="" - hidden="[[!isTangibleSyncEnabled_]]"> +<div class="main-container tangible-sync-style"> + <img class="tangible-sync-style-left-banner" alt=""> + <img class="tangible-sync-style-right-banner" alt=""> <div class="content-container"> - <div id="header-container"> - <div id="banner" hidden="[[isTangibleSyncEnabled_]]"></div> - <div id="avatar-container"> - <img id="avatar" alt="" src="[[pictureUrl_]]"> - <div class="work-badge" hidden="[[!managementDisclaimer_]]"> - <iron-icon class="icon" icon="cr:domain"></iron-icon> - </div> + <div id="avatar-container"> + <img id="avatar" alt="" src="[[pictureUrl_]]"> + <div class="work-badge" hidden="[[!managementDisclaimer_]]"> + <iron-icon class="icon" icon="cr:domain"></iron-icon> </div> - </div> + </div> <div id="text-container"> <h2 class="title"> [[title_]] </h2> - <p class="subtitle" class="secondary"> + <p class="subtitle"> [[subtitle_]] </p> </div> @@ -268,9 +172,8 @@ </p> </div> </div> - </div> - <div class$="action-container - [[getTangibleSyncStyleClass_(isTangibleSyncEnabled_)]]"> +</div> +<div class="action-container tangible-sync-style"> <cr-button id="proceedButton" class="action-button" on-click="onProceed_" disabled="[[disableProceedButton_]]"> $i18n{proceedLabel}
diff --git a/chrome/browser/resources/intro/lacros_app.ts b/chrome/browser/resources/intro/lacros_app.ts index 13be7d3b..04f218c 100644 --- a/chrome/browser/resources/intro/lacros_app.ts +++ b/chrome/browser/resources/intro/lacros_app.ts
@@ -10,7 +10,6 @@ import {CrButtonElement} from 'chrome://resources/cr_elements/cr_button/cr_button.js'; import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js'; -import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {IntroBrowserProxy, IntroBrowserProxyImpl, LacrosIntroProfileInfo} from './browser_proxy.js'; @@ -52,11 +51,6 @@ type: Boolean, value: false, }, - - isTangibleSyncEnabled_: { - type: Boolean, - value: () => loadTimeData.getBoolean('isTangibleSyncEnabled'), - }, }; } @@ -73,7 +67,6 @@ private subtitle_: string; private managementDisclaimer_: string; private disableProceedButton_: boolean; - private isTangibleSyncEnabled_: boolean; private browserProxy_: IntroBrowserProxy = IntroBrowserProxyImpl.getInstance(); @@ -90,10 +83,6 @@ this.disableProceedButton_ = true; this.browserProxy_.continueWithAccount(); } - - private getTangibleSyncStyleClass_() { - return this.isTangibleSyncEnabled_ ? 'tangible-sync-style' : ''; - } } declare global {
diff --git a/chrome/browser/resources/side_panel/read_anything/app.html b/chrome/browser/resources/side_panel/read_anything/app.html index e7611a62..263608a 100644 --- a/chrome/browser/resources/side_panel/read_anything/app.html +++ b/chrome/browser/resources/side_panel/read_anything/app.html
@@ -23,6 +23,7 @@ } ::selection { background: var(--selection-color); + color: var(--google-grey-800); } @media (prefers-color-scheme: dark) { ::selection {
diff --git a/chrome/browser/resources/side_panel/shared/sp_shared_vars.css b/chrome/browser/resources/side_panel/shared/sp_shared_vars.css index 4388d2f6..2b8e40c4 100644 --- a/chrome/browser/resources/side_panel/shared/sp_shared_vars.css +++ b/chrome/browser/resources/side_panel/shared/sp_shared_vars.css
@@ -11,4 +11,8 @@ --sp-card-block-padding: 8px; --sp-card-inline-padding: 16px; --sp-card-gap: 12px; + + /* Override default WebUI vars from cr_shared_vars. */ + --cr-primary-text-color: var(--color-side-panel-card-primary-foreground); + --cr-secondary-text-color: var(--color-side-panel-card-secondary-foreground); }
diff --git a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.ts b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.ts index 1022a4a..c80604a 100644 --- a/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.ts +++ b/chrome/browser/resources/signin/profile_picker/profile_creation_flow/profile_type_choice.ts
@@ -150,7 +150,7 @@ } private handleLoadSigninFinished_(_success: boolean) { - // TODO(crbug.com/1126913): If failed, show some error message to inform the + // TODO(crbug.com/1444046): If failed, show some error message to inform the // user. this.profileCreationInProgress = false; }
diff --git a/chrome/browser/resources/video_tutorials/BUILD.gn b/chrome/browser/resources/video_tutorials/BUILD.gn deleted file mode 100644 index 5a59b55d..0000000 --- a/chrome/browser/resources/video_tutorials/BUILD.gn +++ /dev/null
@@ -1,11 +0,0 @@ -# Copyright 2020 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//tools/typescript/ts_library.gni") - -ts_library("build_ts") { - root_dir = "." - out_dir = "$target_gen_dir/tsc" - in_files = [ "video_player.ts" ] -}
diff --git a/chrome/browser/resources/video_tutorials/DIR_METADATA b/chrome/browser/resources/video_tutorials/DIR_METADATA deleted file mode 100644 index 00888370..0000000 --- a/chrome/browser/resources/video_tutorials/DIR_METADATA +++ /dev/null
@@ -1 +0,0 @@ -mixins: "//chrome/browser/video_tutorials/COMMON_METADATA"
diff --git a/chrome/browser/resources/video_tutorials/OWNERS b/chrome/browser/resources/video_tutorials/OWNERS deleted file mode 100644 index 36c3bec..0000000 --- a/chrome/browser/resources/video_tutorials/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://chrome/browser/video_tutorials/OWNERS
diff --git a/chrome/browser/resources/video_tutorials/video_player.css b/chrome/browser/resources/video_tutorials/video_player.css deleted file mode 100644 index 2e66730..0000000 --- a/chrome/browser/resources/video_tutorials/video_player.css +++ /dev/null
@@ -1,27 +0,0 @@ -/* Copyright 2020 The Chromium Authors - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -html, -body { - background-color: black; - height: 100%; - margin: 0; -} - -video { - height: 100%; - width: 100%; -} - -.video-ended { - height: 50%; - left: 25%; - position: absolute; - top: 15%; - width: 50%; -} - -video::-webkit-media-controls-fullscreen-button { - display: none !important; -}
diff --git a/chrome/browser/resources/video_tutorials/video_player.html b/chrome/browser/resources/video_tutorials/video_player.html deleted file mode 100644 index 615f363..0000000 --- a/chrome/browser/resources/video_tutorials/video_player.html +++ /dev/null
@@ -1,23 +0,0 @@ -<!doctype html> -<html> - <head> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta http-equiv="Cache-Control" - content="no-cache, no-store, must-revalidate"> - <meta http-equiv="Pragma" content="no-cache"> - <meta http-equiv="Expires" content="0"> - - <link rel="stylesheet" href="video_player.css"> - <script type="module" src="video_player.js"></script> - </head> - - <body> - <video id="video" preload="metadata" controls disablePictureInPicture - controlsList="nodownload nofullscreen noremoteplayback"> - <source type="video/mp4"></source> - <track id="track" label="English" kind="captions" srclang="en-us" - mode="showing" default > - </video> - </body> -</html> -
diff --git a/chrome/browser/resources/video_tutorials/video_player.ts b/chrome/browser/resources/video_tutorials/video_player.ts deleted file mode 100644 index 6bf90bb..0000000 --- a/chrome/browser/resources/video_tutorials/video_player.ts +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -function onDocumentLoaded() { - // Find out the video, image, and caption urls from the url params. - const urlParams = new URLSearchParams(window.location.search); - video!.src = urlParams.get('video_url') || ''; - video!.poster = urlParams.get('poster_url') || ''; - track!.src = urlParams.get('caption_url') || ''; - video!.play(); -} - -function onVideoEnded() { - // Resize the poster. - video!.classList.add('video-ended'); - video!.controls = false; -} - -const video = document.querySelector('video'); -const track = document.querySelector('track'); -if (!video || !track) { - throw new Error('Failed to find video or track'); -} -video.addEventListener('ended', onVideoEnded); -document.addEventListener('DOMContentLoaded', onDocumentLoaded);
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc index f51eee8..e230421 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
@@ -689,7 +689,7 @@ std::string script = "var node = document.getElementById('reset-password-button'); \n" "node.click();"; - ASSERT_TRUE(content::ExecuteScript(new_web_contents, script)); + ASSERT_TRUE(content::ExecJs(new_web_contents, script)); content::TestNavigationObserver observer1(new_web_contents, /*number_of_navigations=*/1); observer1.Wait();
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_sync_browsertest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_sync_browsertest.cc index 549ceec..8511312 100644 --- a/chrome/browser/safe_browsing/chrome_password_protection_service_sync_browsertest.cc +++ b/chrome/browser/safe_browsing/chrome_password_protection_service_sync_browsertest.cc
@@ -143,7 +143,7 @@ std::string script = "var node = document.getElementById('reset-password-button'); \n" "node.click();"; - ASSERT_TRUE(content::ExecuteScript(interstitial_web_contents, script)); + ASSERT_TRUE(content::ExecJs(interstitial_web_contents, script)); content::TestNavigationObserver observer1(interstitial_web_contents, /*number_of_navigations=*/1); observer1.Wait();
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc index a19e3f9..b0dc1486 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -2084,7 +2084,7 @@ browser->tab_strip_model()->GetActiveWebContents(); content::TestNavigationObserver observer(contents); const char* const kScript = "document.body.webkitRequestFullscreen()"; - EXPECT_TRUE(content::ExecuteScript(contents, kScript)); + EXPECT_TRUE(content::ExecJs(contents, kScript)); observer.WaitForNavigationFinished(); return WaitForReady(browser); } @@ -2094,7 +2094,7 @@ browser->tab_strip_model()->GetActiveWebContents(); content::TestNavigationObserver observer(contents); const char* const kScript = "Notification.requestPermission(function(){})"; - EXPECT_TRUE(content::ExecuteScript(contents, kScript)); + EXPECT_TRUE(content::ExecJs(contents, kScript)); observer.WaitForNavigationFinished(); return WaitForReady(browser); } @@ -2104,7 +2104,8 @@ browser->tab_strip_model()->GetActiveWebContents(); content::TestNavigationObserver observer(contents); const char* const kScript = "navigator.mediaDevices.getDisplayMedia()"; - EXPECT_TRUE(content::ExecuteScript(contents, kScript)); + EXPECT_TRUE(content::ExecJs(contents, kScript, + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); observer.WaitForNavigationFinished(); return WaitForReady(browser); } @@ -2519,7 +2520,7 @@ content::WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents(); content::TestNavigationObserver observer(contents); - EXPECT_TRUE(content::ExecuteScript(contents, "alert('test')")); + EXPECT_TRUE(content::ExecJs(contents, "alert('test')")); observer.WaitForNavigationFinished(); EXPECT_TRUE(WaitForReady(browser())); @@ -2666,7 +2667,7 @@ std::string fill_and_submit = "document.getElementById('retry_password_field').value = 'pw';" "document.getElementById('retry_submit_button').click()"; - ASSERT_TRUE(content::ExecuteScript(contents, fill_and_submit)); + ASSERT_TRUE(content::ExecJs(contents, fill_and_submit)); ASSERT_TRUE(observer2.Wait()); EXPECT_FALSE(prompt_observer->IsSavePromptShownAutomatically()); PasswordManagerBrowserTestBase::WaitForPasswordStore(browser());
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc index ad720db..351766fb 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -266,7 +266,7 @@ script_executing_frame = ChildFrameAt(script_executing_frame, subframe_index); } - ASSERT_TRUE(content::ExecuteScript(script_executing_frame, script)); + ASSERT_TRUE(content::ExecJs(script_executing_frame, script)); } // Wait for navigations on current tab and new tab (if any) to finish. navigation_observer.Wait(); @@ -274,7 +274,7 @@ // Since this test uses javascript to mimic clicking on a link (no actual // user gesture), and DidGetUserInteraction() does not respond to - // ExecuteScript(), navigation_transition field in resulting + // ExecJs(), navigation_transition field in resulting // NavigationEvents will always be RENDERER_INITIATED_WITHOUT_USER_GESTURE. // Therefore, we need to make some adjustment to relevant NavigationEvent. for (std::size_t i = 0U; @@ -307,12 +307,12 @@ script_executing_frame = ChildFrameAt(script_executing_frame, subframe_index); } - ASSERT_TRUE(content::ExecuteScript(script_executing_frame, script)); + ASSERT_TRUE(content::ExecJs(script_executing_frame, script)); } // Since this test uses javascript to mimic clicking on a link (no actual // user gesture), and DidGetUserInteraction() does not respond to - // ExecuteScript(), navigation_transition field in resulting + // ExecJs(), navigation_transition field in resulting // NavigationEvents will always be RENDERER_INITIATED_WITHOUT_USER_GESTURE. // Therefore, we need to make some adjustment to relevant // PendingNavigationEvent. @@ -331,8 +331,7 @@ browser()->profile()->GetDownloadManager(); content::WebContents* current_web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - ASSERT_TRUE( - content::ExecuteScript(current_web_contents, "downloadViaFileApi()")); + ASSERT_TRUE(content::ExecJs(current_web_contents, "downloadViaFileApi()")); manager->GetAllDownloads(&items); ASSERT_EQ(0U, items.size()); } @@ -2950,15 +2949,15 @@ EXPECT_EQ(3U, nav_list->NavigationEventsSize()); // Simulates back. - ASSERT_TRUE(content::ExecuteScript( - browser()->tab_strip_model()->GetActiveWebContents(), - "window.history.back();")); + ASSERT_TRUE( + content::ExecJs(browser()->tab_strip_model()->GetActiveWebContents(), + "window.history.back();")); base::RunLoop().RunUntilIdle(); // Simulates forward. - ASSERT_TRUE(content::ExecuteScript( - browser()->tab_strip_model()->GetActiveWebContents(), - "window.history.forward();")); + ASSERT_TRUE( + content::ExecJs(browser()->tab_strip_model()->GetActiveWebContents(), + "window.history.forward();")); base::RunLoop().RunUntilIdle(); nav_list = navigation_event_list(); @@ -2976,9 +2975,9 @@ EXPECT_EQ(1U, nav_list->NavigationEventsSize()); // Simulates reload. - ASSERT_TRUE(content::ExecuteScript( - browser()->tab_strip_model()->GetActiveWebContents(), - "location.reload();")); + ASSERT_TRUE( + content::ExecJs(browser()->tab_strip_model()->GetActiveWebContents(), + "location.reload();")); base::RunLoop().RunUntilIdle(); nav_list = navigation_event_list(); @@ -3003,9 +3002,9 @@ GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), initial_url)); - ASSERT_TRUE(content::ExecuteScript( - browser()->tab_strip_model()->GetActiveWebContents(), - "window.location='../signed.exe'")); + ASSERT_TRUE( + content::ExecJs(browser()->tab_strip_model()->GetActiveWebContents(), + "window.location='../signed.exe'")); base::RunLoop().RunUntilIdle(); ReferrerChain referrer_chain;
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index 12e0264..cf6bb93 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -3998,7 +3998,7 @@ "meta.name = 'referrer';" "meta.content = 'no-referrer';" "document.head.appendChild(meta)"; - EXPECT_TRUE(content::ExecuteScript(contents, kNoReferrerJS)); + EXPECT_TRUE(content::ExecJs(contents, kNoReferrerJS)); // Navigate the tab to url 3. ui_test_utils::NavigateToURLWithDisposition(
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java index 351c877..03c3f8ff 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/share_sheet/ShareSheetBottomSheetContentTest.java
@@ -39,7 +39,6 @@ import org.chromium.base.test.util.Batch; import org.chromium.chrome.R; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.share.ChromeShareExtras.DetailedContentType; import org.chromium.chrome.browser.share.ShareContentTypeHelper.ContentType; @@ -283,7 +282,6 @@ @Test @MediumTest - @Features.DisableFeatures({ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS}) public void createRecyclerViews_toggleOff_showsIph() { String fileContentType = "image/gif"; ShareSheetBottomSheetContent shareSheetBottomSheetContent =
diff --git a/chrome/browser/signin/account_investigator_factory.cc b/chrome/browser/signin/account_investigator_factory.cc index a08ac36..9727193 100644 --- a/chrome/browser/signin/account_investigator_factory.cc +++ b/chrome/browser/signin/account_investigator_factory.cc
@@ -25,14 +25,7 @@ } AccountInvestigatorFactory::AccountInvestigatorFactory() - : ProfileKeyedServiceFactory( - "AccountInvestigator", - ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOriginalOnly) - // TODO(crbug.com/1418376): Check if this service is needed in - // Guest mode. - .WithGuest(ProfileSelection::kOriginalOnly) - .Build()) { + : ProfileKeyedServiceFactory("AccountInvestigator") { DependsOn(IdentityManagerFactory::GetInstance()); }
diff --git a/chrome/browser/signin/dice_response_handler.cc b/chrome/browser/signin/dice_response_handler.cc index 9ce8582..5fef0aca 100644 --- a/chrome/browser/signin/dice_response_handler.cc +++ b/chrome/browser/signin/dice_response_handler.cc
@@ -126,14 +126,7 @@ friend struct base::DefaultSingletonTraits<DiceResponseHandlerFactory>; DiceResponseHandlerFactory() - : ProfileKeyedServiceFactory( - "DiceResponseHandler", - ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOriginalOnly) - // TODO(crbug.com/1418376): Check if this service is needed in - // Guest mode. - .WithGuest(ProfileSelection::kOriginalOnly) - .Build()) { + : ProfileKeyedServiceFactory("DiceResponseHandler") { DependsOn(AboutSigninInternalsFactory::GetInstance()); DependsOn(AccountReconcilorFactory::GetInstance()); DependsOn(ChromeSigninClientFactory::GetInstance());
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_factory.cc b/chrome/browser/signin/dice_web_signin_interceptor_factory.cc index 77218a93..47350bba 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_factory.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_factory.cc
@@ -23,14 +23,7 @@ } DiceWebSigninInterceptorFactory::DiceWebSigninInterceptorFactory() - : ProfileKeyedServiceFactory( - "DiceWebSigninInterceptor", - ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOriginalOnly) - // TODO(crbug.com/1418376): Check if this service is needed in - // Guest mode. - .WithGuest(ProfileSelection::kOriginalOnly) - .Build()) { + : ProfileKeyedServiceFactory("DiceWebSigninInterceptor") { DependsOn(IdentityManagerFactory::GetInstance()); }
diff --git a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc index e8a015a..b87c5a1 100644 --- a/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc +++ b/chrome/browser/signin/dice_web_signin_interceptor_unittest.cc
@@ -444,6 +444,10 @@ sync_promo_enabled_(std::get<1>(GetParam())) { if (sync_promo_enabled_) { scoped_feature_list_.InitAndEnableFeature(kSyncPromoAfterSigninIntercept); + } else { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{}, /*disabled_features=*/{ + kSigninInterceptBubbleV2, kSyncPromoAfterSigninIntercept}); } } @@ -738,6 +742,10 @@ : sync_promo_enabled_(GetParam()) { if (sync_promo_enabled_) { scoped_feature_list_.InitAndEnableFeature(kSyncPromoAfterSigninIntercept); + } else { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{}, /*disabled_features=*/{ + kSigninInterceptBubbleV2, kSyncPromoAfterSigninIntercept}); } }
diff --git a/chrome/browser/signin/e2e_tests/live_sign_in_test.cc b/chrome/browser/signin/e2e_tests/live_sign_in_test.cc index 9d360d7..b83c2d5 100644 --- a/chrome/browser/signin/e2e_tests/live_sign_in_test.cc +++ b/chrome/browser/signin/e2e_tests/live_sign_in_test.cc
@@ -270,7 +270,7 @@ "settings.SyncBrowserProxyImpl.getInstance()." "startSyncingWithEmail(\"%s\", true);", test_account.user.c_str()); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( settings_tab, base::StringPrintf(kSettingsScriptWrapperFormat, start_syncing_script.c_str()))); EXPECT_TRUE(login_ui_test_utils::CancelSyncConfirmationDialog(
diff --git a/chrome/browser/signin/e2e_tests/signin_util.cc b/chrome/browser/signin/e2e_tests/signin_util.cc index 724835d..0dbdba8 100644 --- a/chrome/browser/signin/e2e_tests/signin_util.cc +++ b/chrome/browser/signin/e2e_tests/signin_util.cc
@@ -65,7 +65,7 @@ ui::PageTransition::PAGE_TRANSITION_TYPED)); ui_test_utils::TabAddedWaiter signin_tab_waiter(browser); auto* settings_tab = browser->tab_strip_model()->GetActiveWebContents(); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( settings_tab, base::StringPrintf( kSettingsScriptWrapperFormat, @@ -117,7 +117,7 @@ account_reconcilor(browser_.Run())); auto* settings_tab = browser_.Run()->tab_strip_model()->GetActiveWebContents(); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( settings_tab, base::StringPrintf( kSettingsScriptWrapperFormat,
diff --git a/chrome/browser/signin/primary_account_policy_manager_factory.cc b/chrome/browser/signin/primary_account_policy_manager_factory.cc index 0c7596e..9b734da 100644 --- a/chrome/browser/signin/primary_account_policy_manager_factory.cc +++ b/chrome/browser/signin/primary_account_policy_manager_factory.cc
@@ -24,14 +24,7 @@ } PrimaryAccountPolicyManagerFactory::PrimaryAccountPolicyManagerFactory() - : ProfileKeyedServiceFactory( - "PrimaryAccountPolicyManager", - ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOriginalOnly) - // TODO(crbug.com/1418376): Check if this service is needed in - // Guest mode. - .WithGuest(ProfileSelection::kOriginalOnly) - .Build()) { + : ProfileKeyedServiceFactory("PrimaryAccountPolicyManager") { DependsOn(IdentityManagerFactory::GetInstance()); DependsOn(ChromeSigninClientFactory::GetInstance()); }
diff --git a/chrome/browser/signin/signin_features.cc b/chrome/browser/signin/signin_features.cc index a21f974e..71288ef 100644 --- a/chrome/browser/signin/signin_features.cc +++ b/chrome/browser/signin/signin_features.cc
@@ -65,16 +65,17 @@ "ProcessGaiaRemoveLocalAccountHeader", base::FEATURE_ENABLED_BY_DEFAULT); -// Enables the sync promo after the sign-in intercept. +// Enables the sync promo after the sign-in intercept. Fully rolled out on +// Desktop. BASE_FEATURE(kSyncPromoAfterSigninIntercept, "SyncPromoAfterSigninIntercept", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables using new style (strings, illustration, and disclaimer if needed) -// for the sign-in intercept bubble. +// for the sign-in intercept bubble. Fully rolled out on Desktop. BASE_FEATURE(kSigninInterceptBubbleV2, "SigninInterceptBubbleV2", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables showing the enterprise dialog after every signin into a managed // account.
diff --git a/chrome/browser/signin/signin_manager_factory.cc b/chrome/browser/signin/signin_manager_factory.cc index fedece2..f9f56ed 100644 --- a/chrome/browser/signin/signin_manager_factory.cc +++ b/chrome/browser/signin/signin_manager_factory.cc
@@ -24,14 +24,7 @@ } SigninManagerFactory::SigninManagerFactory() - : ProfileKeyedServiceFactory( - "SigninManager", - ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOriginalOnly) - // TODO(crbug.com/1418376): Check if this service is needed in - // Guest mode. - .WithGuest(ProfileSelection::kOriginalOnly) - .Build()) { + : ProfileKeyedServiceFactory("SigninManager") { DependsOn(IdentityManagerFactory::GetInstance()); DependsOn(ChromeSigninClientFactory::GetInstance()); }
diff --git a/chrome/browser/signin/signin_profile_attributes_updater_factory.cc b/chrome/browser/signin/signin_profile_attributes_updater_factory.cc index d38f5d14..c4273ab9 100644 --- a/chrome/browser/signin/signin_profile_attributes_updater_factory.cc +++ b/chrome/browser/signin/signin_profile_attributes_updater_factory.cc
@@ -24,14 +24,7 @@ } SigninProfileAttributesUpdaterFactory::SigninProfileAttributesUpdaterFactory() - : ProfileKeyedServiceFactory( - "SigninProfileAttributesUpdater", - ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOriginalOnly) - // TODO(crbug.com/1418376): Check if this service is needed in - // Guest mode. - .WithGuest(ProfileSelection::kOriginalOnly) - .Build()) { + : ProfileKeyedServiceFactory("SigninProfileAttributesUpdater") { DependsOn(IdentityManagerFactory::GetInstance()); }
diff --git a/chrome/browser/site_isolation/chrome_site_isolation_policy_unittest.cc b/chrome/browser/site_isolation/chrome_site_isolation_policy_unittest.cc index 5e97427..b658c9e 100644 --- a/chrome/browser/site_isolation/chrome_site_isolation_policy_unittest.cc +++ b/chrome/browser/site_isolation/chrome_site_isolation_policy_unittest.cc
@@ -9,6 +9,7 @@ #include "base/system/sys_info.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" +#include "chrome/browser/chrome_content_browser_client.h" #include "chrome/common/chrome_features.h" #include "components/site_isolation/features.h" #include "components/site_isolation/preloaded_isolated_origins.h" @@ -115,9 +116,11 @@ // built-in origins. std::vector<url::Origin> expected_embedder_origins = site_isolation::GetBrowserSpecificBuiltInIsolatedOrigins(); -#if !BUILDFLAG(IS_ANDROID) - expected_embedder_origins.push_back(GaiaUrls::GetInstance()->gaia_origin()); -#endif + + if (ChromeContentBrowserClient::DoesGaiaOriginRequireDedicatedProcess()) { + expected_embedder_origins.push_back(GaiaUrls::GetInstance()->gaia_origin()); + } + #if BUILDFLAG(ENABLE_EXTENSIONS) expected_embedder_origins.push_back( url::Origin::Create(extension_urls::GetWebstoreLaunchURL()));
diff --git a/chrome/browser/storage_access_api/api_browsertest.cc b/chrome/browser/storage_access_api/api_browsertest.cc index 41189f0..ca333ad4 100644 --- a/chrome/browser/storage_access_api/api_browsertest.cc +++ b/chrome/browser/storage_access_api/api_browsertest.cc
@@ -306,7 +306,7 @@ content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); content::TestNavigationObserver load_observer(web_contents); - ASSERT_TRUE(ExecuteScript( + ASSERT_TRUE(ExecJs( GetFrame(), base::StringPrintf("document.body.querySelector('iframe').src = '%s';", url.spec().c_str()))); @@ -814,9 +814,9 @@ SetBlockThirdPartyCookies(true); NavigateToPageWithFrame(kHostA); - ASSERT_TRUE(ExecuteScript( - GetPrimaryMainFrame(), - "document.querySelector('iframe').sandbox='allow-scripts';")); + ASSERT_TRUE( + ExecJs(GetPrimaryMainFrame(), + "document.querySelector('iframe').sandbox='allow-scripts';")); NavigateFrameTo(EchoCookiesURL(kHostB)); EXPECT_FALSE(storage::test::HasStorageAccessForFrame(GetFrame())); @@ -833,9 +833,9 @@ SetBlockThirdPartyCookies(true); NavigateToPageWithFrame(kHostA); - ASSERT_TRUE(ExecuteScript(GetPrimaryMainFrame(), - "document.querySelector('iframe').sandbox='allow-" - "scripts allow-same-origin';")); + ASSERT_TRUE(ExecJs(GetPrimaryMainFrame(), + "document.querySelector('iframe').sandbox='allow-" + "scripts allow-same-origin';")); NavigateFrameTo(EchoCookiesURL(kHostB)); EXPECT_FALSE(storage::test::HasStorageAccessForFrame(GetFrame())); @@ -851,10 +851,10 @@ SetBlockThirdPartyCookies(true); NavigateToPageWithFrame(kHostA); - ASSERT_TRUE(ExecuteScript( - GetPrimaryMainFrame(), - "document.querySelector('iframe').sandbox='allow-scripts " - "allow-same-origin allow-storage-access-by-user-activation';")); + ASSERT_TRUE( + ExecJs(GetPrimaryMainFrame(), + "document.querySelector('iframe').sandbox='allow-scripts " + "allow-same-origin allow-storage-access-by-user-activation';")); NavigateFrameTo(EchoCookiesURL(kHostB)); EXPECT_FALSE(storage::test::HasStorageAccessForFrame(GetFrame()));
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc index 8ed8ec8..75cc36e0a 100644 --- a/chrome/browser/sync/sync_ui_util.cc +++ b/chrome/browser/sync/sync_ui_util.cc
@@ -103,8 +103,7 @@ // Check to see if sync has been disabled via the dashboard and needs to be // set up once again. - if (service->HasDisableReason( - syncer::SyncService::DISABLE_REASON_USER_CHOICE)) { + if (service->IsSyncFeatureDisabledViaDashboard()) { return {SyncStatusMessageType::kSyncError, IDS_SIGNED_IN_WITH_SYNC_STOPPED_VIA_DASHBOARD, IDS_SETTINGS_EMPTY_STRING, SyncStatusActionType::kNoAction};
diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc index 5a430dd8..d36d09ffc 100644 --- a/chrome/browser/sync/sync_ui_util_unittest.cc +++ b/chrome/browser/sync/sync_ui_util_unittest.cc
@@ -200,6 +200,7 @@ // dashboard, and the UI treats it as such. service->SetDisableReasons( syncer::SyncService::DISABLE_REASON_USER_CHOICE); + service->SetSyncFeatureDisabledViaDashboard(true); service->SetFirstSetupComplete(true); service->SetTransportState(syncer::SyncService::TransportState::ACTIVE); service->SetPassphraseRequired(false);
diff --git a/chrome/browser/tab_contents/navigation_metrics_recorder_browsertest.cc b/chrome/browser/tab_contents/navigation_metrics_recorder_browsertest.cc index a1bb16fb..5c3e027b 100644 --- a/chrome/browser/tab_contents/navigation_metrics_recorder_browsertest.cc +++ b/chrome/browser/tab_contents/navigation_metrics_recorder_browsertest.cc
@@ -97,7 +97,7 @@ base::HistogramTester histograms; content::TestNavigationObserver observer(web_contents); const char* const kScript = "document.getElementById('form').submit()"; - EXPECT_TRUE(content::ExecuteScript(web_contents, kScript)); + EXPECT_TRUE(content::ExecJs(web_contents, kScript)); observer.WaitForNavigationFinished(); histograms.ExpectTotalCount(
diff --git a/chrome/browser/tab_contents/view_source_browsertest.cc b/chrome/browser/tab_contents/view_source_browsertest.cc index 88fc36d8..3fca0cb 100644 --- a/chrome/browser/tab_contents/view_source_browsertest.cc +++ b/chrome/browser/tab_contents/view_source_browsertest.cc
@@ -184,9 +184,8 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url_viewsource)); observer.Wait(); - ASSERT_TRUE( - content::ExecuteScript(browser()->tab_strip_model()->GetWebContentsAt(0), - "window.location.reload();")); + ASSERT_TRUE(content::ExecJs(browser()->tab_strip_model()->GetWebContentsAt(0), + "window.location.reload();")); content::LoadStopObserver observer2( browser()->tab_strip_model()->GetWebContentsAt(0)); @@ -214,9 +213,9 @@ GURL url = embedded_test_server()->GetURL("a.com", "/title1.html"); ui_test_utils::UrlLoadObserver load_complete( url, content::NotificationService::AllSources()); - EXPECT_TRUE(content::ExecuteScript( - browser()->tab_strip_model()->GetActiveWebContents(), - "window.open('" + url.spec() + "');")); + EXPECT_TRUE( + content::ExecJs(browser()->tab_strip_model()->GetActiveWebContents(), + "window.open('" + url.spec() + "');")); load_complete.Wait(); EXPECT_EQ(2, browser()->tab_strip_model()->count()); } @@ -344,8 +343,8 @@ // Submit the form and verify that we arrived at the expected location. content::TestNavigationObserver form_post_observer(original_contents, 1); - EXPECT_TRUE(ExecuteScript(original_main_frame, - "document.getElementById('form').submit();")); + EXPECT_TRUE( + ExecJs(original_main_frame, "document.getElementById('form').submit();")); form_post_observer.Wait(); GURL target_url(embedded_test_server()->GetURL("a.com", "/echoall")); @@ -536,8 +535,8 @@ // Submit the form and verify that we arrived at the expected location. content::TestNavigationObserver form_post_observer(original_contents, 1); - EXPECT_TRUE(ExecuteScript(original_child_frame, - "document.getElementById('form').submit();")); + EXPECT_TRUE(ExecJs(original_child_frame, + "document.getElementById('form').submit();")); form_post_observer.Wait(); original_child_frame = ChildFrameAt(original_contents, 0); @@ -715,9 +714,9 @@ // Click the first link in the view-source markup. content::WebContentsAddedObserver nav_observer; - EXPECT_TRUE(content::ExecuteScript( - browser()->tab_strip_model()->GetActiveWebContents(), - "document.getElementsByTagName('A')[0].click();")); + EXPECT_TRUE( + content::ExecJs(browser()->tab_strip_model()->GetActiveWebContents(), + "document.getElementsByTagName('A')[0].click();")); content::WebContents* new_contents = nav_observer.GetWebContents(); EXPECT_TRUE(WaitForLoadStop(new_contents));
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc index e8abb43..11d49e16 100644 --- a/chrome/browser/task_manager/task_manager_browsertest.cc +++ b/chrome/browser/task_manager/task_manager_browsertest.cc
@@ -951,9 +951,9 @@ GURL d_url = embedded_test_server()->GetURL( "d.com", "/cross_site_iframe_factory.html?d(e)"); - ASSERT_TRUE(content::ExecuteScript( - tab->GetPrimaryMainFrame(), - "frames[0][0].location.href = '" + d_url.spec() + "';")); + ASSERT_TRUE( + content::ExecJs(tab->GetPrimaryMainFrame(), + "frames[0][0].location.href = '" + d_url.spec() + "';")); ASSERT_NO_FATAL_FAILURE( WaitForTaskManagerRows(0, MatchSubframe("http://c.com/"))); @@ -1083,7 +1083,7 @@ // Reload the subframe and verify it has re-appeared in the task manager. // This is a regression test for https://crbug.com/642958. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( browser() ->tab_strip_model() ->GetActiveWebContents() @@ -1230,11 +1230,11 @@ const std::string r_script = R"( document.getElementById('frame1').src='/title1.html'; document.title='aac'; )"; - ASSERT_TRUE(content::ExecuteScript(browser() - ->tab_strip_model() - ->GetActiveWebContents() - ->GetPrimaryMainFrame(), - r_script)); + ASSERT_TRUE(content::ExecJs(browser() + ->tab_strip_model() + ->GetActiveWebContents() + ->GetPrimaryMainFrame(), + r_script)); ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchTab("aac"))); ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(1, MatchAnyTab())); if (!ShouldExpectSubframes()) {
diff --git a/chrome/browser/top_level_storage_access_api/request_storage_access_for_browsertest.cc b/chrome/browser/top_level_storage_access_api/request_storage_access_for_browsertest.cc index c287988..5c443f21 100644 --- a/chrome/browser/top_level_storage_access_api/request_storage_access_for_browsertest.cc +++ b/chrome/browser/top_level_storage_access_api/request_storage_access_for_browsertest.cc
@@ -198,7 +198,7 @@ content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); content::TestNavigationObserver load_observer(web_contents); - ASSERT_TRUE(ExecuteScript( + ASSERT_TRUE(ExecJs( GetFrame(), base::StringPrintf("document.body.querySelector('iframe').src = '%s';", url.spec().c_str())));
diff --git a/chrome/browser/translate/translate_manager_browsertest.cc b/chrome/browser/translate/translate_manager_browsertest.cc index 2ffa485..2da9ffb8 100644 --- a/chrome/browser/translate/translate_manager_browsertest.cc +++ b/chrome/browser/translate/translate_manager_browsertest.cc
@@ -314,7 +314,7 @@ const std::string click_link_js = "(function() { document.getElementById('test').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page // TODO(crbug.com/1258185): Migrate to better mechanism for testing around @@ -574,7 +574,7 @@ const std::string click_link_js = "(function() { document.getElementById('test').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page. // TODO(crbug.com/1258185): Migrate to better mechanism for testing around @@ -623,7 +623,7 @@ const std::string click_link_js = "(function() { " "document.getElementById('test-unsupported-language').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page. // TODO(crbug.com/1258185): Migrate to better mechanism for testing around @@ -678,7 +678,7 @@ const std::string click_link_js = "(function() { document.getElementById('test-conflict').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page. WaitUntilLanguageDetermined(chrome_translate_client); @@ -732,7 +732,7 @@ const std::string click_link_js = "(function() { document.getElementById('test-no-hrefLang').click(); " "})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page WaitUntilLanguageDetermined(chrome_translate_client); @@ -1153,7 +1153,7 @@ const std::string click_link_js = "(function() { document.getElementById('test').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page WaitUntilLanguageDetermined(chrome_translate_client); @@ -1343,7 +1343,7 @@ const std::string click_link_js = "(function() { document.getElementById('test').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page WaitUntilLanguageDetermined(chrome_translate_client); @@ -1399,7 +1399,7 @@ const std::string click_link_js = "(function() { document.getElementById('test').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page WaitUntilLanguageDetermined(chrome_translate_client); @@ -1442,7 +1442,7 @@ const std::string click_link_js = "(function() { " "document.getElementById('test-unsupported-language').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page WaitUntilLanguageDetermined(chrome_translate_client); @@ -1491,7 +1491,7 @@ const std::string click_link_js = "(function() { document.getElementById('test-conflict').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page WaitUntilLanguageDetermined(chrome_translate_client); @@ -1543,7 +1543,7 @@ const std::string click_link_js = "(function() { document.getElementById('test-no-hrefLang').click(); " "})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page WaitUntilLanguageDetermined(chrome_translate_client); @@ -1598,7 +1598,7 @@ const std::string click_link_js = "(function() { document.getElementById('test').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page WaitUntilLanguageDetermined(chrome_translate_client); @@ -1926,7 +1926,7 @@ const std::string click_link_js = "(function() { document.getElementById('test').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_link_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_link_js)); // Detect language on the new page WaitUntilLanguageDetermined(chrome_translate_client);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 5bfd07e..afa4529d 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -436,7 +436,6 @@ "//chrome/browser/ui/webui/segmentation_internals:mojo_bindings", "//chrome/browser/ui/webui/suggest_internals:mojo_bindings", "//chrome/browser/ui/webui/usb_internals:mojo_bindings", - "//chrome/browser/video_tutorials", "//chrome/common", "//chrome/common/net", "//chrome/common/search:mojo_bindings", @@ -881,8 +880,6 @@ "webui/offline/offline_internals_ui.h", "webui/offline/offline_internals_ui_message_handler.cc", "webui/offline/offline_internals_ui_message_handler.h", - "webui/video_tutorials/video_player_ui.cc", - "webui/video_tutorials/video_player_ui.h", "webui/webapks/webapks_handler.cc", "webui/webapks/webapks_handler.h", "webui/webapks/webapks_ui.cc",
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtilsUnitTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtilsUnitTest.java index 5613d09c..866bd435 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtilsUnitTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/SearchEngineLogoUtilsUnitTest.java
@@ -82,7 +82,7 @@ @Mock LocaleManagerDelegate mLocaleManagerDelegate; @Mock - Resources mResource; + Resources mResources; SearchEngineLogoUtils mSearchEngineLogoUtils; Bitmap mBitmap; @@ -102,7 +102,7 @@ LocaleManager.getInstance().setDelegateForTest(mLocaleManagerDelegate); // Used when creating bitmaps, needs to be greater than 0. - doReturn(1).when(mResource).getDimensionPixelSize(anyInt()); + doReturn(1).when(mResources).getDimensionPixelSize(anyInt()); mSearchEngineLogoUtils = new SearchEngineLogoUtils(); mSearchEngineLogoUtils.setFaviconHelperForTesting(mFaviconHelper); @@ -135,7 +135,7 @@ public void getSearchEngineLogo() { StatusIconResource expected = new StatusIconResource(LOGO_URL, mBitmap, 0); - Promise<StatusIconResource> promise = mSearchEngineLogoUtils.getSearchEngineLogo(mResource, + Promise<StatusIconResource> promise = mSearchEngineLogoUtils.getSearchEngineLogo(mResources, BrandedColorScheme.APP_DEFAULT, Mockito.mock(Profile.class), mTemplateUrlService); verify(mFaviconHelper) .getLocalFaviconImageForURL(any(), any(), anyInt(), mCallbackCaptor.capture()); @@ -183,7 +183,7 @@ public void getSearchEngineLogo_faviconCached() { StatusIconResource expected = new StatusIconResource(LOGO_URL, mBitmap, 0); - Promise<StatusIconResource> promise = mSearchEngineLogoUtils.getSearchEngineLogo(mResource, + Promise<StatusIconResource> promise = mSearchEngineLogoUtils.getSearchEngineLogo(mResources, BrandedColorScheme.APP_DEFAULT, Mockito.mock(Profile.class), mTemplateUrlService); verify(mFaviconHelper) .getLocalFaviconImageForURL(any(), any(), anyInt(), mCallbackCaptor.capture());
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarData.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarData.java index 72e64a3..abd3c695 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarData.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarData.java
@@ -70,7 +70,7 @@ public static UrlBarData forUrlAndText( String url, CharSequence displayText, @Nullable String editingText) { int pathSearchOffset = 0; - String displayTextStr = displayText.toString(); + String displayTextStr = displayText == null ? "" : displayText.toString(); String scheme = Uri.parse(displayTextStr).getScheme(); if (!TextUtils.isEmpty(scheme)) { @@ -93,14 +93,17 @@ } } int pathOffset = -1; - if (pathSearchOffset < displayText.length()) { + if (displayText != null && pathSearchOffset < displayText.length()) { pathOffset = displayTextStr.indexOf('/', pathSearchOffset); } - if (pathOffset == -1) return create(url, displayText, 0, displayText.length(), editingText); + if (pathOffset == -1) { + return create(url, displayText, 0, displayText == null ? 0 : displayText.length(), + editingText); + } // If the '/' is the last character and the beginning of the path, then just drop // the path entirely. - if (pathOffset == displayText.length() - 1) { + if (displayText != null && pathOffset == displayText.length() - 1) { return create( url, displayTextStr.subSequence(0, pathOffset), 0, pathOffset, editingText); }
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarDataTest.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarDataTest.java index 0c0ef840..a03e3257 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarDataTest.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarDataTest.java
@@ -101,7 +101,8 @@ private void verifyOriginSpan( String expectedOrigin, @Nullable String expectedOriginSuffix, String url) { UrlBarData urlBarData = UrlBarData.forUrl(url); - String displayText = urlBarData.displayText.toString(); + String displayText = + urlBarData.displayText == null ? "" : urlBarData.displayText.toString(); Assert.assertEquals(expectedOriginSuffix == null ? expectedOrigin : expectedOrigin + expectedOriginSuffix, displayText);
diff --git a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java index 2291606..7c09da7 100644 --- a/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java +++ b/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
@@ -107,7 +107,8 @@ } // Do not scroll to the end of the host for URLs such as data:, javascript:, etc... - if (data.url != null && data.originEndIndex == data.displayText.length()) { + if (data.url != null && data.displayText != null + && data.originEndIndex == data.displayText.length()) { Uri uri = Uri.parse(data.url); String scheme = uri.getScheme(); if (!TextUtils.isEmpty(scheme)
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index f7bd7189..51f07b0 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -729,18 +729,15 @@ <message name="IDS_PASSWORD_SETTINGS_EXPORT_ERROR_DETAILS" desc="A short prefix to introduce a technical error message passed to the user from Android after exporting passwords through a temporary file fails. Both the prefix and the error message are shown in the body of an alert dialog."> Details: <ph name="ERROR_DESCRIPTION">%1$s<ex>IOException: No space left on device</ex></ph> </message> - <message name="IDS_UPM_ERROR_NOTIFICATION_TITLE" translateable="false" desc="The title of the UI surface telling the user that the new password manager backend has encountered an error."> - Unified password manager error - </message> - <message name="IDS_UPM_ERROR_NOTIFICATION_CONTENTS" translateable="false" desc="The contents of the UI surface shown when the new password manager backend encounters an error, prompting the user to file a bug."> - The unified password manager was automatically disabled. Please submit an issue via the bug app! - </message> <message name="IDS_PASSWORDS_NOT_SECURE_FILLING" desc="The title of the dialog which is shown when the user attempts to enter obfuscated text to a regular text field."> Not secure </message> <message name="IDS_PASSWORDS_NOT_SECURE_FILLING_DETAILS" desc="The message of the dialog which is shown when the user attempts to enter obfuscated text to a regular text field."> To protect your privacy, Chrome will not autofill your password in this field. </message> + <message name="IDS_PASSWORD_MIGRATION_WARNING_TITLE" desc="The title of the password migration warning sheet."> + We’re changing how passwords are saved on this device + </message> <!-- Lock Screen Fragment --> <message name="IDS_LOCKSCREEN_DESCRIPTION_COPY" desc="When a user attempts to copy a password for a particular website into clipboard in Chrome's settings, Chrome launches a lock screen to verify the user's identity and displays the following explanation."> @@ -1726,9 +1723,6 @@ <message name="IDS_ADD_LANGUAGE" desc="Title for the screen that allows users to add languages to their preferred language list. [CHAR_LIMIT=32]"> Add language </message> - <message name="IDS_CHANGE_CHROME_LANG" desc="Title of page to select a language within Chrome's language settings. [CHAR_LIMIT=32]"> - Change language - </message> <message name="IDS_LANGUAGES_SELECT" desc="Option in overflow menu on Language settings page to change Chrome’s user interface language. [CHAR_LIMIT=32]"> Select language </message> @@ -3388,7 +3382,7 @@ <message name="IDS_NTP_DISCOVER_OFF_BRANDED" desc="Title in the feed header when the feed is turned off and the default search engine is not Google. Please use the branded term for Discover, as listed under Product Names in the Google Glossary Manager (TC ID 1799975766543019278)."> Discover by Google - off </message> - <message name="IDS_NTP_FOLLOWING" + <message name="IDS_NTP_FOLLOWING" meaning="Title for content - e.g. Followed sites" desc="Title in the feed header for user-customized following feed. This feed is composed of articles and content from sites that the user has followed">Following</message> <message name="IDS_NTP_FEED_MENU_IPH" desc="In-product help that points at the menu icon for the news feed on Chrome's new tab page. This string instructs the user to open the menu for settings that let them control the content that appears on the feed."> @@ -3452,71 +3446,6 @@ Explore content to follow </message> - <!-- Video tutorials --> - <message name="IDS_VIDEO_TUTORIALS_CARD_CHROME_INTRO" desc="Card text prompting user to learn about an introduction to chrome. Tapping on this card will open a video tutorial."> - How to use Chrome - </message> - <message name="IDS_VIDEO_TUTORIALS_CARD_SEARCH" desc="Card text prompting user to learn about how to search using chrome. Tapping on this card will open a video tutorial."> - How to search with Chrome - </message> - <message name="IDS_VIDEO_TUTORIALS_CARD_VOICE_SEARCH" desc="Card text prompting user to learn about how use voice search inside chrome. Tapping on this card will open a video tutorial."> - How to search with your voice - </message> - <message name="IDS_VIDEO_TUTORIALS_CARD_DOWNLOAD" desc="Card text prompting user to learn about how to download content using chrome. Tapping on this card will open a video tutorial."> - How to download content for later - </message> - <message name="IDS_VIDEO_TUTORIALS_CARD_ALL_VIDEOS" desc="Card text prompting user to tap on this card and explore videos on various aspects of chrome. Tapping on this card will open up a page listing all the available video tutorials."> - Videos about how to use Chrome - </message> - <message name="IDS_VIDEO_TUTORIALS_LEARN_CHROME" desc="Header text for the video tutorials home page that lists all the video tutorials."> - Learn Chrome - </message> - <message name="IDS_VIDEO_TUTORIALS_POPULAR_VIDEOS" desc="Header text for the video tutorials carousel on the help and feedback page."> - Popular videos - </message> - <message name="IDS_VIDEO_TUTORIALS_TILE_CHROME_INTRO" desc="Text under image tile prompting user to learn about an introduction to chrome. Tapping on this image will open a video tutorial."> - Navigate Chrome - </message> - <message name="IDS_VIDEO_TUTORIALS_TILE_SEARCH" desc="Text under image tile prompting user to learn about how to search using chrome. Tapping on this image will open a video tutorial."> - Search the internet - </message> - <message name="IDS_VIDEO_TUTORIALS_TILE_VOICE_SEARCH" desc="Text under image tile prompting user to learn about how use voice search inside chrome. Tapping on this image will open a video tutorial."> - Use voice search - </message> - <message name="IDS_VIDEO_TUTORIALS_TILE_DOWNLOAD" desc="Text under image tile prompting user to learn about how to download content using chrome. Tapping on this image will open a video tutorial."> - Download content - </message> - <message name="IDS_VIDEO_TUTORIALS_LANGUAGE_PICKER_TITLE" desc="Label text in the video player prompting user to pick a language."> - Pick your language - </message> - <message name="IDS_VIDEO_TUTORIALS_WATCH" desc="Button text in the video player prompting user to watch the video."> - Watch - </message> - <message name="IDS_VIDEO_TUTORIALS_TRY_NOW" desc="Button text in the video player prompting user to try out the steps mentioned in the tutorial."> - Try now - </message> - <message name="IDS_VIDEO_TUTORIALS_WATCH_NEXT_VIDEO" desc="Button text in the video player prompting user to watch the next video."> - Watch next video - </message> - <message name="IDS_VIDEO_TUTORIALS_CHANGE_LANGUAGE" desc="Button text in the video player prompting user to change the language."> - Change <ph name="LANGUAGE">%1$s<ex>Hindi</ex></ph>? - </message> - <message name="IDS_VIDEO_TUTORIALS_ACCESSIBILITY_SHARE" desc="Accessibility text in the video player describing that users can tap on this icon to share the video."> - Share - </message> - <message name="IDS_VIDEO_TUTORIALS_ACCESSIBILITY_CLOSE" desc="Accessibility text in the video player describing that users can tap on this icon to close the video."> - Close - </message> - <message name="IDS_VIDEO_TUTORIALS_IPH_TAP_HERE_TO_START" desc="In-product help bubble text prompting user to click on the search box to start."> - Tap here to start - </message> - <message name="IDS_VIDEO_TUTORIALS_IPH_TAP_VOICE_ICON_TO_START" desc="In-product help bubble text prompting user to start typing on the search box or tap on the microphone icon to start a voice search."> - Type here or tap the voice icon to start - </message> - <message name="IDS_VIDEO_TUTORIALS_LOADING" desc="Text on the loading animation screen indicating that the video loading is currently in progress."> - Loading… - </message> - <!-- Feature notification guide --> <message name="IDS_FEATURE_NOTIFICATION_GUIDE_NOTIFICATION_TITLE" desc="Notification title text educating user about tips and tricks in chrome."> Chrome tips
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_CHANGE_CHROME_LANG.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_CHANGE_CHROME_LANG.png.sha1 deleted file mode 100644 index 81c27ff..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_CHANGE_CHROME_LANG.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -04abc2f59083e1c85ea9327376343f4aba0f45b7 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_TITLE.png.sha1 new file mode 100644 index 0000000..13fa35f8 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_PASSWORD_MIGRATION_WARNING_TITLE.png.sha1
@@ -0,0 +1 @@ +51ede015580ca818146693629e1a95b2cef6037c \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_ACCESSIBILITY_CLOSE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_ACCESSIBILITY_CLOSE.png.sha1 deleted file mode 100644 index ddd1bde..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_ACCESSIBILITY_CLOSE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1e72344d7da7da2d784cff5bb65dbdceba59f684 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_ACCESSIBILITY_SHARE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_ACCESSIBILITY_SHARE.png.sha1 deleted file mode 100644 index ddd1bde..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_ACCESSIBILITY_SHARE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1e72344d7da7da2d784cff5bb65dbdceba59f684 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_ALL_VIDEOS.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_ALL_VIDEOS.png.sha1 deleted file mode 100644 index e597e63..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_ALL_VIDEOS.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -2af6ead5370d22d207d5d4c31a78947d2c3cea5a \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_CHROME_INTRO.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_CHROME_INTRO.png.sha1 deleted file mode 100644 index ef9ce56..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_CHROME_INTRO.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -64ff03dde2d33614f30b1d441d17ebb5e7d27a81 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_DOWNLOAD.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_DOWNLOAD.png.sha1 deleted file mode 100644 index 3475f6a..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_DOWNLOAD.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -810d092f0eee1135be253c9233067073bea7a1a6 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_SEARCH.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_SEARCH.png.sha1 deleted file mode 100644 index 773cd86..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_SEARCH.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -54049a334a09370caf57e259928c7a0f8d3d7ae4 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_VOICE_SEARCH.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_VOICE_SEARCH.png.sha1 deleted file mode 100644 index d0f52ec..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CARD_VOICE_SEARCH.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -b797c42cf6c94ba01eb0b7ca2adb07cf35ed1517 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CHANGE_LANGUAGE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CHANGE_LANGUAGE.png.sha1 deleted file mode 100644 index 8210b1e..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_CHANGE_LANGUAGE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1e72344d7da7da2d784cff5bb65dbdceba59f684
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_IPH_TAP_HERE_TO_START.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_IPH_TAP_HERE_TO_START.png.sha1 deleted file mode 100644 index e8ceaa2d..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_IPH_TAP_HERE_TO_START.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -eff6a2c9ea179fc13bae931c5bd700a4f03ef8ba \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_IPH_TAP_VOICE_ICON_TO_START.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_IPH_TAP_VOICE_ICON_TO_START.png.sha1 deleted file mode 100644 index d198c6d..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_IPH_TAP_VOICE_ICON_TO_START.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -bac4d73f5f82ca874c0e3777f0d02474bb6a2e63 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_LANGUAGE_PICKER_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_LANGUAGE_PICKER_TITLE.png.sha1 deleted file mode 100644 index 7db625d..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_LANGUAGE_PICKER_TITLE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -24e7fadc4d0ced52cd28bc716277614afce2e460 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_LEARN_CHROME.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_LEARN_CHROME.png.sha1 deleted file mode 100644 index fbf8a34..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_LEARN_CHROME.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -f1e6bab93102f45f65ad8f70b34e8a0b2eca7d72 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_LOADING.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_LOADING.png.sha1 deleted file mode 100644 index 563b51c..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_LOADING.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -edcd73ed1f1bf2d070a0eeb3cf272d3284e01668 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_POPULAR_VIDEOS.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_POPULAR_VIDEOS.png.sha1 deleted file mode 100644 index d5af12eeb..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_POPULAR_VIDEOS.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -40e58aa1eabf784f5dcc42e4a67b0ff823856bc0 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_CHROME_INTRO.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_CHROME_INTRO.png.sha1 deleted file mode 100644 index d5af12eeb..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_CHROME_INTRO.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -40e58aa1eabf784f5dcc42e4a67b0ff823856bc0 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_DOWNLOAD.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_DOWNLOAD.png.sha1 deleted file mode 100644 index d5af12eeb..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_DOWNLOAD.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -40e58aa1eabf784f5dcc42e4a67b0ff823856bc0 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_SEARCH.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_SEARCH.png.sha1 deleted file mode 100644 index d5af12eeb..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_SEARCH.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -40e58aa1eabf784f5dcc42e4a67b0ff823856bc0 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_VOICE_SEARCH.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_VOICE_SEARCH.png.sha1 deleted file mode 100644 index d5af12eeb..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TILE_VOICE_SEARCH.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -40e58aa1eabf784f5dcc42e4a67b0ff823856bc0 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TRY_NOW.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TRY_NOW.png.sha1 deleted file mode 100644 index ddd1bde..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_TRY_NOW.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1e72344d7da7da2d784cff5bb65dbdceba59f684 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_WATCH.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_WATCH.png.sha1 deleted file mode 100644 index 7db625d..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_WATCH.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -24e7fadc4d0ced52cd28bc716277614afce2e460 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_WATCH_NEXT_VIDEO.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_WATCH_NEXT_VIDEO.png.sha1 deleted file mode 100644 index ddd1bde..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_VIDEO_TUTORIALS_WATCH_NEXT_VIDEO.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1e72344d7da7da2d784cff5bb65dbdceba59f684 \ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java index 63903aa..70defa9 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -159,7 +159,6 @@ @Nullable private LruCache<SpannableDisplayTextCacheKey, SpannableStringBuilder> mSpannableDisplayTextCache; - private boolean mOptimizationsEnabled; private Tab mTab; private int mPrimaryColor; @@ -214,25 +213,21 @@ mOfflineStatus = offlineStatus; mPrimaryColor = ChromeColors.getDefaultThemeColor(context, false); mSearchEngineLogoUtils = searchEngineLogoUtils; + mUrlForDisplay = ""; + mFormattedFullUrl = ""; } /** * Handle any initialization that must occur after native has been initialized. */ public void initializeWithNative() { - mOptimizationsEnabled = - ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS); mOmniboxUpdatedConnectionSecurityIndicatorsEnabled = ChromeFeatureList.isEnabled( ChromeFeatureList.OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS); mLastUsedNonOTRProfile = Profile.getLastUsedRegularProfile(); mNativeLocationBarModelAndroid = LocationBarModelJni.get().init(LocationBarModel.this); - - if (mOptimizationsEnabled) { - mSpannableDisplayTextCache = new LruCache<>(LRU_CACHE_SIZE); - mChromeAutocompleteSchemeClassifier = - new ChromeAutocompleteSchemeClassifier(getProfile()); - recalculateFormattedUrls(); - } + mSpannableDisplayTextCache = new LruCache<>(LRU_CACHE_SIZE); + mChromeAutocompleteSchemeClassifier = new ChromeAutocompleteSchemeClassifier(getProfile()); + recalculateFormattedUrls(); } /** @@ -314,12 +309,7 @@ return UrlConstants.ntpGurl(); } - if (mOptimizationsEnabled) { - return mVisibleGurl; - } - - Tab tab = getTab(); - return tab != null && tab.isInitialized() ? tab.getUrl() : GURL.emptyGURL(); + return mVisibleGurl; } /** @@ -328,7 +318,6 @@ */ @VisibleForTesting boolean updateVisibleGurl() { - if (!mOptimizationsEnabled) return true; try (TraceEvent te = TraceEvent.scoped("LocationBarModel.updateVisibleGurl")) { if (isInOverviewAndShowingOmnibox()) { mFormattedFullUrl = ""; @@ -442,8 +431,8 @@ private UrlBarData buildUrlBarData( String url, boolean isOfflinePage, String displayText, String editingText) { - SpannableStringBuilder spannableDisplayText = new SpannableStringBuilder(displayText); - if (mNativeLocationBarModelAndroid != 0 && spannableDisplayText.length() > 0 + SpannableStringBuilder spannableDisplayText = null; + if (mNativeLocationBarModelAndroid != 0 && displayText != null && displayText.length() > 0 && shouldEmphasizeUrl()) { final @BrandedColorScheme int brandedColorScheme = OmniboxResourceProvider.getBrandedColorScheme( @@ -463,30 +452,19 @@ SpannableDisplayTextCacheKey cacheKey = new SpannableDisplayTextCacheKey(url, displayText, securityLevel, nonEmphasizedColor, emphasizedColor, dangerColor, secureColor); - SpannableStringBuilder cachedSpannableDisplayText = null; - if (mOptimizationsEnabled) { - autocompleteSchemeClassifier = mChromeAutocompleteSchemeClassifier; - cachedSpannableDisplayText = mSpannableDisplayTextCache.get(cacheKey); - } else { - autocompleteSchemeClassifier = new ChromeAutocompleteSchemeClassifier(getProfile()); - } + SpannableStringBuilder cachedSpannableDisplayText = + mSpannableDisplayTextCache.get(cacheKey); + autocompleteSchemeClassifier = mChromeAutocompleteSchemeClassifier; - try { - if (cachedSpannableDisplayText != null) { - return UrlBarData.forUrlAndText(url, cachedSpannableDisplayText, editingText); - } else { - OmniboxUrlEmphasizer.emphasizeUrl(spannableDisplayText, - autocompleteSchemeClassifier, getSecurityLevel(), - shouldEmphasizeHttpsScheme(), nonEmphasizedColor, emphasizedColor, - dangerColor, secureColor); - if (mOptimizationsEnabled) { - mSpannableDisplayTextCache.put(cacheKey, spannableDisplayText); - } - } - } finally { - if (!mOptimizationsEnabled) { - autocompleteSchemeClassifier.destroy(); - } + if (cachedSpannableDisplayText != null) { + return UrlBarData.forUrlAndText(url, cachedSpannableDisplayText, editingText); + } else { + spannableDisplayText = new SpannableStringBuilder(displayText); + OmniboxUrlEmphasizer.emphasizeUrl(spannableDisplayText, + autocompleteSchemeClassifier, getSecurityLevel(), + shouldEmphasizeHttpsScheme(), nonEmphasizedColor, emphasizedColor, + dangerColor, secureColor); + mSpannableDisplayTextCache.put(cacheKey, spannableDisplayText); } } return UrlBarData.forUrlAndText(url, spannableDisplayText, editingText); @@ -812,19 +790,11 @@ } private String getFormattedFullUrl() { - if (mOptimizationsEnabled) { - return mFormattedFullUrl; - } - - return calculateFormattedFullUrl(); + return mFormattedFullUrl; } private String getUrlForDisplay() { - if (mOptimizationsEnabled) { - return mUrlForDisplay; - } - - return calculateUrlForDisplay(); + return mUrlForDisplay; } /** @return The formatted URL suitable for editing. */
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/HomeButtonCoordinatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/HomeButtonCoordinatorTest.java index 1d1d56a..6ec36a7 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/HomeButtonCoordinatorTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/HomeButtonCoordinatorTest.java
@@ -29,13 +29,11 @@ import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.toolbar.HomeButton; import org.chromium.chrome.browser.toolbar.R; import org.chromium.chrome.browser.user_education.IPHCommand; import org.chromium.chrome.browser.user_education.UserEducationHelper; import org.chromium.chrome.test.util.browser.Features; -import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.components.feature_engagement.FeatureConstants; import org.chromium.url.GURL; import org.chromium.url.JUnitTestGURLs; @@ -44,7 +42,6 @@ /** Unit tests for HomeButtonCoordinator. */ @RunWith(BaseRobolectricTestRunner.class) -@DisableFeatures(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS) public class HomeButtonCoordinatorTest { private static final GURL NTP_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.NTP_URL); private static final GURL NOT_NTP_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL); @@ -115,6 +112,9 @@ private void verifyIphShownWithStringIds(int contentId, int accessibilityId) { verify(mUserEducationHelper).requestShowIPH(mIPHCommandCaptor.capture()); + // Note that we aren't actually showing the IPH (unit tests) so resources aren't resolved + // unless we force it. + mIPHCommandCaptor.getValue().fetchFromResources(); Assert.assertEquals("Wrong feature name", FeatureConstants.NEW_TAB_PAGE_HOME_BUTTON_FEATURE, mIPHCommandCaptor.getValue().featureName); Assert.assertEquals("Wrong text id", ID_TO_STRING_MAP.get(contentId),
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinatorTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinatorTest.java index 1f82c2b..f77baef 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinatorTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToggleTabStackButtonCoordinatorTest.java
@@ -30,13 +30,11 @@ import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.OneshotSupplierImpl; import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.layouts.LayoutStateProvider; import org.chromium.chrome.browser.layouts.LayoutType; import org.chromium.chrome.browser.user_education.IPHCommand; import org.chromium.chrome.browser.user_education.UserEducationHelper; import org.chromium.chrome.test.util.browser.Features; -import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import java.util.HashSet; import java.util.Set; @@ -46,7 +44,6 @@ */ @RunWith(BaseRobolectricTestRunner.class) @LooperMode(LooperMode.Mode.LEGACY) -@DisableFeatures(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS) public class ToggleTabStackButtonCoordinatorTest { @Rule public TestRule mFeaturesProcessorRule = new Features.JUnitProcessor();
diff --git a/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc b/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc index 204c4e6..71f7351 100644 --- a/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc +++ b/chrome/browser/ui/ash/capture_mode/capture_mode_browsertest.cc
@@ -13,6 +13,7 @@ #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "base/files/file_util.h" +#include "base/files/safe_base_name.h" #include "base/functional/callback_forward.h" #include "base/run_loop.h" #include "base/scoped_observation.h" @@ -884,7 +885,8 @@ void StartProjectorModeSession() { auto* projector_session = ash::ProjectorSession::Get(); EXPECT_FALSE(projector_session->is_active()); - ash::ProjectorController::Get()->StartProjectorSession("projector_data"); + ash::ProjectorController::Get()->StartProjectorSession( + base::SafeBaseName::Create("projector_data").value()); EXPECT_TRUE(projector_session->is_active()); EXPECT_TRUE(ash::CaptureModeTestApi().IsSessionActive()); }
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc index 26121c6..9e0bbf9 100644 --- a/chrome/browser/ui/browser_browsertest.cc +++ b/chrome/browser/ui/browser_browsertest.cc
@@ -951,8 +951,8 @@ // Click a target=_blank link. WebContents* const contents = browser()->tab_strip_model()->GetActiveWebContents(); - ASSERT_TRUE(ExecuteScript( - contents, "simulateClick(\"test-anchor-with-blank-target\", {})")); + ASSERT_TRUE( + ExecJs(contents, "simulateClick(\"test-anchor-with-blank-target\", {})")); // The new tab should have inherited the tab group from the first tab. EXPECT_EQ(group_id, browser()->tab_strip_model()->GetTabGroupForTab(1));
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc index d5b282a..f7a0bafc 100644 --- a/chrome/browser/ui/browser_focus_uitest.cc +++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -377,7 +377,7 @@ browser()->window()->Activate(); ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); EXPECT_TRUE(browser()->window()->IsActive()); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( background_browser->tab_strip_model()->GetActiveWebContents(), "stealFocus();")); @@ -402,7 +402,7 @@ chrome::FocusLocationBar(browser()); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( browser()->tab_strip_model()->GetActiveWebContents(), "stealFocus();")); // Make sure the location bar is still focused. @@ -698,7 +698,7 @@ "w.document.location = '" + url2.spec() + "';"; - ASSERT_TRUE(content::ExecuteScript(web_contents, spoof)); + ASSERT_TRUE(content::ExecJs(web_contents, spoof)); EXPECT_EQ(url1, web_contents->GetVisibleURL()); // After running the spoof code, |GetActiveWebContents| returns the new tab, // not the same as |web_contents|. @@ -724,7 +724,7 @@ const GURL new_url = embedded_test_server()->GetURL("/title2.html"); const std::string open_script = "window.open('" + new_url.spec() + "');"; content::WebContentsAddedObserver open_observer; - ASSERT_TRUE(content::ExecuteScript(opener_web_contents, open_script)); + ASSERT_TRUE(content::ExecJs(opener_web_contents, open_script)); WebContents* new_web_contents = open_observer.GetWebContents(); // Tell the first (non-selected) tab to go back. This should not give the @@ -732,7 +732,7 @@ // the focus may scroll the origin out of view, making a spoof possible. const std::string go_back_script = "window.opener.history.back();"; content::TestNavigationObserver back_observer(opener_web_contents); - ASSERT_TRUE(content::ExecuteScript(new_web_contents, go_back_script)); + ASSERT_TRUE(content::ExecJs(new_web_contents, go_back_script)); back_observer.Wait(); EXPECT_FALSE(IsViewFocused(VIEW_ID_OMNIBOX)); }
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h index 225f5cc..1b3cbab 100644 --- a/chrome/browser/ui/color/chrome_color_id.h +++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -339,6 +339,8 @@ E_CPONLY(kColorSidePanelBadgeForeground) \ E_CPONLY(kColorSidePanelBadgeForegroundUpdated) \ E_CPONLY(kColorSidePanelCardBackground) \ + E_CPONLY(kColorSidePanelCardPrimaryForeground) \ + E_CPONLY(kColorSidePanelCardSecondaryForeground) \ E_CPONLY(kColorSidePanelContentAreaSeparator) \ E_CPONLY(kColorSidePanelContentBackground) \ E_CPONLY(kColorSidePanelDivider) \
diff --git a/chrome/browser/ui/color/material_side_panel_color_mixer.cc b/chrome/browser/ui/color/material_side_panel_color_mixer.cc index 6498548d..a701482 100644 --- a/chrome/browser/ui/color/material_side_panel_color_mixer.cc +++ b/chrome/browser/ui/color/material_side_panel_color_mixer.cc
@@ -16,6 +16,9 @@ mixer[kColorSidePanelContentBackground] = {ui::kColorSysSurface4}; mixer[kColorSidePanelScrollbarThumb] = {ui::kColorSysPrimary}; mixer[kColorSidePanelCardBackground] = {ui::kColorSysSurface}; + mixer[kColorSidePanelCardPrimaryForeground] = {ui::kColorSysOnSurface}; + mixer[kColorSidePanelCardSecondaryForeground] = { + ui::kColorSysOnSurfaceSubtle}; mixer[kColorSidePanelDivider] = {ui::kColorSysDivider}; mixer[kColorSidePanelBadgeBackground] = {ui::kColorSysSurfaceVariant};
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_interactive_browsertest.cc index 8ba6c75..4957217 100644 --- a/chrome/browser/ui/exclusive_access/fullscreen_interactive_browsertest.cc +++ b/chrome/browser/ui/exclusive_access/fullscreen_interactive_browsertest.cc
@@ -96,16 +96,16 @@ // Make the top page fullscreen. { FullscreenWebContentsObserver observer(web_contents, main_frame); - EXPECT_TRUE( - ExecuteScript(main_frame, "document.body.webkitRequestFullscreen();")); + EXPECT_TRUE(ExecJs(main_frame, "document.body.webkitRequestFullscreen();", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); observer.Wait(); } // Make the child frame fullscreen. { FullscreenWebContentsObserver observer(web_contents, child_frame); - EXPECT_TRUE( - ExecuteScript(child_frame, "document.body.webkitRequestFullscreen();")); + EXPECT_TRUE(ExecJs(child_frame, "document.body.webkitRequestFullscreen();", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); observer.Wait(); } @@ -115,8 +115,8 @@ if (!content::SiteIsolationPolicy::UseDedicatedProcessesForAllSites()) { { FullscreenWebContentsObserver observer(web_contents, main_frame); - EXPECT_TRUE( - ExecuteScript(child_frame, "document.webkitExitFullscreen();")); + EXPECT_TRUE(ExecJs(child_frame, "document.webkitExitFullscreen();", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); observer.Wait(); } } @@ -136,23 +136,24 @@ // Make the top page fullscreen. { FullscreenWebContentsObserver observer(web_contents, main_frame); - EXPECT_TRUE( - ExecuteScript(main_frame, "document.body.webkitRequestFullscreen();")); + EXPECT_TRUE(ExecJs(main_frame, "document.body.webkitRequestFullscreen();", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); observer.Wait(); } // Make the child frame fullscreen. { FullscreenWebContentsObserver observer(web_contents, child_frame); - EXPECT_TRUE( - ExecuteScript(child_frame, "document.body.webkitRequestFullscreen();")); + EXPECT_TRUE(ExecJs(child_frame, "document.body.webkitRequestFullscreen();", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); observer.Wait(); } // Exit fullscreen on the child frame. { FullscreenWebContentsObserver observer(web_contents, main_frame); - EXPECT_TRUE(ExecuteScript(child_frame, "document.webkitExitFullscreen();")); + EXPECT_TRUE(ExecJs(child_frame, "document.webkitExitFullscreen();", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); observer.Wait(); } }
diff --git a/chrome/browser/ui/extensions/hosted_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc index d2cb277..a1d3267 100644 --- a/chrome/browser/ui/extensions/hosted_app_browsertest.cc +++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -822,8 +822,7 @@ bool expect_same_process, bool expect_app_process) { content::WebContentsAddedObserver tab_added_observer; - ASSERT_TRUE( - content::ExecuteScript(rfh, "window.open('" + url.spec() + "');")); + ASSERT_TRUE(content::ExecJs(rfh, "window.open('" + url.spec() + "');")); content::WebContents* new_tab = tab_added_observer.GetWebContents(); ASSERT_TRUE(new_tab); EXPECT_TRUE(WaitForLoadStop(new_tab)); @@ -842,7 +841,7 @@ << " for " << url << " from " << rfh->GetLastCommittedURL(); content::WebContentsDestroyedWatcher watcher(new_tab); - ASSERT_TRUE(content::ExecuteScript(new_rfh, "window.close();")); + ASSERT_TRUE(content::ExecJs(new_rfh, "window.close();")); watcher.Wait(); } @@ -869,7 +868,7 @@ script += "f.id = '" + element_id + "';"; script += "f.src = '" + url.spec() + "';"; script += "document.body.appendChild(f);"; - EXPECT_TRUE(ExecuteScript(parent_rfh, script)); + EXPECT_TRUE(ExecJs(parent_rfh, script)); nav_observer.Wait(); RenderFrameHost* subframe = content::FrameMatchingPredicate( @@ -1860,7 +1859,7 @@ foo_process->GetID(), url::Origin::Create(bar_app_url))); // Ensure the current process is allowed to access cookies. - EXPECT_TRUE(ExecuteScript(web_contents, "document.cookie = 'foo=bar';")); + EXPECT_TRUE(ExecJs(web_contents, "document.cookie = 'foo=bar';")); EXPECT_EQ("foo=bar", EvalJs(web_contents, "document.cookie")); // Now navigate to a bar.com app URL in the same BrowsingInstance. Ensure @@ -1868,7 +1867,7 @@ { content::TestNavigationObserver observer(web_contents); EXPECT_TRUE( - ExecuteScript(web_contents, "location = '" + bar_app_url.spec() + "'")); + ExecJs(web_contents, "location = '" + bar_app_url.spec() + "'")); observer.Wait(); } EXPECT_EQ(bar_app_url, web_contents->GetLastCommittedURL()); @@ -1886,7 +1885,7 @@ bar_process->GetID(), url::Origin::Create(foo_app_url))); // Ensure the current process is allowed to access cookies. - EXPECT_TRUE(ExecuteScript(web_contents, "document.cookie = 'foo=bar';")); + EXPECT_TRUE(ExecJs(web_contents, "document.cookie = 'foo=bar';")); EXPECT_EQ("foo=bar", EvalJs(web_contents, "document.cookie")); // Now navigate from a foo.com app URL to a foo.com non-app URL. Ensure that @@ -1901,8 +1900,8 @@ embedded_test_server()->GetURL("foo.com", "/title1.html")); { content::TestNavigationObserver observer(web_contents); - EXPECT_TRUE(ExecuteScript(web_contents, - "location = '" + foo_nonapp_url.spec() + "'")); + EXPECT_TRUE( + ExecJs(web_contents, "location = '" + foo_nonapp_url.spec() + "'")); observer.Wait(); } EXPECT_EQ(foo_nonapp_url, web_contents->GetLastCommittedURL()); @@ -1916,7 +1915,7 @@ // data. EXPECT_TRUE(policy->CanAccessDataForOrigin( foo_nonapp_process->GetID(), url::Origin::Create(foo_nonapp_url))); - EXPECT_TRUE(ExecuteScript(web_contents, "document.cookie = 'foo=bar';")); + EXPECT_TRUE(ExecJs(web_contents, "document.cookie = 'foo=bar';")); EXPECT_EQ("foo=bar", EvalJs(web_contents, "document.cookie")); } @@ -1997,7 +1996,7 @@ { content::TestNavigationObserver background_page_observer(nullptr); background_page_observer.StartWatchingNewWebContents(); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( foo_contents, "window.bg = window.open('/empty.html', 'bg', 'background');")); background_page_observer.Wait(); @@ -2010,8 +2009,8 @@ // Script the background page from the first foo.com window and set a dummy // value. - EXPECT_TRUE(content::ExecuteScript(foo_contents, - "bg.document.body.innerText = 'foo'")); + EXPECT_TRUE( + content::ExecJs(foo_contents, "bg.document.body.innerText = 'foo'")); // Ensure that the second foo.com page can script the same background page // and retrieve the value. @@ -2048,15 +2047,15 @@ { content::TestNavigationObserver background_page_observer(nullptr); background_page_observer.StartWatchingNewWebContents(); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( bar_contents, "window.bg = window.open('/empty.html', 'bg2', 'background');")); background_page_observer.Wait(); EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/empty.html"), background_page_observer.last_navigation_url()); } - EXPECT_TRUE(content::ExecuteScript(bar_contents, - "bg.document.body.innerText = 'bar'")); + EXPECT_TRUE( + content::ExecJs(bar_contents, "bg.document.body.innerText = 'bar'")); EXPECT_EQ("bar", content::EvalJs(bar_contents2, "window.open('', 'bg2').document.body.innerText"));
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc index b70e23d2..0fefdc4 100644 --- a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc +++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -345,7 +345,7 @@ constexpr char kRemoveFrameScript[] = "frame = document.getElementsByTagName(\"FRAME\")[0];\n" "frame.parentElement.removeChild(frame);\n"; - ASSERT_TRUE(content::ExecuteScript(web_contents, kRemoveFrameScript)); + ASSERT_TRUE(content::ExecJs(web_contents, kRemoveFrameScript)); ASSERT_TRUE( ui_test_utils::NavigateToURL(browser(), GetURL("specialchar.html")));
diff --git a/chrome/browser/ui/keyboard_lock_interactive_browsertest.cc b/chrome/browser/ui/keyboard_lock_interactive_browsertest.cc index 787e183..4d10adf 100644 --- a/chrome/browser/ui/keyboard_lock_interactive_browsertest.cc +++ b/chrome/browser/ui/keyboard_lock_interactive_browsertest.cc
@@ -179,7 +179,7 @@ bool KeyboardLockInteractiveBrowserTest::CancelKeyboardLock() { // keyboard.unlock() is a synchronous call. - return ExecuteScript(GetActiveWebContents(), kKeyboardUnlockMethodCall); + return ExecJs(GetActiveWebContents(), kKeyboardUnlockMethodCall); } #if BUILDFLAG(IS_MAC)
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc b/chrome/browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc index 607b43b..09a1cb6 100644 --- a/chrome/browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc +++ b/chrome/browser/ui/media_router/presentation_receiver_window_controller_browsertest.cc
@@ -255,8 +255,8 @@ content::WebContentsDestroyedWatcher destroyed_watcher( receiver_window->web_contents()); - ASSERT_TRUE(content::ExecuteScript(receiver_window->web_contents(), - "window.location = 'about:blank'")); + ASSERT_TRUE(content::ExecJs(receiver_window->web_contents(), + "window.location = 'about:blank'")); destroyed_watcher.Wait(); destroyer.AwaitTerminate(std::move(receiver_window));
diff --git a/chrome/browser/ui/signin/profile_customization_util.cc b/chrome/browser/ui/signin/profile_customization_util.cc index 843b9be..a8c894b 100644 --- a/chrome/browser/ui/signin/profile_customization_util.cc +++ b/chrome/browser/ui/signin/profile_customization_util.cc
@@ -38,9 +38,13 @@ CHECK(entry); CHECK(!profile_name.empty()); +#if !BUILDFLAG(IS_CHROMEOS_LACROS) // We don't expect this to be run for profiles where the user already had a - // chance to set a custom profile name. + // chance to set a custom profile name. One exception might be post-migration + // Lacros silent first run, see crbug.com/1443026. DCHECK(entry->IsUsingDefaultName()); +#endif + entry->SetLocalProfileName(profile_name, is_default_name); if (!entry->IsOmitted()) {
diff --git a/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc b/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc index 4bfa2c4..4bcc15a 100644 --- a/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc +++ b/chrome/browser/ui/signin_reauth_view_controller_browsertest.cc
@@ -403,7 +403,7 @@ content::WebContents* target_contents = signin_reauth_view_controller()->GetModalDialogWebContentsForTesting(); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( target_contents, "document.getElementsByTagName('a')[0].click();")); EXPECT_EQ(WaitForReauthResult(), signin::ReauthResult::kSuccess); EXPECT_THAT( @@ -451,7 +451,7 @@ TrustedVaultKeysChangedStateChecker keys_added_checker( SyncServiceFactory::GetAsSyncServiceImplForProfileForTesting( browser()->profile())); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( target_contents, "chrome.setSyncEncryptionKeys(() => {}, \"\", [new ArrayBuffer()], 0);")); EXPECT_TRUE(keys_added_checker.Wait()); @@ -479,7 +479,7 @@ signin_reauth_view_controller()->GetModalDialogWebContentsForTesting(); content::TestNavigationObserver new_tab_observer(nullptr); new_tab_observer.StartWatchingNewWebContents(); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( dialog_contents, "document.getElementsByTagName('a')[0].click();")); new_tab_observer.Wait(); @@ -526,7 +526,7 @@ signin_reauth_view_controller()->GetModalDialogWebContentsForTesting()); EXPECT_EQ(target_contents->GetLastCommittedURL(), target_url); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( target_contents, "document.getElementsByTagName('a')[0].click();")); EXPECT_EQ(WaitForReauthResult(), signin::ReauthResult::kSuccess); EXPECT_THAT(
diff --git a/chrome/browser/ui/startup/startup_browser_creator.h b/chrome/browser/ui/startup/startup_browser_creator.h index 1e798e6..338de16 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.h +++ b/chrome/browser/ui/startup/startup_browser_creator.h
@@ -89,7 +89,7 @@ // Bundles the startup profile path together with a StartupProfileMode. // Depending on `StartupProfileModeFromReason(reason)`, `path` is either: // - regular profile path for kBrowserWindow; if the guest mode is requested, -// contains default profile path with kBrowserWindow mode +// may contain either the default profile path or the guest profile path // - guest profile path for kProfilePicker, // - empty path for kError // TODO(https://crbug.com/1150326): return a guest profile path for the Guest @@ -102,7 +102,7 @@ // Bundles the startup profile together with a StartupProfileMode. // Depending on the `mode` value, `profile` is either: // - regular profile for kBrowserWindow; if the Guest mode is requested, -// contains default profile with kBrowserWindow mode +// may contain either the default profile path or the guest profile path // - guest profile for kProfilePicker, // - nullptr for kError // TODO(https://crbug.com/1150326): return a guest profile for the Guest mode
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc index 12d8953..188a906 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -34,6 +34,7 @@ #include "chrome/browser/browser_features.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/buildflags.h" +#include "chrome/browser/chrome_browser_main.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/launch_util.h" @@ -50,6 +51,7 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_test_util.h" #include "chrome/browser/profiles/profile_window.h" +#include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/search/search.h" #include "chrome/browser/sessions/app_session_service.h" #include "chrome/browser/sessions/app_session_service_factory.h" @@ -2444,6 +2446,120 @@ } #if !BUILDFLAG(IS_CHROMEOS_LACROS) +class StartupBrowserCreatorTestWithGuestParam + : public StartupBrowserCreatorTest, + public testing::WithParamInterface<bool> { + public: + bool IsGuest() const { return GetParam(); } + + GURL GetTestURL() const { return GURL("https://www.youtube.com"); } + + // Creates a browser for a new profile (which may be Guest, based on + // `IsGuest()`). + Browser* CreateBrowser() { + if (IsGuest()) { + profiles::SwitchToGuestProfile(); + } else { + base::FilePath profile_path = g_browser_process->profile_manager() + ->GenerateNextProfileDirectoryPath(); + profiles::SwitchToProfile(profile_path, /*always_create=*/true); + } + Browser* test_browser = ui_test_utils::WaitForBrowserToOpen(); + profiles::SetLastUsedProfile(test_browser->profile()->GetBaseName()); + return test_browser; + } + + void OpenTabAlreadyRunning() { + base::CommandLine command_line(base::CommandLine::NO_PROGRAM); + command_line.AppendArg(GetTestURL().spec()); + ChromeBrowserMainParts::ProcessSingletonNotificationCallback( + command_line, /*current_directory=*/{}); + } +}; + +// Tests that receiving a launch notification while Chrome is already running +// opens the URL in the current browser window. +IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorTestWithGuestParam, + ProcessCommandLineAlreadyRunning) { + ScopedKeepAlive keep_alive(KeepAliveOrigin::BACKGROUND_MODE_MANAGER, + KeepAliveRestartOption::DISABLED); + CloseBrowserSynchronously(browser()); + + // Create a browser for a new profile. + Browser* test_browser = CreateBrowser(); + ASSERT_TRUE(test_browser); + ASSERT_EQ(test_browser->profile()->IsGuestSession(), IsGuest()); + TabStripModel* tab_strip = test_browser->tab_strip_model(); + int initial_tab_count = tab_strip->count(); + + // Open a URL while a browser is already open. + ui_test_utils::AllBrowserTabAddedWaiter tab_waiter; + OpenTabAlreadyRunning(); + content::WebContents* contents = tab_waiter.Wait(); + + EXPECT_EQ(initial_tab_count + 1, tab_strip->count()); + EXPECT_EQ(contents, tab_strip->GetWebContentsAt(tab_strip->count() - 1)); + EXPECT_EQ(GetTestURL(), contents->GetVisibleURL()); +} + +// Tests that receiving a launch notification while Chrome is already running, +// but there was no browser window, reopens the last profile if it was regular, +// and opens the profile picker if it was guest. +IN_PROC_BROWSER_TEST_P(StartupBrowserCreatorTestWithGuestParam, + ProcessCommandLineAlreadyRunningAfterBrowserClose) { + ScopedKeepAlive keep_alive(KeepAliveOrigin::BACKGROUND_MODE_MANAGER, + KeepAliveRestartOption::DISABLED); + CloseBrowserSynchronously(browser()); + + ProfileManager* profile_manager = g_browser_process->profile_manager(); + // Create a browser for a new profile. + Browser* test_browser = CreateBrowser(); + Profile* last_profile = test_browser->profile(); + ASSERT_TRUE(test_browser); + ASSERT_EQ(last_profile->IsGuestSession(), IsGuest()); + + std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive; + if (!IsGuest()) { + // Keep the profile alive to avoid unloading and immediately reloading it, + // which causes some flakiness within the HistoryService. + // This is not done for the guest profile because: + // - the test scenario does not involve reloading the guest profile, + // - it is not allowed to take a keep alive on a OTR profile. + profile_keep_alive = std::make_unique<ScopedProfileKeepAlive>( + last_profile, ProfileKeepAliveOrigin::kBackgroundMode); + } + + CloseBrowserSynchronously(test_browser); + // Closing the browser did not change the last used profile. + EXPECT_EQ(profile_manager->GetLastUsedProfileDir(), last_profile->GetPath()); + ASSERT_FALSE(ProfilePicker::IsOpen()); + + // Open a URL after the last active browser was closed. + OpenTabAlreadyRunning(); + + if (IsGuest()) { + // The profile picker opens. There is no browser, the URL is not loaded. + profiles::testing::WaitForPickerWidgetCreated(); + EXPECT_EQ(0u, BrowserList::GetInstance()->size()); + } else { + // The last used profile is reopened and the URL is loaded. + Browser* browser = ui_test_utils::WaitForBrowserToOpen(); + Profile* profile = browser->profile(); + EXPECT_FALSE(profile->IsGuestSession()); + TabStripModel* tab_strip = browser->tab_strip_model(); + EXPECT_EQ( + tab_strip->GetWebContentsAt(tab_strip->count() - 1)->GetVisibleURL(), + GetTestURL()); + EXPECT_FALSE(ProfilePicker::IsOpen()); + EXPECT_EQ(1u, BrowserList::GetInstance()->size()); + EXPECT_EQ(last_profile, profile); + } +} + +INSTANTIATE_TEST_SUITE_P(, + StartupBrowserCreatorTestWithGuestParam, + testing::Bool()); + class StartupBrowserWithRealWebAppTest : public StartupBrowserCreatorTest { protected: StartupBrowserWithRealWebAppTest() = default;
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index f4d78b6..97029ad 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -162,7 +162,6 @@ #include "chrome/browser/plugins/plugin_observer_android.h" #include "chrome/browser/ui/android/context_menu_helper.h" #include "chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_android.h" -#include "chrome/browser/video_tutorials/video_tutorial_tab_helper.h" #include "content/public/common/content_features.h" #else #include "chrome/browser/banners/app_banner_manager_desktop.h" @@ -475,7 +474,6 @@ } PolicyAuditorBridge::CreateForWebContents(web_contents); PluginObserverAndroid::CreateForWebContents(web_contents); - video_tutorials::VideoTutorialTabHelper::CreateForWebContents(web_contents); #else if (web_app::AreWebAppsUserInstallable(profile)) webapps::AppBannerManagerDesktop::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc index 04b42ffe..44bf5af 100644 --- a/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc +++ b/chrome/browser/ui/tabs/saved_tab_groups/saved_tab_group_keyed_service.cc
@@ -391,6 +391,12 @@ for (const SavedTabGroup& group : model()->saved_tab_groups()) { base::UmaHistogramCounts10000("TabGroups.SavedTabGroupTabCount", group.saved_tabs().size()); + + const base::TimeDelta duration_saved = + base::Time::Now() - group.creation_time_windows_epoch_micros(); + + base::UmaHistogramCounts1M("TabGroups.SavedTabGroupAge", + duration_saved.InMinutes()); } }
diff --git a/chrome/browser/ui/views/accessibility/accessibility_focus_highlight_browsertest.cc b/chrome/browser/ui/views/accessibility/accessibility_focus_highlight_browsertest.cc index 8d2f8a6..29fea0a 100644 --- a/chrome/browser/ui/views/accessibility/accessibility_focus_highlight_browsertest.cc +++ b/chrome/browser/ui/views/accessibility/accessibility_focus_highlight_browsertest.cc
@@ -178,7 +178,7 @@ content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); std::string script("document.getElementById('div').focus();"); - EXPECT_TRUE(content::ExecuteScript(web_contents, script)); + EXPECT_TRUE(content::ExecJs(web_contents, script)); // Now wait until at least 0.1% of the image has the focus ring's highlight // color. If it never does, the test will time out. @@ -201,7 +201,7 @@ browser()->tab_strip_model()->GetActiveWebContents(); content::FocusChangedObserver observer(web_contents); std::string script("document.getElementById('link').focus();"); - ASSERT_TRUE(content::ExecuteScript(web_contents, script)); + ASSERT_TRUE(content::ExecJs(web_contents, script)); auto details = observer.Wait(); gfx::Rect bounds = details.node_bounds_in_screen; @@ -271,7 +271,7 @@ browser()->tab_strip_model()->GetActiveWebContents(); content::FocusChangedObserver observer(web_contents); std::string script("document.getElementById('link').focus();"); - ASSERT_TRUE(content::ExecuteScript(web_contents, script)); + ASSERT_TRUE(content::ExecJs(web_contents, script)); observer.Wait(); BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser()); AccessibilityFocusHighlight* highlight =
diff --git a/chrome/browser/ui/views/autofill/autofill_accessibility_win_browsertest.cc b/chrome/browser/ui/views/autofill/autofill_accessibility_win_browsertest.cc index a9ace4f..506b610 100644 --- a/chrome/browser/ui/views/autofill/autofill_accessibility_win_browsertest.cc +++ b/chrome/browser/ui/views/autofill/autofill_accessibility_win_browsertest.cc
@@ -96,7 +96,7 @@ // Show drop down based on the element id. void ShowDropdown(const std::string& field_id) { std::string js("document.getElementById('" + field_id + "').focus();"); - ASSERT_TRUE(ExecuteScript(GetWebContents(), js)); + ASSERT_TRUE(ExecJs(GetWebContents(), js)); SendKeyToPage(GetWebContents(), ui::DomKey::ARROW_DOWN); }
diff --git a/chrome/browser/ui/views/autofill/payments/iban_bubble_view_uitest.cc b/chrome/browser/ui/views/autofill/payments/iban_bubble_view_uitest.cc index 918e17b..ae20f1a 100644 --- a/chrome/browser/ui/views/autofill/payments/iban_bubble_view_uitest.cc +++ b/chrome/browser/ui/views/autofill/payments/iban_bubble_view_uitest.cc
@@ -188,7 +188,7 @@ const std::string click_submit_button_js = "(function() { document.getElementById('submit').click(); })();"; content::TestNavigationObserver nav_observer(web_contents); - ASSERT_TRUE(content::ExecuteScript(web_contents, click_submit_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_submit_button_js)); nav_observer.Wait(); } @@ -198,13 +198,13 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); if (iban_value.has_value()) { std::string set_value_js = "(function() { document.getElementById('iban').value ='" + iban_value.value() + "';})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, set_value_js)); + ASSERT_TRUE(content::ExecJs(web_contents, set_value_js)); } }
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_uitest.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_uitest.cc index c87de90c..a72c662 100644 --- a/chrome/browser/ui/views/autofill/payments/local_card_migration_uitest.cc +++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_uitest.cc
@@ -187,7 +187,10 @@ RECEIVED_MIGRATE_CARDS_RESPONSE }; - LocalCardMigrationBrowserTest() : SyncTest(SINGLE_CLIENT) {} + LocalCardMigrationBrowserTest() : SyncTest(SINGLE_CLIENT) { + feature_list_.InitAndDisableFeature( + features::kAutofillEnableNewCardArtAndNetworkImages); + } ~LocalCardMigrationBrowserTest() override {} @@ -367,17 +370,17 @@ const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string fill_cc_number_js = "(function() { document.getElementsByName(\"cc_number\")[0].value = " + card_number + "; })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, fill_cc_number_js)); + ASSERT_TRUE(content::ExecJs(web_contents, fill_cc_number_js)); const std::string click_submit_button_js = "(function() { document.getElementById('submit').click(); })();"; content::TestNavigationObserver nav_observer(web_contents); - ASSERT_TRUE(content::ExecuteScript(web_contents, click_submit_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_submit_button_js)); nav_observer.Wait(); } @@ -535,6 +538,7 @@ network::TestURLLoaderFactory test_url_loader_factory_; scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_; std::unique_ptr<device::ScopedGeolocationOverrider> geolocation_overrider_; + base::test::ScopedFeatureList feature_list_; }; class LocalCardMigrationBrowserUiTest
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc index 0fe2d3a..e154a6d 100644 --- a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc +++ b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
@@ -388,7 +388,7 @@ const std::string click_submit_button_js = "(function() { document.getElementById('submit').click(); })();"; content::TestNavigationObserver nav_observer(web_contents); - ASSERT_TRUE(content::ExecuteScript(web_contents, click_submit_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_submit_button_js)); nav_observer.Wait(); } @@ -398,7 +398,7 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); } // Should be called for credit_card_upload_form_cc.html. @@ -408,10 +408,9 @@ "(function() { document.getElementById('fill_form').click(); })();"; const std::string click_add_fields_button_js = "(function() { document.getElementById('add_fields').click(); })();"; + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), click_fill_button_js)); ASSERT_TRUE( - content::ExecuteScript(GetActiveWebContents(), click_fill_button_js)); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - click_add_fields_button_js)); + content::ExecJs(GetActiveWebContents(), click_add_fields_button_js)); } void FillFormWithCardDetailsOnly() { @@ -420,8 +419,7 @@ const std::string click_fill_card_button_js = "(function() { document.getElementById('fill_card_only').click(); " "})();"; - ASSERT_TRUE( - content::ExecuteScript(web_contents, click_fill_card_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_card_button_js)); } // Should be called for credit_card_upload_form_address_and_cc.html. @@ -430,12 +428,11 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string click_clear_cvc_button_js = "(function() { document.getElementById('clear_cvc').click(); })();"; - ASSERT_TRUE( - content::ExecuteScript(web_contents, click_clear_cvc_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_clear_cvc_button_js)); } // Should be called for credit_card_upload_form_address_and_cc.html. @@ -444,13 +441,13 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string click_fill_invalid_cvc_button_js = "(function() { document.getElementById('fill_invalid_cvc').click(); " "})();"; ASSERT_TRUE( - content::ExecuteScript(web_contents, click_fill_invalid_cvc_button_js)); + content::ExecJs(web_contents, click_fill_invalid_cvc_button_js)); } // Should be called for credit_card_upload_form_address_and_cc.html. @@ -459,12 +456,11 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string click_clear_name_button_js = "(function() { document.getElementById('clear_name').click(); })();"; - ASSERT_TRUE( - content::ExecuteScript(web_contents, click_clear_name_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_clear_name_button_js)); } // Should be called for credit_card_upload_form_shipping_address.html. @@ -473,13 +469,13 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string click_conflicting_name_button_js = "(function() { document.getElementById('conflicting_name').click(); " "})();"; ASSERT_TRUE( - content::ExecuteScript(web_contents, click_conflicting_name_button_js)); + content::ExecJs(web_contents, click_conflicting_name_button_js)); } // Should be called for credit_card_upload_form_address_and_cc.html. @@ -488,14 +484,14 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string click_clear_expiration_date_button_js = "(function() { " "document.getElementById('clear_expiration_date').click(); " "})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, - click_clear_expiration_date_button_js)); + ASSERT_TRUE( + content::ExecJs(web_contents, click_clear_expiration_date_button_js)); } // Should be called for credit_card_upload_form_address_and_cc.html. @@ -504,19 +500,19 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string click_clear_expiration_date_button_js = "(function() { " "document.getElementById('clear_expiration_date').click(); " "})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, - click_clear_expiration_date_button_js)); + ASSERT_TRUE( + content::ExecJs(web_contents, click_clear_expiration_date_button_js)); std::string set_month_js = "(function() { document.getElementById('cc_month_exp_id').value =" + month + ";})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, set_month_js)); + ASSERT_TRUE(content::ExecJs(web_contents, set_month_js)); } // Should be called for credit_card_upload_form_address_and_cc.html. @@ -525,19 +521,19 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string click_clear_expiration_date_button_js = "(function() { " "document.getElementById('clear_expiration_date').click(); " "})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, - click_clear_expiration_date_button_js)); + ASSERT_TRUE( + content::ExecJs(web_contents, click_clear_expiration_date_button_js)); std::string set_year_js = "(function() { document.getElementById('cc_year_exp_id').value =" + year + ";})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, set_year_js)); + ASSERT_TRUE(content::ExecJs(web_contents, set_year_js)); } // Should be called for credit_card_upload_form_address_and_cc.html. @@ -547,17 +543,17 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); std::string set_month_js = "(function() { document.getElementById('cc_month_exp_id').value =" + month + ";})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, set_month_js)); + ASSERT_TRUE(content::ExecJs(web_contents, set_month_js)); std::string set_year_js = "(function() { document.getElementById('cc_year_exp_id').value =" + year + ";})();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, set_year_js)); + ASSERT_TRUE(content::ExecJs(web_contents, set_year_js)); } // Should be called for credit_card_upload_form_address_and_cc.html. @@ -566,12 +562,11 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string click_clear_address_button_js = "(function() { document.getElementById('clear_address').click(); })();"; - ASSERT_TRUE( - content::ExecuteScript(web_contents, click_clear_address_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_clear_address_button_js)); } // Should be called for credit_card_upload_form_shipping_address.html. @@ -580,13 +575,13 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_fill_button_js = "(function() { document.getElementById('fill_form').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_fill_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_fill_button_js)); const std::string click_conflicting_postal_code_button_js = "(function() { " "document.getElementById('conflicting_postal_code').click(); })();"; - ASSERT_TRUE(content::ExecuteScript( - web_contents, click_conflicting_postal_code_button_js)); + ASSERT_TRUE( + content::ExecJs(web_contents, click_conflicting_postal_code_button_js)); } void SetUploadDetailsRpcPaymentsAccepts() {
diff --git a/chrome/browser/ui/views/chrome_typography_provider.cc b/chrome/browser/ui/views/chrome_typography_provider.cc index 420a64fe..4f1c63fe 100644 --- a/chrome/browser/ui/views/chrome_typography_provider.cc +++ b/chrome/browser/ui/views/chrome_typography_provider.cc
@@ -8,8 +8,10 @@ #include "build/chromeos_buildflags.h" #include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/views/chrome_typography.h" +#include "ui/base/default_style.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/theme_provider.h" +#include "ui/base/ui_base_features.h" #include "ui/color/color_id.h" #include "ui/gfx/color_palette.h" #include "ui/gfx/color_utils.h" @@ -57,6 +59,9 @@ break; case views::style::CONTEXT_BUTTON_MD: details.weight = MediumWeightForUI(); + details.size_delta = features::IsChromeRefresh2023() + ? ui::kLabelFontSizeDeltaChromeRefresh2023 + : ui::kLabelFontSizeDelta; break; case views::style::CONTEXT_DIALOG_TITLE: details.size_delta = kTitleSize - gfx::PlatformFont::kDefaultBaseFontSize;
diff --git a/chrome/browser/ui/views/content_test_utils.cc b/chrome/browser/ui/views/content_test_utils.cc index 5bbec078..a6fc8da8 100644 --- a/chrome/browser/ui/views/content_test_utils.cc +++ b/chrome/browser/ui/views/content_test_utils.cc
@@ -31,7 +31,7 @@ void TestTextInputViaKeyEvent(content::WebContents* contents) { // Replace the dialog content with a single text input element and focus it. ASSERT_TRUE(content::WaitForLoadStop(contents)); - ASSERT_TRUE(content::ExecuteScript(contents, R"( + ASSERT_TRUE(content::ExecJs(contents, R"( document.body.innerHTML = trustedTypes.emptyHTML; const input = document.createElement('input'); input.type = 'text';
diff --git a/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc b/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc index 4749a94..df336df 100644 --- a/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc +++ b/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.cc
@@ -6,18 +6,43 @@ #include "base/task/bind_post_task.h" #include "base/task/thread_pool.h" +#include "chrome/browser/favicon/favicon_utils.h" #include "chrome/browser/media/webrtc/desktop_media_picker_utils.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_widget_host_view.h" #include "media/base/video_util.h" #include "ui/gfx/image/image_skia_operations.h" +#include "ui/gfx/text_constants.h" #include "ui/views/layout/box_layout.h" namespace { -constexpr gfx::Size kPreviewSize(320, 240); +// Base UI measurements +constexpr int kPreviewWidth = 320; +constexpr int kPreviewHeight = 240; constexpr int kPadding = 8; +constexpr int kFaviconWidth = 16; +constexpr int kFaviconHeight = kFaviconWidth; +constexpr int kFaviconTabTitleRowHeight = 20; + +// Derived UI measurements +constexpr int kFaviconExtraPadding = + (kFaviconTabTitleRowHeight - kFaviconHeight) / 2; +constexpr gfx::Rect kPreviewRect(kPadding, + kPadding, + kPreviewWidth, + kPreviewHeight); +constexpr gfx::Rect kFaviconRect(kPadding, + kPreviewRect.bottom() + kPadding + + kFaviconExtraPadding, + kFaviconWidth, + kFaviconTabTitleRowHeight); +constexpr gfx::Rect kTabTitleMaxRect(kFaviconRect.right() + kPadding, + kPreviewRect.bottom() + kPadding, + kPreviewWidth - kFaviconWidth - kPadding, + kFaviconTabTitleRowHeight); + constexpr base::TimeDelta kUpdatePeriodMs = base::Milliseconds(250); void HandleCapturedBitmap( @@ -48,6 +73,8 @@ : web_contents_(web_contents), thumbnail_task_runner_(base::ThreadPool::CreateSequencedTaskRunner( {base::MayBlock(), base::TaskPriority::USER_VISIBLE})) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + CHECK(web_contents_); View* throbber_container = AddChildView(std::make_unique<views::View>()); views::BoxLayout* throbber_layout = throbber_container->SetLayoutManager(std::make_unique<views::BoxLayout>( @@ -57,8 +84,7 @@ throbber_layout->set_cross_axis_alignment( views::BoxLayout::CrossAxisAlignment::kCenter); // TODO(crbug.com/1428878): Use distances from LayoutProvider - throbber_container->SetBoundsRect( - gfx::Rect(gfx::Point(kPadding, kPadding), kPreviewSize)); + throbber_container->SetBoundsRect(kPreviewRect); throbber_container->SetCanProcessEventsWithinSubtree(false); throbber_ = throbber_container->AddChildView(std::make_unique<views::Throbber>()); @@ -66,12 +92,25 @@ image_view_ = AddChildView(std::make_unique<views::ImageView>()); image_view_->SetVisible(false); - image_view_->SetBoundsRect(gfx::Rect(8, 8, 320, 240)); + image_view_->SetBoundsRect(kPreviewRect); + + favicon_view_ = AddChildView(std::make_unique<views::ImageView>()); + favicon_view_->SetBoundsRect(kFaviconRect); + + tab_title_label_ = AddChildView(std::make_unique<views::Label>()); + tab_title_label_->SetBoundsRect(kTabTitleMaxRect); + tab_title_label_->SetHorizontalAlignment( + gfx::HorizontalAlignment::ALIGN_LEFT); + tab_title_label_->SetVerticalAlignment(gfx::VerticalAlignment::ALIGN_MIDDLE); + tab_title_label_->SetElideBehavior(gfx::ElideBehavior::ELIDE_TAIL); + + UpdateFaviconAndTabTitle(); } ShareThisTabSourceView::~ShareThisTabSourceView() = default; void ShareThisTabSourceView::Activate() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); throbber_->Stop(); throbber_->SetVisible(false); image_view_->SetVisible(true); @@ -80,12 +119,29 @@ } void ShareThisTabSourceView::StopRefreshing() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); refreshing_ = false; } gfx::Size ShareThisTabSourceView::CalculatePreferredSize() const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // TODO(crbug.com/1428878): Use distances from LayoutProvider - return kPreviewSize + gfx::Size(2 * kPadding, 2 * kPadding); + return gfx::Size(kPreviewWidth + 2 * kPadding, + kTabTitleMaxRect.bottom() + kPadding); +} + +void ShareThisTabSourceView::UpdateFaviconAndTabTitle() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + if (!web_contents_) { + return; + } + + const gfx::Image favicon = + favicon::TabFaviconFromWebContents(web_contents_.get()); + favicon_view_->SetImage(ui::ImageModel::FromImage( + favicon.IsEmpty() ? favicon::GetDefaultFavicon() : favicon)); + + tab_title_label_->SetText(web_contents_->GetTitle()); } void ShareThisTabSourceView::Refresh() { @@ -112,7 +168,7 @@ gfx::Rect(), gfx::Size(), base::BindPostTask(thumbnail_task_runner_, base::BindOnce(&HandleCapturedBitmap, std::move(reply), - last_hash_, gfx::Size(320, 240)))); + last_hash_, kPreviewRect.size()))); } void ShareThisTabSourceView::OnCaptureHandled( @@ -121,6 +177,8 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); CHECK((hash != last_hash_) == image.has_value()); // Only new frames passed. + UpdateFaviconAndTabTitle(); + if (hash != last_hash_) { last_hash_ = hash; image_view_->SetImage(image.value());
diff --git a/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.h b/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.h index 913b0d6..d580e33 100644 --- a/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.h +++ b/chrome/browser/ui/views/desktop_capture/share_this_tab_source_view.h
@@ -9,6 +9,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_media_capture_id.h" #include "ui/views/controls/image_view.h" +#include "ui/views/controls/label.h" #include "ui/views/controls/throbber.h" #include "ui/views/view.h" @@ -29,6 +30,8 @@ gfx::Size CalculatePreferredSize() const override; private: + void UpdateFaviconAndTabTitle(); + void Refresh(); // Called on the UI thread after the captured image is handled. If the @@ -40,6 +43,8 @@ raw_ptr<views::Throbber> throbber_ = nullptr; raw_ptr<views::ImageView> image_view_ = nullptr; + raw_ptr<views::ImageView> favicon_view_ = nullptr; + raw_ptr<views::Label> tab_title_label_ = nullptr; // The capturing tab's WebContent const base::WeakPtr<content::WebContents> web_contents_;
diff --git a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc index 1ea4622..abd856f5 100644 --- a/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc +++ b/chrome/browser/ui/views/drag_and_drop_interactive_uitest.cc
@@ -1640,9 +1640,9 @@ DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState* state) { // Delete the left frame in an attempt to repro https://crbug.com/670123. content::RenderFrameDeletedObserver frame_deleted_observer(GetLeftFrame()); - ASSERT_TRUE(ExecuteScript(web_contents()->GetPrimaryMainFrame(), - "frame = document.getElementById('left');\n" - "frame.parentNode.removeChild(frame);\n")); + ASSERT_TRUE(ExecJs(web_contents()->GetPrimaryMainFrame(), + "frame = document.getElementById('left');\n" + "frame.parentNode.removeChild(frame);\n")); frame_deleted_observer.WaitUntilDeleted(); // While dragging, move mouse from the left into the right frame. @@ -2154,12 +2154,12 @@ ui_test_utils::TabAddedWaiter wait_for_new_tab(browser()); // Create a new tab that closes itself on dragover event. - ASSERT_TRUE(ExecuteScript(browser() - ->tab_strip_model() - ->GetActiveWebContents() - ->GetPrimaryMainFrame(), - "window.open('javascript:document.addEventListener(" - "\"dragover\", () => {window.close(); })');")); + ASSERT_TRUE(ExecJs(browser() + ->tab_strip_model() + ->GetActiveWebContents() + ->GetPrimaryMainFrame(), + "window.open('javascript:document.addEventListener(" + "\"dragover\", () => {window.close(); })');")); wait_for_new_tab.Wait();
diff --git a/chrome/browser/ui/views/extensions/extension_dialog_interactive_uitest.cc b/chrome/browser/ui/views/extensions/extension_dialog_interactive_uitest.cc index 5304d22c..3a782922 100644 --- a/chrome/browser/ui/views/extensions/extension_dialog_interactive_uitest.cc +++ b/chrome/browser/ui/views/extensions/extension_dialog_interactive_uitest.cc
@@ -57,9 +57,8 @@ ASSERT_TRUE(init_listener.WaitUntilSatisfied()); // Focus the second button. - ASSERT_TRUE( - content::ExecuteScript(dialog->host()->host_contents(), - "document.querySelector('#button2').focus()")); + ASSERT_TRUE(content::ExecJs(dialog->host()->host_contents(), + "document.querySelector('#button2').focus()")); ASSERT_TRUE(button2_focus_listener.WaitUntilSatisfied()); // Pressing TAB should focus the third(last) button.
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index 3eb7c4b..af76a66b 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -192,6 +192,7 @@ #if BUILDFLAG(IS_MAC) views::Widget* overlay_widget() { return overlay_widget_.get(); } + views::View* overlay_view() { return overlay_view_.get(); } views::Widget* tab_overlay_widget() { return tab_overlay_widget_.get(); } views::View* tab_overlay_view() { return tab_overlay_view_.get(); }
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm b/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm index 2dbd49f..b65ce757 100644 --- a/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm +++ b/chrome/browser/ui/views/frame/immersive_mode_controller_mac.mm
@@ -6,11 +6,14 @@ #include "chrome/browser/ui/views/frame/immersive_mode_controller_mac.h" +#include <vector> + #include "base/check.h" #include "base/mac/foundation_util.h" #include "base/mac/scoped_nsobject.h" #include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" +#include "base/ranges/algorithm.h" #include "chrome/browser/ui/find_bar/find_bar.h" #include "chrome/browser/ui/find_bar/find_bar_controller.h" #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.h" @@ -26,6 +29,7 @@ #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/cocoa/native_widget_mac_ns_window_host.h" #include "ui/views/focus/focus_manager.h" +#include "ui/views/focus/focus_search.h" #include "ui/views/view_observer.h" #include "ui/views/widget/widget.h" @@ -41,7 +45,8 @@ class ImmersiveModeControllerMac : public ImmersiveModeController, public views::FocusChangeListener, public views::ViewObserver, - public views::WidgetObserver { + public views::WidgetObserver, + public views::FocusTraversable { public: class RevealedLock : public ImmersiveRevealedLock { public: @@ -94,6 +99,11 @@ // views::WidgetObserver implementation void OnWidgetDestroying(views::Widget* widget) override; + // views::Traversable: + views::FocusSearch* GetFocusSearch() override; + views::FocusTraversable* GetFocusTraversableParent() override; + views::View* GetFocusTraversableParentView() override; + BrowserView* browser_view() { return browser_view_; } private: @@ -116,6 +126,8 @@ base::ScopedObservation<views::Widget, views::WidgetObserver> browser_frame_observation_{this}; + std::unique_ptr<views::FocusSearch> focus_search_; + // Used as a convenience to access // NativeWidgetMacNSWindowHost::GetNSWindowMojo(). raw_ptr<remote_cocoa::mojom::NativeWidgetNSWindow> ns_window_mojo_ = @@ -129,6 +141,28 @@ base::WeakPtrFactory<ImmersiveModeControllerMac> weak_ptr_factory_; }; +class ImmersiveModeFocusSearchMac : public views::FocusSearch { + public: + explicit ImmersiveModeFocusSearchMac(BrowserView* browser_view); + ImmersiveModeFocusSearchMac(const ImmersiveModeFocusSearchMac&) = delete; + ImmersiveModeFocusSearchMac& operator=(const ImmersiveModeFocusSearchMac&) = + delete; + ~ImmersiveModeFocusSearchMac() override; + + // views::FocusSearch: + views::View* FindNextFocusableView( + views::View* starting_view, + SearchDirection search_direction, + TraversalDirection traversal_direction, + StartingViewPolicy check_starting_view, + AnchoredDialogPolicy can_go_into_anchored_dialog, + views::FocusTraversable** focus_traversable, + views::View** focus_traversable_view) override; + + private: + raw_ptr<BrowserView> browser_view_; +}; + } // namespace ImmersiveModeControllerMac::RevealedLock::RevealedLock( @@ -152,6 +186,7 @@ ns_window_mojo_ = views::NativeWidgetMacNSWindowHost::GetFromNativeWindow( browser_view_->GetWidget()->GetNativeWindow()) ->GetNSWindowMojo(); + focus_search_ = std::make_unique<ImmersiveModeFocusSearchMac>(browser_view); } void ImmersiveModeControllerMac::SetEnabled(bool enabled) { @@ -194,6 +229,19 @@ ns_window_mojo_->EnableImmersiveFullscreen( overlay_host->bridged_native_widget_id(), tab_native_widget_id_); + // Set up a root FocusTraversable that handles focus cycles between overlay + // widgets and the browser widget. + browser_view_->GetWidget()->SetFocusTraversableParent(this); + browser_view_->GetWidget()->SetFocusTraversableParentView(browser_view_); + browser_view_->overlay_widget()->SetFocusTraversableParent(this); + browser_view_->overlay_widget()->SetFocusTraversableParentView( + browser_view_->overlay_view()); + if (browser_view_->tab_overlay_widget()) { + browser_view_->tab_overlay_widget()->SetFocusTraversableParent(this); + browser_view_->tab_overlay_widget()->SetFocusTraversableParentView( + browser_view_->tab_overlay_view()); + } + // If the window is maximized OnViewBoundsChanged will not be called // when transitioning to full screen. Call it now. OnViewBoundsChanged(browser_view_->top_container()); @@ -216,6 +264,17 @@ ns_window_mojo_->DisableImmersiveFullscreen(); browser_view_->overlay_widget()->SetNativeWindowProperty( views::NativeWidgetMacNSWindowHost::kImmersiveContentNSView, nullptr); + + // Remove the root FocusTraversable. + browser_view_->GetWidget()->SetFocusTraversableParent(nullptr); + browser_view_->GetWidget()->SetFocusTraversableParentView(nullptr); + browser_view_->overlay_widget()->SetFocusTraversableParent(nullptr); + browser_view_->overlay_widget()->SetFocusTraversableParentView(nullptr); + if (browser_view_->tab_overlay_widget()) { + browser_view_->tab_overlay_widget()->SetFocusTraversableParent(nullptr); + browser_view_->tab_overlay_widget()->SetFocusTraversableParentView( + nullptr); + } } } @@ -432,6 +491,79 @@ ImmersiveModeControllerMac::OnViewBoundsChanged(observed_view); } +views::FocusSearch* ImmersiveModeControllerMac::GetFocusSearch() { + return focus_search_.get(); +} + +views::FocusTraversable* +ImmersiveModeControllerMac::GetFocusTraversableParent() { + return nullptr; +} + +views::View* ImmersiveModeControllerMac::GetFocusTraversableParentView() { + return nullptr; +} + +ImmersiveModeFocusSearchMac::ImmersiveModeFocusSearchMac( + BrowserView* browser_view) + : views::FocusSearch(browser_view, true, true), + browser_view_(browser_view) {} + +ImmersiveModeFocusSearchMac::~ImmersiveModeFocusSearchMac() = default; + +views::View* ImmersiveModeFocusSearchMac::FindNextFocusableView( + views::View* starting_view, + SearchDirection search_direction, + TraversalDirection traversal_direction, + StartingViewPolicy check_starting_view, + AnchoredDialogPolicy can_go_into_anchored_dialog, + views::FocusTraversable** focus_traversable, + views::View** focus_traversable_view) { + // Search in the `starting_view` traversable tree. + views::FocusTraversable* starting_focus_traversable = + starting_view->GetFocusTraversable(); + if (!starting_focus_traversable) { + starting_focus_traversable = + starting_view->GetWidget()->GetFocusTraversable(); + } + + views::View* v = + starting_focus_traversable->GetFocusSearch()->FindNextFocusableView( + starting_view, search_direction, traversal_direction, + check_starting_view, can_go_into_anchored_dialog, focus_traversable, + focus_traversable_view); + + if (v) { + return v; + } + + // If no next focusable view in the `starting_view` traversable tree, + // jumps to the next widget. + views::FocusManager* focus_manager = + browser_view_->GetWidget()->GetFocusManager(); + + // The focus cycles between overlay widget(s) and the browser widget. + std::vector<views::Widget*> traverse_order = {browser_view_->overlay_widget(), + browser_view_->GetWidget()}; + if (browser_view_->tab_overlay_widget()) { + traverse_order.push_back(browser_view_->tab_overlay_widget()); + } + + auto current_widget_it = base::ranges::find_if( + traverse_order, [starting_view](const views::Widget* widget) { + return widget->GetRootView()->Contains(starting_view); + }); + CHECK(current_widget_it != traverse_order.end()); + int current_widget_ind = current_widget_it - traverse_order.begin(); + + bool reverse = search_direction == SearchDirection::kBackwards; + int next_widget_ind = + (current_widget_ind + (reverse ? -1 : 1) + traverse_order.size()) % + traverse_order.size(); + return focus_manager->GetNextFocusableView( + nullptr, traverse_order[next_widget_ind], reverse, true); +} + std::unique_ptr<ImmersiveModeController> CreateImmersiveModeControllerMac( const BrowserView* browser_view) { if (browser_view->UsesImmersiveFullscreenTabbedMode()) {
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc index d27ff17..19e27f90 100644 --- a/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/intent_picker_bubble_view_browsertest.cc
@@ -73,11 +73,10 @@ // Inserts an iframe in the main frame of |web_contents|. bool InsertIFrame(content::WebContents* web_contents) { - return content::ExecuteScript( - web_contents, - "let iframe = document.createElement('iframe');" - "iframe.id = 'iframe';" - "document.body.appendChild(iframe);"); + return content::ExecJs(web_contents, + "let iframe = document.createElement('iframe');" + "iframe.id = 'iframe';" + "document.body.appendChild(iframe);"); } views::Button* GetIntentPickerIcon() {
diff --git a/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc b/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc index 0768970..cfb11eb 100644 --- a/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc +++ b/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc
@@ -192,7 +192,7 @@ ASSERT_TRUE(ui_test_utils::NavigateToURL( browser(), embedded_test_server()->GetURL("/popup_blocker/popup-many-10.html"))); - EXPECT_TRUE(content::ExecuteScript(web_contents, std::string())); + EXPECT_TRUE(content::ExecJs(web_contents, std::string())); auto* helper = blocked_content::PopupBlockerTabHelper::FromWebContents(web_contents); // popup-many-10.html should generate 10 blocked popups.
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc b/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc index c4faa6c1..13bca4d 100644 --- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc +++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
@@ -92,7 +92,7 @@ std::string script = "window.open('" + target_url.spec() + "', 'popup', 'width=400 height=400');"; - EXPECT_TRUE(content::ExecuteScript(web_contents, script)); + EXPECT_TRUE(content::ExecJs(web_contents, script)); nav_observer.Wait(); return browser_change_observer.Wait(); @@ -104,7 +104,7 @@ content::TestNavigationObserver nav_observer(web_contents); std::string script = "window.location = '" + target_url.spec() + "';"; - EXPECT_TRUE(content::ExecuteScript(web_contents, script)); + EXPECT_TRUE(content::ExecJs(web_contents, script)); nav_observer.Wait(); } @@ -119,7 +119,7 @@ TestTitleObserver title_observer(web_contents, title); std::string script = "document.title = '" + base::UTF16ToASCII(title) + "';"; - EXPECT_TRUE(content::ExecuteScript(web_contents, script)); + EXPECT_TRUE(content::ExecJs(web_contents, script)); title_observer.Wait(); } @@ -522,7 +522,7 @@ // Do a state replacing navigation, so we don't have any in scope urls in // history. content::TestNavigationObserver nav_observer(web_contents); - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( web_contents, "window.location.replace('http://example.com');")); nav_observer.Wait(); EXPECT_TRUE(app_controller_->ShouldShowCustomTabBar()); @@ -717,7 +717,7 @@ " new Blob([], {type: 'text/html'})" " )," " '_self');"; - EXPECT_TRUE(content::ExecuteScript(web_contents, script)); + EXPECT_TRUE(content::ExecJs(web_contents, script)); nav_observer.Wait(); EXPECT_EQ(
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc index 182c801f..e72c4cc 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.cc +++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -177,15 +177,15 @@ set_suppress_default_focus_handling(); if (!is_popup_mode_) { views::FocusRing::Install(this); - views::FocusRing::Get(this)->SetHasFocusPredicate([](View* view) -> bool { - DCHECK(views::IsViewClass<LocationBarView>(view)); - auto* v = static_cast<LocationBarView*>(view); - - // Show focus ring when the Omnibox is visibly focused and the popup is - // closed. - return v->omnibox_view_->model()->is_caret_visible() && - !v->GetOmniboxPopupView()->IsOpen(); - }); + views::FocusRing::Get(this)->SetHasFocusPredicate( + base::BindRepeating([](const View* view) { + const auto* v = views::AsViewClass<LocationBarView>(view); + CHECK(v); + // Show focus ring when the Omnibox is visibly focused and the popup + // is closed. + return v->omnibox_view_->model()->is_caret_visible() && + !v->GetOmniboxPopupView()->IsOpen(); + })); if (features::IsChromeRefresh2023()) { views::FocusRing::Get(this)->SetOutsetFocusRingDisabled(true); } @@ -1115,6 +1115,11 @@ } OmniboxPopupView* LocationBarView::GetOmniboxPopupView() { + return const_cast<OmniboxPopupView*>( + std::as_const(*this).GetOmniboxPopupView()); +} + +const OmniboxPopupView* LocationBarView::GetOmniboxPopupView() const { DCHECK(IsInitialized()); return omnibox_view_->model()->get_popup_view(); }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h index 1c7a736..5817354 100644 --- a/chrome/browser/ui/views/location_bar/location_bar_view.h +++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -305,6 +305,7 @@ // Gets the OmniboxPopupView associated with the model in |omnibox_view_|. OmniboxPopupView* GetOmniboxPopupView(); + const OmniboxPopupView* GetOmniboxPopupView() const; // Called when the page info bubble is closed. void OnPageInfoBubbleClosed(views::Widget::ClosedReason closed_reason,
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc index f9211d7..3bfa3ec 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -207,11 +207,13 @@ remove_suggestion_button_->SetTooltipText( l10n_util::GetStringUTF16(IDS_OMNIBOX_REMOVE_SUGGESTION)); auto* const focus_ring = views::FocusRing::Get(remove_suggestion_button_); - focus_ring->SetHasFocusPredicate([&](View* view) { - return view->GetVisible() && GetMatchSelected() && - (popup_view_->GetSelection().state == - OmniboxPopupSelection::FOCUSED_BUTTON_REMOVE_SUGGESTION); - }); + focus_ring->SetHasFocusPredicate(base::BindRepeating( + [](const OmniboxResultView* results, const View* view) { + return view->GetVisible() && results->GetMatchSelected() && + (results->popup_view_->GetSelection().state == + OmniboxPopupSelection::FOCUSED_BUTTON_REMOVE_SUGGESTION); + }, + base::Unretained(this))); focus_ring->SetColorId(kColorOmniboxResultsFocusIndicator); button_row_ = AddChildView(std::make_unique<OmniboxSuggestionButtonRowView>(
diff --git a/chrome/browser/ui/views/omnibox/omnibox_row_view.cc b/chrome/browser/ui/views/omnibox/omnibox_row_view.cc index 7f0c0b8..4720ecc 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_row_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_row_view.cc
@@ -75,10 +75,13 @@ views::FocusRing::Install(header_toggle_button_); views::FocusRing::Get(header_toggle_button_) - ->SetHasFocusPredicate([&](View* view) { - return view->GetVisible() && - row_view_->model_->GetPopupSelection() == GetHeaderSelection(); - }); + ->SetHasFocusPredicate(base::BindRepeating( + [](const HeaderView* header, const View* view) { + return view->GetVisible() && + header->row_view_->model_->GetPopupSelection() == + header->GetHeaderSelection(); + }, + base::Unretained(this))); if (row_view_->pref_service_) { pref_change_registrar_.Init(row_view_->pref_service_);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc index a6f8a921..c996b26c 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_suggestion_button_row_view.cc
@@ -44,6 +44,7 @@ #include "ui/views/layout/flex_layout.h" #include "ui/views/painter.h" #include "ui/views/view_class_properties.h" +#include "ui/views/view_utils.h" class OmniboxSuggestionRowButton : public views::MdTextButton { public: @@ -83,10 +84,12 @@ ink_drop->GetInkDrop()->SetHoverHighlightFadeDuration(base::TimeDelta()); auto* const focus_ring = views::FocusRing::Get(this); - focus_ring->SetHasFocusPredicate([=](View* view) { - return view->GetVisible() && - popup_contents_view_->GetSelection() == selection_; - }); + focus_ring->SetHasFocusPredicate(base::BindRepeating([](const View* view) { + const auto* v = views::AsViewClass<OmniboxSuggestionRowButton>(view); + CHECK(v); + return v->GetVisible() && + v->popup_contents_view_->GetSelection() == v->selection_; + })); focus_ring->SetColorId(kColorOmniboxResultsFocusIndicator); }
diff --git a/chrome/browser/ui/views/payments/contact_info_editor_view_controller_browsertest.cc b/chrome/browser/ui/views/payments/contact_info_editor_view_controller_browsertest.cc index 3b003b75e..05269c4 100644 --- a/chrome/browser/ui/views/payments/contact_info_editor_view_controller_browsertest.cc +++ b/chrome/browser/ui/views/payments/contact_info_editor_view_controller_browsertest.cc
@@ -441,14 +441,14 @@ DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION, DialogEvent::CONTACT_INFO_EDITOR_OPENED}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "retry({" - " payer: {" - " email: 'EMAIL ERROR'," - " name: 'NAME ERROR'," - " phone: 'PHONE ERROR'" - " }" - "});")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "retry({" + " payer: {" + " email: 'EMAIL ERROR'," + " name: 'NAME ERROR'," + " phone: 'PHONE ERROR'" + " }" + "});")); ASSERT_TRUE(WaitForObservedEvent()); EXPECT_EQ(u"EMAIL ERROR", GetErrorLabelForType(autofill::EMAIL_ADDRESS)); @@ -496,14 +496,14 @@ DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION, DialogEvent::CONTACT_INFO_EDITOR_OPENED}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "retry({" - " payer: {" - " email: 'EMAIL ERROR'," - " name: 'NAME ERROR'," - " phone: 'PHONE ERROR'" - " }" - "});")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "retry({" + " payer: {" + " email: 'EMAIL ERROR'," + " name: 'NAME ERROR'," + " phone: 'PHONE ERROR'" + " }" + "});")); ASSERT_TRUE(WaitForObservedEvent()); EXPECT_EQ(u"EMAIL ERROR", GetErrorLabelForType(autofill::EMAIL_ADDRESS)); @@ -546,14 +546,14 @@ DialogEvent::SPEC_DONE_UPDATING, DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "retry({" - " payer: {" - " email: 'EMAIL ERROR'," - " name: 'NAME ERROR'," - " phone: 'PHONE ERROR'" - " }" - "});")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "retry({" + " payer: {" + " email: 'EMAIL ERROR'," + " name: 'NAME ERROR'," + " phone: 'PHONE ERROR'" + " }" + "});")); ASSERT_TRUE(WaitForObservedEvent()); const int kErrorLabelOffset =
diff --git a/chrome/browser/ui/views/payments/payment_request_blob_url_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_blob_url_browsertest.cc index c616758..559c65b 100644 --- a/chrome/browser/ui/views/payments/payment_request_blob_url_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_blob_url_browsertest.cc
@@ -18,7 +18,7 @@ NavigateTo("/payment_request_blob_url_test.html"); // Trigger the Blob URL load, and wait for it to finish. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( GetActiveWebContents(), "(function() { document.getElementById('buy').click(); })();")); WaitForLoadStop(GetActiveWebContents());
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_browsertest.cc index 0de564b..9073f017 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
@@ -169,7 +169,7 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_buy_button_js = "(function() { document.getElementById('abort').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_buy_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_buy_button_js)); ASSERT_TRUE(WaitForObservedEvent());
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc index cc68557..e4dfd27d 100644 --- a/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc +++ b/chrome/browser/ui/views/payments/payment_request_browsertest_base.cc
@@ -308,7 +308,8 @@ ResetEventWaiterForDialogOpened(); content::WebContents* web_contents = GetActiveWebContents(); - ASSERT_TRUE(content::ExecuteScript(web_contents, click_buy_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_buy_button_js, + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); ASSERT_TRUE(WaitForObservedEvent()); @@ -676,8 +677,8 @@ DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "retry(" + validation_errors + ");")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "retry(" + validation_errors + ");")); ASSERT_TRUE(WaitForObservedEvent()); } @@ -692,8 +693,8 @@ DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION, dialog_event}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "retry(" + validation_errors + ");")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "retry(" + validation_errors + ");")); ASSERT_TRUE(WaitForObservedEvent()); }
diff --git a/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc index ec8bcfc..211c837 100644 --- a/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_can_make_payment_metrics_browsertest.cc
@@ -164,8 +164,8 @@ DialogEvent::CAN_MAKE_PAYMENT_RETURNED, DialogEvent::HAS_ENROLLED_INSTRUMENT_CALLED, DialogEvent::HAS_ENROLLED_INSTRUMENT_RETURNED}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "queryNoShowWithUrlMethods();")); + ASSERT_TRUE( + content::ExecJs(GetActiveWebContents(), "queryNoShowWithUrlMethods();")); ASSERT_TRUE(WaitForObservedEvent()); // Navigate away to trigger the log. @@ -296,8 +296,7 @@ {DialogEvent::ABORT_CALLED, DialogEvent::DIALOG_CLOSED}); const std::string click_buy_button_js = "(function() { document.getElementById('abort').click(); })();"; - ASSERT_TRUE( - content::ExecuteScript(GetActiveWebContents(), click_buy_button_js)); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), click_buy_button_js)); ASSERT_TRUE(WaitForObservedEvent()); // Make sure the correct events were logged. @@ -450,8 +449,7 @@ {DialogEvent::ABORT_CALLED, DialogEvent::DIALOG_CLOSED}); const std::string click_buy_button_js = "(function() { document.getElementById('abort').click(); })();"; - ASSERT_TRUE( - content::ExecuteScript(GetActiveWebContents(), click_buy_button_js)); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), click_buy_button_js)); ASSERT_TRUE(WaitForObservedEvent()); // Make sure the correct events were logged. @@ -566,8 +564,7 @@ {DialogEvent::ABORT_CALLED, DialogEvent::DIALOG_CLOSED}); const std::string click_buy_button_js = "(function() { document.getElementById('abort').click(); })();"; - ASSERT_TRUE( - content::ExecuteScript(GetActiveWebContents(), click_buy_button_js)); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), click_buy_button_js)); ASSERT_TRUE(WaitForObservedEvent()); // Make sure that no canMakePayment events were logged.
diff --git a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc index 397be98..d97c43f 100644 --- a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
@@ -90,8 +90,8 @@ // The merchant reloads the page. ResetEventWaiter(DialogEvent::DIALOG_CLOSED); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "(function() { location.reload(); })();")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "(function() { location.reload(); })();")); ASSERT_TRUE(WaitForObservedEvent()); // Make sure the metrics are logged correctly. @@ -152,10 +152,10 @@ // The merchant navigates away. ResetEventWaiter(DialogEvent::DIALOG_CLOSED); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "(function() { window.location.href = " - "'/payment_request_email_test.html'; " - "})();")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "(function() { window.location.href = " + "'/payment_request_email_test.html'; " + "})();")); ASSERT_TRUE(WaitForObservedEvent()); // Make sure the metrics are logged correctly. @@ -219,8 +219,7 @@ {DialogEvent::ABORT_CALLED, DialogEvent::DIALOG_CLOSED}); const std::string click_buy_button_js = "(function() { document.getElementById('abort').click(); })();"; - ASSERT_TRUE( - content::ExecuteScript(GetActiveWebContents(), click_buy_button_js)); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), click_buy_button_js)); ASSERT_TRUE(WaitForObservedEvent()); // Make sure the metrics are logged correctly.
diff --git a/chrome/browser/ui/views/payments/payment_request_data_url_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_data_url_browsertest.cc index e0ee23e..743cd64 100644 --- a/chrome/browser/ui/views/payments/payment_request_data_url_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_data_url_browsertest.cc
@@ -29,7 +29,7 @@ ASSERT_EQ(false, content::EvalJs(GetActiveWebContents(), "'PaymentRequest' in window;")); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( GetActiveWebContents(), "(function() { document.getElementById('buy').click(); })();")); ExpectBodyContains({"PaymentRequest is not defined"});
diff --git a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc index 2e2b5af2..b1214ef 100644 --- a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
@@ -93,7 +93,7 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_buy_button_js = "(function() { document.getElementById('buy').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_buy_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_buy_button_js)); ASSERT_TRUE(WaitForObservedEvent()); histogram_tester.ExpectBucketCount( @@ -157,7 +157,7 @@ content::WebContents* web_contents = GetActiveWebContents(); const std::string click_buy_button_js = "(function() { document.getElementById('showAgain').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_buy_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_buy_button_js)); // Complete the original Payment Request. ResetEventWaiterForSequence( @@ -226,7 +226,7 @@ // Try to show a second request. content::WebContents* web_contents = GetActiveWebContents(); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( web_contents, content::JsReplace("showSecondRequestWithMethods([{supportedMethods:$1}, " "{supportedMethods:$2}]);", @@ -756,7 +756,7 @@ DialogEvent::HAS_ENROLLED_INSTRUMENT_RETURNED}); // Initiate a Payment Request without showing it. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( GetActiveWebContents(), content::JsReplace("queryNoShowWithMethods([{supportedMethods:$1}" ", {supportedMethods:$2}]);", @@ -1072,10 +1072,10 @@ a_method, b_method)); // PushState on the history. - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "window.history.pushState(\"\", \"\", " - "\"/favicon/" - "pushstate_with_favicon_pushed.html\");")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "window.history.pushState(\"\", \"\", " + "\"/favicon/" + "pushstate_with_favicon_pushed.html\");")); // Simulate that the user cancels the PR. ClickOnCancel(); @@ -1133,10 +1133,10 @@ a_method, b_method)); // PushState on the history. - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "window.history.pushState(\"\", \"\", " - "\"/favicon/" - "pushstate_with_favicon_pushed.html\");")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "window.history.pushState(\"\", \"\", " + "\"/favicon/" + "pushstate_with_favicon_pushed.html\");")); // Complete the Payment Request. ResetEventWaiterForSequence(
diff --git a/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc index e23ba75a..a3d45333 100644 --- a/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_payment_app_browsertest.cc
@@ -484,7 +484,7 @@ const std::string click_buy_button_js = "(function() { " "document.getElementById('buyWithRequestedEmail').click(); })();"; - ASSERT_TRUE(content::ExecuteScript(web_contents, click_buy_button_js)); + ASSERT_TRUE(content::ExecJs(web_contents, click_buy_button_js)); ASSERT_TRUE(WaitForObservedEvent()); EXPECT_TRUE(IsPayButtonEnabled()); @@ -505,10 +505,11 @@ NavigateTo("/payment_request_bobpay_and_cards_test.html"); SetDownloaderAndIgnorePortInOriginComparisonForTesting(); ResetEventWaiterForDialogOpened(); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( GetActiveWebContents(), "testPaymentMethods([{supportedMethods: 'https://kylepay.test/webpay'}], " - "true /*= requestShippingContact */);")); + "true /*= requestShippingContact */);", + content::EXECUTE_SCRIPT_NO_RESOLVE_PROMISES)); ASSERT_TRUE(WaitForObservedEvent()); // Pay button should be enabled without any autofill profiles since the
diff --git a/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc index 8d3bb4b..f9a19210 100644 --- a/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc
@@ -135,7 +135,7 @@ DialogEvent::SPEC_DONE_UPDATING, DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "retry({});")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), "retry({});")); // Select "contact2" profile OpenContactInfoScreen();
diff --git a/chrome/browser/ui/views/payments/payment_request_retry_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_retry_browsertest.cc index eec0b1e..32a63ad 100644 --- a/chrome/browser/ui/views/payments/payment_request_retry_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_retry_browsertest.cc
@@ -51,14 +51,14 @@ DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION, DialogEvent::CONTACT_INFO_EDITOR_OPENED}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "retry({" - " payer: {" - " email: 'EMAIL ERROR'," - " name: 'NAME ERROR'," - " phone: 'PHONE ERROR'" - " }" - "});")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "retry({" + " payer: {" + " email: 'EMAIL ERROR'," + " name: 'NAME ERROR'," + " phone: 'PHONE ERROR'" + " }" + "});")); ASSERT_TRUE(WaitForObservedEvent()); EXPECT_EQ(1U, request->state()->available_apps().size()); }
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_sheet_controller_browsertest.cc index 066868e..4ce0af4 100644 --- a/chrome/browser/ui/views/payments/payment_request_sheet_controller_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller_browsertest.cc
@@ -61,14 +61,14 @@ DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION, DialogEvent::CONTACT_INFO_EDITOR_OPENED}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), - "retry({" - " payer: {" - " email: 'EMAIL ERROR'," - " name: 'NAME ERROR'," - " phone: 'PHONE ERROR'" - " }" - "});")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), + "retry({" + " payer: {" + " email: 'EMAIL ERROR'," + " name: 'NAME ERROR'," + " phone: 'PHONE ERROR'" + " }" + "});")); ASSERT_TRUE(WaitForObservedEvent()); EXPECT_FALSE(dialog_view()->throbber_overlay_for_testing()->GetVisible());
diff --git a/chrome/browser/ui/views/payments/payment_request_show_promise_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_show_promise_browsertest.cc index ec44f1ed4..5787316 100644 --- a/chrome/browser/ui/views/payments/payment_request_show_promise_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_show_promise_browsertest.cc
@@ -42,8 +42,8 @@ DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::DIALOG_OPENED}); ASSERT_TRUE( - content::ExecuteScript(GetActiveWebContents(), - content::JsReplace("buy($1)", payment_method_))); + content::ExecJs(GetActiveWebContents(), + content::JsReplace("buy($1)", payment_method_))); ASSERT_TRUE(WaitForObservedEvent()); EXPECT_TRUE(web_modal::WebContentsModalDialogManager::FromWebContents( GetActiveWebContents()) @@ -226,15 +226,15 @@ base::HistogramTester histogram_tester; NavigateTo("/show_promise/digital_goods.html"); InstallEchoPaymentHandler(); - ASSERT_TRUE(content::ExecuteScript( - GetActiveWebContents(), - content::JsReplace("create($1)", payment_method_))); + ASSERT_TRUE( + content::ExecJs(GetActiveWebContents(), + content::JsReplace("create($1)", payment_method_))); ResetEventWaiterForSequence( {DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::SPEC_DONE_UPDATING, DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::DIALOG_OPENED, DialogEvent::PROCESSING_SPINNER_SHOWN, DialogEvent::DIALOG_CLOSED}); - ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), "buy();")); + ASSERT_TRUE(content::ExecJs(GetActiveWebContents(), "buy();")); ASSERT_TRUE(WaitForObservedEvent()); ExpectBodyContains({R"({"currency":"USD","value":"1.00"})"});
diff --git a/chrome/browser/ui/views/payments/payment_request_update_with_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_update_with_browsertest.cc index 1a47f08..12f1971 100644 --- a/chrome/browser/ui/views/payments/payment_request_update_with_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_update_with_browsertest.cc
@@ -28,7 +28,7 @@ ResetEventWaiterForDialogOpened(); content::WebContents* web_contents = GetActiveWebContents(); - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( web_contents, function_name + "('" + payment_method_name + "');")); ASSERT_TRUE(WaitForObservedEvent());
diff --git a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view_browsertest.cc b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view_browsertest.cc index 298490d..bcff1135 100644 --- a/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/dice_web_signin_interception_bubble_view_browsertest.cc
@@ -150,7 +150,7 @@ // `kSigninInterceptBubbleV2` feature is tested in // `DiceWebSigninInterceptionBubbleV2PixelTest` std::vector<base::test::FeatureRef> disabled_features = { - kSigninInterceptBubbleV2}; + kSigninInterceptBubbleV2, kSyncPromoAfterSigninIntercept}; if (GetParam().use_dark_theme) { enabled_features.push_back(features::kWebUIDarkMode); } @@ -169,6 +169,10 @@ policy::ScopedManagementServiceOverrideForTesting browser_management( policy::ManagementServiceFactory::GetForProfile(browser()->profile()), GetParam().management_authority); + policy::ScopedManagementServiceOverrideForTesting + platform_browser_management( + policy::ManagementServiceFactory::GetForPlatform(), + policy::EnterpriseManagementAuthority::NONE); SkColor primary_highlight_color = GetParam().primary_profile_color.toSkColor();
diff --git a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc index 8cf671f..ecf4f549 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "chrome/app/chrome_command_ids.h" #include "chrome/browser/ui/views/profiles/profile_picker_view.h" #include "base/check.h" @@ -19,6 +20,8 @@ #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/interaction/interactive_browser_test.h" #include "content/public/browser/navigation_controller.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" @@ -33,8 +36,20 @@ #include "ui/views/widget/widget.h" #include "ui/views/widget/widget_observer.h" +using testing::Eq; +using testing::IsFalse; +using testing::IsTrue; + namespace { +DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kProfilePickerViewId); +DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kPickerWebContentsId); + +const WebContentsInteractionTestUtil::DeepQuery kSignInButton = { + "profile-picker-app", "profile-type-choice", "#signInButton"}; +const WebContentsInteractionTestUtil::DeepQuery kAddProfileButton = { + "profile-picker-app", "profile-picker-main-view", "#addProfile"}; + // Waits until the widget bounds change. class WidgetBoundsChangeWaiter : public views::WidgetObserver { public: @@ -60,6 +75,25 @@ } // namespace +struct NavState { + int entry_count; + int last_committed_entry_index; + bool has_pending_entry = false; + + bool operator==(const NavState& other) const { + return entry_count == other.entry_count && + last_committed_entry_index == other.last_committed_entry_index && + has_pending_entry == other.has_pending_entry; + } + + friend std::ostream& operator<<(std::ostream& stream, const NavState& state) { + return stream << "{entry_count=" << state.entry_count + << ", last_committed_entry_index=" + << state.last_committed_entry_index + << ", has_pending_entry=" << state.has_pending_entry << "}"; + } +}; + class ProfilePickerInteractiveUiTest : public InteractiveBrowserTest, public WithProfilePickerInteractiveUiTestHelpers { @@ -68,13 +102,36 @@ ~ProfilePickerInteractiveUiTest() override = default; void ShowAndFocusPicker(ProfilePicker::EntryPoint entry_point, - const GURL& expected_url) { + const GURL& expected_url = GURL()) { ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint(entry_point)); - WaitForLoadStop(expected_url); + WaitForPickerWidgetCreated(); + view()->SetProperty(views::kElementIdentifierKey, kProfilePickerViewId); + if (!expected_url.is_empty()) { + WaitForLoadStop(expected_url); + } + EXPECT_TRUE( ui_test_utils::ShowAndFocusNativeWindow(widget()->GetNativeWindow())); } + auto GetNavState() { + return [this]() { + return NavState{ + .entry_count = web_contents()->GetController().GetEntryCount(), + .last_committed_entry_index = + web_contents()->GetController().GetLastCommittedEntryIndex(), + .has_pending_entry = + web_contents()->GetController().GetPendingEntry() != nullptr, + }; + }; + } + + auto HasPendingNav() { + return [this]() { + return web_contents()->GetController().GetPendingEntry() != nullptr; + }; + } + void SimulateUserActivation() { content::UpdateUserActivationStateInterceptor user_activation_interceptor( web_contents()->GetPrimaryMainFrame()); @@ -82,6 +139,33 @@ blink::mojom::UserActivationUpdateType::kNotifyActivation, blink::mojom::UserActivationNotificationType::kTest); } + + StateChange Exists(const DeepQuery& where) { + DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kElementExistsEvent); + StateChange state_change; + state_change.type = StateChange::Type::kExists; + state_change.where = where; + state_change.event = kElementExistsEvent; + return state_change; + } + + // Used to wait for screen changes inside of the `profile-picker-app`, in + // combination with `WaitForStateChange()`. + // + // In the profile picker app we modify the displayed URL but don't do a full + // navigation, so `WaitForWebContentsNavigation()` does not detect these + // changes. + StateChange UrlEntryMatches(const GURL& url) { + DEFINE_LOCAL_CUSTOM_ELEMENT_EVENT_TYPE(kUrlEntryMatchesEvent); + StateChange state_change; + state_change.test_function = base::StringPrintf( + "(_) => navigation && navigation.currentEntry && " + "navigation.currentEntry.url === '%s'", + url.spec().c_str()); + state_change.type = StateChange::Type::kConditionTrue; + state_change.event = kUrlEntryMatchesEvent; + return state_change; + } }; // Checks that the main picker view can be closed with keyboard shortcut. @@ -130,22 +214,7 @@ #if !BUILDFLAG(IS_CHROMEOS_LACROS) IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, CloseDiceSigninWithKeyboard) { - DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kProfilePickerViewId); - DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kPickerWebContentsId); - - const DeepQuery kSignInButton = {"profile-picker-app", "profile-type-choice", - "#signInButton"}; - const ui::Accelerator kCloseWindowAccelerator -#if BUILDFLAG(IS_MAC) - {ui::VKEY_W, ui::EF_COMMAND_DOWN}; -#else - {ui::VKEY_W, ui::EF_CONTROL_DOWN}; -#endif - - ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint( - ProfilePicker::EntryPoint::kProfileMenuAddNewProfile)); - WaitForPickerWidgetCreated(); - view()->SetProperty(views::kElementIdentifierKey, kProfilePickerViewId); + ShowAndFocusPicker(ProfilePicker::EntryPoint::kProfileMenuAddNewProfile); RunTestSequenceInContext( views::ElementTrackerViews::GetContextForView(view()), @@ -169,7 +238,7 @@ GetSigninChromeSyncDiceUrl()), // Send "Close window" keyboard shortcut and wait for view to close. - SendAccelerator(kProfilePickerViewId, kCloseWindowAccelerator), + SendAccelerator(kProfilePickerViewId, GetAccelerator(IDC_CLOSE_WINDOW)), WaitForHide(kProfilePickerViewId, /*transition_only_on_event=*/true), // Note: The widget/view is destroyed asynchronously, we need to flush the @@ -179,86 +248,99 @@ // Checks that both the signin web view and the main picker view are able to // process a back keyboard event. -// TODO(https://crbug.com/1173544): Flaky on linux, Win7, Mac -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) -#define MAYBE_NavigateBackFromDiceSigninWithKeyboard \ - DISABLED_NavigateBackFromDiceSigninWithKeyboard -#else -#define MAYBE_NavigateBackFromDiceSigninWithKeyboard \ - NavigateBackFromDiceSigninWithKeyboard -#endif IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, - MAYBE_NavigateBackFromDiceSigninWithKeyboard) { + NavigateBackFromDiceSigninWithKeyboard) { // Simulate walking through the flow starting at the picker so that navigating // back to the picker makes sense. Check that the navigation list is populated // correctly. ShowAndFocusPicker(ProfilePicker::EntryPoint::kProfileMenuManageProfiles, GURL("chrome://profile-picker")); - EXPECT_EQ(1, web_contents()->GetController().GetEntryCount()); - EXPECT_EQ(0, web_contents()->GetController().GetLastCommittedEntryIndex()); - web_contents()->GetController().LoadURL( - GURL("chrome://profile-picker/new-profile"), content::Referrer(), - ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string()); - WaitForLoadStop(GURL("chrome://profile-picker/new-profile")); - EXPECT_EQ(2, web_contents()->GetController().GetEntryCount()); - EXPECT_EQ(1, web_contents()->GetController().GetLastCommittedEntryIndex()); - // Simulate a click on the signin button. - base::MockCallback<base::OnceCallback<void(bool)>> switch_finished_callback; - EXPECT_CALL(switch_finished_callback, Run(true)); - ProfilePicker::SwitchToDiceSignIn(SK_ColorRED, - switch_finished_callback.Get()); + RunTestSequenceInContext( + views::ElementTrackerViews::GetContextForView(view()), - // Switch to the signin webview. - WaitForLoadStop(signin::GetChromeSyncURLForDice({.for_promo_flow = true})); + WaitForShow(kProfilePickerViewId), + InstrumentNonTabWebView(kPickerWebContentsId, web_view()), + WaitForWebContentsReady(kPickerWebContentsId, + GURL("chrome://profile-picker")), + CheckResult(GetNavState(), Eq(NavState{.entry_count = 1, + .last_committed_entry_index = 0})), - // Navigate back with the keyboard. - SendBackKeyboardCommand(); - WaitForLoadStop(GURL("chrome://profile-picker/new-profile")); - EXPECT_EQ(1, web_contents()->GetController().GetLastCommittedEntryIndex()); + // Advance to the profile type choice screen. + EnsurePresent(kPickerWebContentsId, kAddProfileButton), + MoveMouseTo(kPickerWebContentsId, kAddProfileButton), ClickMouse(), + WaitForStateChange( + kPickerWebContentsId, + UrlEntryMatches(GURL("chrome://profile-picker/new-profile"))), + CheckResult(GetNavState(), Eq(NavState{.entry_count = 2, + .last_committed_entry_index = 1})), - // Navigate again back with the keyboard. - SendBackKeyboardCommand(); - WaitForLoadStop(GURL("chrome://profile-picker")); - EXPECT_EQ(0, web_contents()->GetController().GetLastCommittedEntryIndex()); + // Advance to the sign-in page. + WaitForStateChange(kPickerWebContentsId, Exists(kSignInButton)), + MoveMouseTo(kPickerWebContentsId, kSignInButton), ClickMouse(), + WaitForWebContentsNavigation(kPickerWebContentsId, + GetSigninChromeSyncDiceUrl()), - // Navigating back once again does nothing. - SendBackKeyboardCommand(); - EXPECT_EQ(web_contents()->GetController().GetPendingEntry(), nullptr); + // Navigate back with the keyboard, switch back to the picker. + SendAccelerator(kProfilePickerViewId, GetAccelerator(IDC_BACK)), + WaitForStateChange( + kPickerWebContentsId, + UrlEntryMatches(GURL("chrome://profile-picker/new-profile"))), + CheckResult(GetNavState(), Eq(NavState{.entry_count = 2, + .last_committed_entry_index = 1})), + + // Navigate again back with the keyboard. + SendAccelerator(kProfilePickerViewId, GetAccelerator(IDC_BACK)), + CheckResult(HasPendingNav(), IsTrue()), + WaitForStateChange(kPickerWebContentsId, + UrlEntryMatches(GURL("chrome://profile-picker"))), + CheckResult(GetNavState(), Eq(NavState{.entry_count = 2, + .last_committed_entry_index = 0})), + + // Navigating back once again does nothing. + SendAccelerator(kProfilePickerViewId, GetAccelerator(IDC_BACK)), + CheckResult(HasPendingNav(), IsFalse())); } #endif // !BUILDFLAG(IS_CHROMEOS_LACROS) -#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) -#define MAYBE_NavigateBackFromProfileTypeChoiceWithKeyboard \ - DISABLED_NavigateBackFromProfileTypeChoiceWithKeyboard -#else -#define MAYBE_NavigateBackFromProfileTypeChoiceWithKeyboard \ - NavigateBackFromProfileTypeChoiceWithKeyboard -#endif IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest, - MAYBE_NavigateBackFromProfileTypeChoiceWithKeyboard) { + NavigateBackFromProfileTypeChoiceWithKeyboard) { // Simulate walking through the flow starting at the picker so that navigating // back to the picker makes sense. Check that the navigation list is populated // correctly. ShowAndFocusPicker(ProfilePicker::EntryPoint::kProfileMenuManageProfiles, GURL("chrome://profile-picker")); - EXPECT_EQ(1, web_contents()->GetController().GetEntryCount()); - EXPECT_EQ(0, web_contents()->GetController().GetLastCommittedEntryIndex()); - web_contents()->GetController().LoadURL( - GURL("chrome://profile-picker/new-profile"), content::Referrer(), - ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string()); - WaitForLoadStop(GURL("chrome://profile-picker/new-profile")); - EXPECT_EQ(2, web_contents()->GetController().GetEntryCount()); - EXPECT_EQ(1, web_contents()->GetController().GetLastCommittedEntryIndex()); - // Navigate back with the keyboard. - SendBackKeyboardCommand(); - WaitForLoadStop(GURL("chrome://profile-picker")); - EXPECT_EQ(0, web_contents()->GetController().GetLastCommittedEntryIndex()); + RunTestSequenceInContext( + views::ElementTrackerViews::GetContextForView(view()), - // Navigating back once again does nothing. - SendBackKeyboardCommand(); - EXPECT_EQ(web_contents()->GetController().GetPendingEntry(), nullptr); + WaitForShow(kProfilePickerViewId), + InstrumentNonTabWebView(kPickerWebContentsId, web_view()), + WaitForWebContentsReady(kPickerWebContentsId, + GURL("chrome://profile-picker")), + CheckResult(GetNavState(), Eq(NavState{.entry_count = 1, + .last_committed_entry_index = 0})), + + // Advance to the profile type choice screen. + EnsurePresent(kPickerWebContentsId, kAddProfileButton), + MoveMouseTo(kPickerWebContentsId, kAddProfileButton), ClickMouse(), + WaitForStateChange( + kPickerWebContentsId, + UrlEntryMatches(GURL("chrome://profile-picker/new-profile"))), + CheckResult(GetNavState(), Eq(NavState{.entry_count = 2, + .last_committed_entry_index = 1})), + + // Navigate back with the keyboard. + SendAccelerator(kProfilePickerViewId, GetAccelerator(IDC_BACK)), + CheckResult(HasPendingNav(), IsTrue()), + WaitForStateChange(kPickerWebContentsId, + UrlEntryMatches(GURL("chrome://profile-picker"))), + CheckResult(GetNavState(), Eq(NavState{.entry_count = 2, + .last_committed_entry_index = 0})), + + // Navigating back once again does nothing. + SendAccelerator(kProfilePickerViewId, GetAccelerator(IDC_BACK)), + CheckResult(HasPendingNav(), IsFalse())); } IN_PROC_BROWSER_TEST_F(ProfilePickerInteractiveUiTest,
diff --git a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest_base.cc b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest_base.cc index 8f83fd6..d2f3e88 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest_base.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest_base.cc
@@ -4,70 +4,86 @@ #include "chrome/browser/ui/views/profiles/profile_picker_interactive_uitest_base.h" +#include "base/notreached.h" #include "base/test/bind.h" +#include "chrome/app/chrome_command_ids.h" #include "chrome/browser/ui/views/profiles/profile_picker_test_base.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/interaction/tracked_element_webcontents.h" #include "content/public/browser/web_contents.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/accelerators/accelerator.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/views/widget/widget.h" +ui::Accelerator WithProfilePickerInteractiveUiTestHelpers::GetAccelerator( + int command_id) { + // TODO(crbug.com/1444053): Rely on `AcceleratorProvider` instead of + // hardcoding the accelerators here. + + switch (command_id) { + case IDC_CLOSE_WINDOW: + // Sending accelerators for CLOSE_TAB instead, as although CLOSE_WINDOW is + // registered on other platforms, it is not on mac +#if BUILDFLAG(IS_MAC) + return {ui::VKEY_W, ui::EF_COMMAND_DOWN}; // Cmd-W +#else + return {ui::VKEY_W, ui::EF_CONTROL_DOWN}; // Ctrl-W +#endif + + case IDC_BACK: +#if BUILDFLAG(IS_MAC) + return {ui::VKEY_OEM_4, ui::EF_COMMAND_DOWN}; // Cmd-[ +#else + return {ui::VKEY_LEFT, ui::EF_ALT_DOWN}; // Alt-left +#endif + + case IDC_FULLSCREEN: +#if BUILDFLAG(IS_MAC) + return {ui::VKEY_F, + ui::EF_COMMAND_DOWN | ui::EF_CONTROL_DOWN}; // Cmd-Ctrl-F. +#else + return {ui::VKEY_F11, ui::EF_NONE}; // F11. +#endif + +#if BUILDFLAG(IS_MAC) + case IDC_EXIT: + return {ui::VKEY_Q, ui::EF_COMMAND_DOWN}; // Cmd-Q. +#endif + + default: + NOTREACHED_NORETURN() << "Unexpected command_id: " << command_id; + } +} + void WithProfilePickerInteractiveUiTestHelpers:: SendCloseWindowKeyboardCommand() { -#if BUILDFLAG(IS_MAC) - // Use Cmd-W on Mac. - bool control = false; - bool command = true; -#else - // Use Ctrl-W on other platforms. Note: while Ctrl-Shift-W would also work, - // Cmd-Shift-W is not supported on Mac for closing non-browser windows. - bool control = true; - bool command = false; -#endif - SendKeyPress(ui::VKEY_W, control, /*shift=*/false, /*alt=*/false, command); + SendKeyPress(GetAccelerator(IDC_CLOSE_WINDOW)); } void WithProfilePickerInteractiveUiTestHelpers::SendBackKeyboardCommand() { -#if BUILDFLAG(IS_MAC) - // Use Cmd-[ on Mac. - bool alt = false; - bool command = true; - ui::KeyboardCode key = ui::VKEY_OEM_4; -#else - // Use Ctrl-left on other platforms. - bool alt = true; - bool command = false; - ui::KeyboardCode key = ui::VKEY_LEFT; -#endif - SendKeyPress(key, /*control=*/false, /*shift=*/false, alt, command); + SendKeyPress(GetAccelerator(IDC_BACK)); } void WithProfilePickerInteractiveUiTestHelpers:: SendToggleFullscreenKeyboardCommand() { -#if BUILDFLAG(IS_MAC) - // Use Cmd-Ctrl-F on Mac. - bool control = true; - bool command = true; - ui::KeyboardCode key_code = ui::VKEY_F; -#else - // Use F11 on other platforms. - bool control = false; - bool command = false; - ui::KeyboardCode key_code = ui::VKEY_F11; -#endif - SendKeyPress(key_code, control, /*shift=*/false, /*alt=*/false, command); + SendKeyPress(GetAccelerator(IDC_FULLSCREEN)); } #if BUILDFLAG(IS_MAC) void WithProfilePickerInteractiveUiTestHelpers::SendQuitAppKeyboardCommand() { - // Send Cmd-Q. - SendKeyPress(ui::VKEY_Q, /*control=*/false, /*shift=*/false, /*alt=*/false, - /*command=*/true); + SendKeyPress(GetAccelerator(IDC_EXIT)); } #endif void WithProfilePickerInteractiveUiTestHelpers::SendKeyPress( + ui::Accelerator accelerator) { + SendKeyPress(accelerator.key_code(), accelerator.IsCtrlDown(), + accelerator.IsShiftDown(), accelerator.IsAltDown(), + accelerator.IsCmdDown()); +} + +void WithProfilePickerInteractiveUiTestHelpers::SendKeyPress( ui::KeyboardCode key, bool control, bool shift,
diff --git a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest_base.h b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest_base.h index c692bd8..2e824da 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest_base.h +++ b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest_base.h
@@ -6,16 +6,15 @@ #define CHROME_BROWSER_UI_VIEWS_PROFILES_PROFILE_PICKER_INTERACTIVE_UITEST_BASE_H_ #include "chrome/browser/ui/views/profiles/profile_picker_test_base.h" - -namespace ui { -enum KeyboardCode; -} +#include "ui/base/accelerators/accelerator.h" // Mixin adding helpers to write interactive ui tests focused on // `ProfilePickerView`. class WithProfilePickerInteractiveUiTestHelpers : public WithProfilePickerTestHelpers { public: + ui::Accelerator GetAccelerator(int command_id); + void SendCloseWindowKeyboardCommand(); void SendBackKeyboardCommand(); @@ -26,6 +25,8 @@ void SendQuitAppKeyboardCommand(); #endif + // Sends the provided keyboard command to the profile picker window. + void SendKeyPress(ui::Accelerator accelerator); void SendKeyPress(ui::KeyboardCode key, bool control, bool shift,
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.cc b/chrome/browser/ui/views/profiles/profile_picker_view.cc index dae44ca..6eac4a4 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view.cc
@@ -5,6 +5,7 @@ #include "chrome/browser/ui/views/profiles/profile_picker_view.h" #include "base/containers/contains.h" +#include "base/debug/dump_without_crashing.h" #include "base/files/file_path.h" #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" @@ -44,6 +45,7 @@ #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/url_constants.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/metadata/metadata_impl_macros.h" #include "ui/views/controls/webview/webview.h" @@ -334,9 +336,12 @@ // ProfilePickerView::NavigationFinishedObserver ------------------------------ ProfilePickerView::NavigationFinishedObserver::NavigationFinishedObserver( + const GURL& requested_url, base::OnceClosure closure, content::WebContents* contents) - : content::WebContentsObserver(contents), closure_(std::move(closure)) {} + : content::WebContentsObserver(contents), + requested_url_(requested_url), + closure_(std::move(closure)) {} ProfilePickerView::NavigationFinishedObserver::~NavigationFinishedObserver() = default; @@ -346,6 +351,28 @@ if (!closure_ || !navigation_handle->HasCommitted()) { return; } + + if (navigation_handle->GetRedirectChain()[0] != requested_url_) { + // Don't notify if the URL for the finishing navigation does not match. + // The navigation may have been replaced by a new one. We are mindful to + // allow redirections, which are necessary for example for Gaia sign-in + // pages (see crbug.com/1430681). + return; + } + + if (navigation_handle->IsErrorPage() && + requested_url_.SchemeIs(content::kChromeUIScheme)) { + // We observed some cases where the navigation to the intended page fails + // (see crbug.com/1442159). + // Loading the wrong URL may lead to crashes if we are expecting a certain + // WebUI page to be loaded in the web contents. For these cases we will not + // notify of the finished navigation to avoid crashing, but this negatively + // affects the user experience anyway. + // TODO(crbug.com/1444046): Improve the user experience for this error. + base::debug::DumpWithoutCrashing(); + return; + } + std::move(closure_).Run(); } @@ -406,6 +433,7 @@ // observer gets destroyed here or later in ShowScreenFinished(). This is okay // as all the previous values get replaced by the new values. show_screen_finished_observer_ = std::make_unique<NavigationFinishedObserver>( + url, base::BindOnce(&ProfilePickerView::ShowScreenFinished, base::Unretained(this), contents, std::move(navigation_finished_closure)),
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.h b/chrome/browser/ui/views/profiles/profile_picker_view.h index 448578b..04964aa4b 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view.h +++ b/chrome/browser/ui/views/profiles/profile_picker_view.h
@@ -138,7 +138,8 @@ class NavigationFinishedObserver : public content::WebContentsObserver { public: - NavigationFinishedObserver(base::OnceClosure closure, + NavigationFinishedObserver(const GURL& requested_url, + base::OnceClosure closure, content::WebContents* contents); NavigationFinishedObserver(const NavigationFinishedObserver&) = delete; NavigationFinishedObserver& operator=(const NavigationFinishedObserver&) = @@ -150,6 +151,7 @@ content::NavigationHandle* navigation_handle) override; private: + const GURL requested_url_; base::OnceClosure closure_; };
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc index 3941737..558fbab4 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/run_loop.h" #include "chrome/browser/ui/views/profiles/profile_picker_view.h" #include <set> @@ -355,6 +356,46 @@ } // namespace +class ProfilePickerViewBrowserTest : public ProfilePickerTestBase {}; + +// Regression test for crbug.com/1442159. +IN_PROC_BROWSER_TEST_F(ProfilePickerViewBrowserTest, + ShowScreen_DoesNotFinishForErrorOnInternalNavigation) { + GURL bad_target_url{"chrome://unregistered-host"}; + base::test::TestFuture<void> navigation_finished_future; + + ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint( + ProfilePicker::EntryPoint::kProfileMenuManageProfiles)); + WaitForLoadStop(GURL{"chrome://profile-picker"}); + view()->ShowScreenInPickerContents(bad_target_url, + navigation_finished_future.GetCallback()); + + WaitForLoadStop(bad_target_url, web_contents()); + EXPECT_FALSE(navigation_finished_future.IsReady()); +} + +// Regression test for crbug.com/1442159. +IN_PROC_BROWSER_TEST_F(ProfilePickerViewBrowserTest, + ShowScreen_FinishesForErrorOnStandardNavigation) { + // URL intended to simulate an https navigation that fails because the host + // can't be found. With an internet connection it would redirect to the + // DNS_PROBE_FINISHED_NXDOMAIN error page. Simulate that in the picker flow + // using the `--gaia-url` command line parameter. + // During tests all external navigations fail anyway, but that's good enough + // for what we're trying to verify. + GURL bad_target_url{"https://url.madeup"}; + base::test::TestFuture<void> navigation_finished_future; + + ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint( + ProfilePicker::EntryPoint::kProfileMenuManageProfiles)); + WaitForLoadStop(GURL{"chrome://profile-picker"}); + view()->ShowScreenInPickerContents(bad_target_url, + navigation_finished_future.GetCallback()); + + WaitForLoadStop(bad_target_url, web_contents()); + EXPECT_TRUE(navigation_finished_future.IsReady()); +} + class ProfilePickerCreationFlowBrowserTest : public ProfilePickerTestBase { public: explicit ProfilePickerCreationFlowBrowserTest(
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.cc b/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.cc index 0f1dcac..268b84b 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view_test_utils.cc
@@ -178,6 +178,12 @@ namespace profiles::testing { void WaitForPickerWidgetCreated() { + if (!ProfilePicker::IsOpen()) { + base::RunLoop run_loop; + ProfilePicker::AddOnProfilePickerOpenedCallbackForTesting( + run_loop.QuitClosure()); + run_loop.Run(); + } ViewAddedWaiter(ProfilePicker::GetViewForTesting()).Wait(); }
diff --git a/chrome/browser/ui/views/profiles/profile_picker_web_contents_host.h b/chrome/browser/ui/views/profiles/profile_picker_web_contents_host.h index 3e67dce..efbe7332 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_web_contents_host.h +++ b/chrome/browser/ui/views/profiles/profile_picker_web_contents_host.h
@@ -38,7 +38,8 @@ // `contents` with its currently loaded url. If both // `navigation_finished_closure` and `url` is non-empty, the closure is called // when the navigation commits (if it never commits such as when the - // navigation is replaced by another navigation, the closure is never called). + // navigation is replaced by another navigation or if an internal page fails + // to load, the closure is never called). virtual void ShowScreen( content::WebContents* contents, const GURL& url,
diff --git a/chrome/browser/ui/views/side_panel/search_companion/companion_side_panel_controller.cc b/chrome/browser/ui/views/side_panel/search_companion/companion_side_panel_controller.cc index 3b99ae7..5ad369a 100644 --- a/chrome/browser/ui/views/side_panel/search_companion/companion_side_panel_controller.cc +++ b/chrome/browser/ui/views/side_panel/search_companion/companion_side_panel_controller.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/ui/views/side_panel/search_companion/companion_side_panel_controller.h" +#include "chrome/browser/companion/core/features.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/views/frame/browser_view.h" @@ -125,19 +126,21 @@ params.initiator_origin = url::Origin::Create(url); } - // Open the new tab in the foreground. - params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; + bool open_in_current_tab = companion::features::kOpenLinksInCurrentTab.Get(); + params.disposition = open_in_current_tab + ? WindowOpenDisposition::CURRENT_TAB + : WindowOpenDisposition::NEW_FOREGROUND_TAB; Browser* browser = chrome::FindBrowserWithWebContents(web_contents_); if (!browser) { return; } - // Open the url in a new tab. + // Open the url in the desired tab. content::WebContents* new_tab_web_contents = browser->OpenURL(params); - // Open companion side panel for the new tab. - if (new_tab_web_contents) { + // If a new tab was opened, open companion side panel in it. + if (new_tab_web_contents && !open_in_current_tab) { BrowserView::GetBrowserViewForBrowser(browser) ->side_panel_coordinator() ->Show(SidePanelEntry::Id::kSearchCompanion);
diff --git a/chrome/browser/ui/views/task_manager_view_browsertest.cc b/chrome/browser/ui/views/task_manager_view_browsertest.cc index 841b0391..457b79d 100644 --- a/chrome/browser/ui/views/task_manager_view_browsertest.cc +++ b/chrome/browser/ui/views/task_manager_view_browsertest.cc
@@ -296,7 +296,7 @@ // Add 3 rows above the selection. The selected tab should not change. for (int i = 0; i < 3; ++i) { - ASSERT_TRUE(content::ExecuteScript(tabs[0], "window.open('title3.html');")); + ASSERT_TRUE(content::ExecJs(tabs[0], "window.open('title3.html');")); EXPECT_EQ(GetTable()->GetFirstSelectedRow(), FindRowForTab(tabs[1])); } ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows((rows += 3), pattern)); @@ -305,7 +305,7 @@ // Add 2 rows below the selection. The selected tab should not change. for (int i = 0; i < 2; ++i) { - ASSERT_TRUE(content::ExecuteScript(tabs[2], "window.open('title3.html');")); + ASSERT_TRUE(content::ExecJs(tabs[2], "window.open('title3.html');")); EXPECT_EQ(GetTable()->GetFirstSelectedRow(), FindRowForTab(tabs[1])); } ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows((rows += 2), pattern)); @@ -314,7 +314,7 @@ // Add a new row in the same process as the selection. The selected tab should // not change. - ASSERT_TRUE(content::ExecuteScript(tabs[1], "window.open('title3.html');")); + ASSERT_TRUE(content::ExecJs(tabs[1], "window.open('title3.html');")); EXPECT_EQ(GetTable()->GetFirstSelectedRow(), FindRowForTab(tabs[1])); ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows((rows += 1), pattern)); EXPECT_EQ(GetTable()->GetFirstSelectedRow(), FindRowForTab(tabs[1]));
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_button.cc b/chrome/browser/ui/views/toolbar/chrome_labs_button.cc index 0ef6258..f001bdf57 100644 --- a/chrome/browser/ui/views/toolbar/chrome_labs_button.cc +++ b/chrome/browser/ui/views/toolbar/chrome_labs_button.cc
@@ -76,7 +76,7 @@ // On Chrome OS if we are still waiting for IsOwnerAsync to return abort // button clicks. #if BUILDFLAG(IS_CHROMEOS_ASH) - if (is_waiting_to_show) { + if (is_waiting_to_show_) { return; } #endif @@ -101,7 +101,7 @@ ash::OwnerSettingsServiceAsh* service = ash::OwnerSettingsServiceAshFactory::GetForBrowserContext( original_profile); - is_waiting_to_show = true; + is_waiting_to_show_ = true; service->IsOwnerAsync(base::BindOnce( [](ChromeLabsButton* button, base::WeakPtr<BrowserView> browser_view, ChromeLabsCoordinator* coordinator, bool is_owner) { @@ -112,7 +112,7 @@ ? coordinator->Show( ChromeLabsCoordinator::ShowUserType::kChromeOsOwnerUserType) : coordinator->Show(); - button->is_waiting_to_show = false; + button->is_waiting_to_show_ = false; }, this, browser_view_->GetAsWeakPtr(), chrome_labs_coordinator_.get())); return; @@ -150,22 +150,5 @@ new_experiments_indicator_->Hide(); } -// static -bool ChromeLabsButton::ShouldShowButton(const ChromeLabsModel* model, - Profile* profile) { -#if BUILDFLAG(IS_CHROMEOS_ASH) - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - ash::switches::kSafeMode) || - !ash::ProfileHelper::IsPrimaryProfile(profile)) { - return false; - } -#endif - - return base::ranges::any_of(model->GetLabInfo(), - [&profile](const LabInfo& lab) { - return IsChromeLabsFeatureValid(lab, profile); - }); -} - BEGIN_METADATA(ChromeLabsButton, ToolbarButton) END_METADATA
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_button.h b/chrome/browser/ui/views/toolbar/chrome_labs_button.h index cf69be7..4a43def 100644 --- a/chrome/browser/ui/views/toolbar/chrome_labs_button.h +++ b/chrome/browser/ui/views/toolbar/chrome_labs_button.h
@@ -14,7 +14,6 @@ #include "ui/views/controls/dot_indicator.h" class BrowserView; -class Profile; class ChromeLabsButton : public ToolbarButton { public: @@ -30,8 +29,6 @@ void HideDotIndicator(); - static bool ShouldShowButton(const ChromeLabsModel* model, Profile* profile); - #if BUILDFLAG(IS_CHROMEOS_ASH) void SetShouldCircumventDeviceCheckForTesting(bool should_circumvent) { @@ -55,7 +52,7 @@ raw_ptr<BrowserView, DanglingUntriaged> browser_view_; #if BUILDFLAG(IS_CHROMEOS_ASH) - bool is_waiting_to_show = false; + bool is_waiting_to_show_ = false; // Used to circumvent the IsRunningOnChromeOS() check in ash-chrome tests. bool should_circumvent_device_check_for_testing_ = false; #endif
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_utils.cc b/chrome/browser/ui/views/toolbar/chrome_labs_utils.cc index bd69593c..6194ddb 100644 --- a/chrome/browser/ui/views/toolbar/chrome_labs_utils.cc +++ b/chrome/browser/ui/views/toolbar/chrome_labs_utils.cc
@@ -3,7 +3,9 @@ // found in the LICENSE file. #include "chrome/browser/ui/views/toolbar/chrome_labs_utils.h" + #include "base/containers/contains.h" +#include "base/ranges/algorithm.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/about_flags.h" #include "chrome/browser/browser_process.h" @@ -15,6 +17,11 @@ #include "components/flags_ui/pref_service_flags_storage.h" #include "components/prefs/scoped_user_pref_update.h" +#if BUILDFLAG(IS_CHROMEOS_ASH) +#include "ash/constants/ash_switches.h" +#include "chrome/browser/ash/profiles/profile_helper.h" +#endif + bool IsFeatureSupportedOnChannel(const LabInfo& lab) { return chrome::GetChannel() <= lab.allowed_channel; } @@ -86,3 +93,18 @@ for (const std::string& key : entries_to_remove) new_badge_prefs.Remove(key); } + +bool ShouldShowChromeLabsUI(const ChromeLabsModel* model, Profile* profile) { +#if BUILDFLAG(IS_CHROMEOS_ASH) + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + ash::switches::kSafeMode) || + !ash::ProfileHelper::IsPrimaryProfile(profile)) { + return false; + } +#endif + + return base::ranges::any_of(model->GetLabInfo(), + [&profile](const LabInfo& lab) { + return IsChromeLabsFeatureValid(lab, profile); + }); +}
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_utils.h b/chrome/browser/ui/views/toolbar/chrome_labs_utils.h index 3aaaf26..5b0f1372 100644 --- a/chrome/browser/ui/views/toolbar/chrome_labs_utils.h +++ b/chrome/browser/ui/views/toolbar/chrome_labs_utils.h
@@ -17,4 +17,8 @@ void UpdateChromeLabsNewBadgePrefs(Profile* profile, const ChromeLabsModel* model); +// This will indicate whether any Chrome Labs UI element (toolbar button, +// menu item, etc..) be shown. +bool ShouldShowChromeLabsUI(const ChromeLabsModel* model, Profile* profile); + #endif // CHROME_BROWSER_UI_VIEWS_TOOLBAR_CHROME_LABS_UTILS_H_
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 8189816..e67d127 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -345,8 +345,7 @@ chrome_labs_model_ = std::make_unique<ChromeLabsModel>(); UpdateChromeLabsNewBadgePrefs(browser_->profile(), chrome_labs_model_.get()); - if (ChromeLabsButton::ShouldShowButton(chrome_labs_model_.get(), - browser_->profile())) { + if (ShouldShowChromeLabsUI(chrome_labs_model_.get(), browser_->profile())) { chrome_labs_button_ = AddChildView(std::make_unique<ChromeLabsButton>( browser_view_, chrome_labs_model_.get()));
diff --git a/chrome/browser/ui/views/tooltip/tooltip_browsertest.cc b/chrome/browser/ui/views/tooltip/tooltip_browsertest.cc index 5dc1951..09867f2f 100644 --- a/chrome/browser/ui/views/tooltip/tooltip_browsertest.cc +++ b/chrome/browser/ui/views/tooltip/tooltip_browsertest.cc
@@ -408,7 +408,7 @@ // Validate that a blur event on another element than our focused one doesn't // hide the tooltip. std::string javascript = "document.getElementById('b2').blur();"; - EXPECT_TRUE(content::ExecuteScript(web_contents(), javascript)); + EXPECT_TRUE(content::ExecJs(web_contents(), javascript)); EXPECT_TRUE(helper()->IsTooltipVisible()); EXPECT_EQ(expected_text_1, helper()->GetTooltipText()); @@ -417,7 +417,7 @@ // Validate that a focus on another element will hide the tooltip. javascript = "document.getElementById('b2').focus();"; - EXPECT_TRUE(content::ExecuteScript(web_contents(), javascript)); + EXPECT_TRUE(content::ExecJs(web_contents(), javascript)); tooltip_monitor()->WaitUntilTooltipClosed(); EXPECT_FALSE(tooltip_monitor()->IsWidgetActive()); EXPECT_FALSE(helper()->IsTooltipVisible()); @@ -433,7 +433,7 @@ // Validate that the blur call hides the tooltip. javascript = "document.getElementById('b1').blur();"; - EXPECT_TRUE(content::ExecuteScript(web_contents(), javascript)); + EXPECT_TRUE(content::ExecJs(web_contents(), javascript)); EXPECT_FALSE(tooltip_monitor()->IsWidgetActive()); EXPECT_FALSE(helper()->IsTooltipVisible());
diff --git a/chrome/browser/ui/views/webid/account_selection_bubble_view.h b/chrome/browser/ui/views/webid/account_selection_bubble_view.h index ac2451f..65636b8c 100644 --- a/chrome/browser/ui/views/webid/account_selection_bubble_view.h +++ b/chrome/browser/ui/views/webid/account_selection_bubble_view.h
@@ -222,7 +222,8 @@ bool show_auto_reauthn_checkbox_{false}; // Observes events on AccountSelectionBubbleView. - raw_ptr<Observer> observer_{nullptr}; + // Dangling when running Chromedriver's run_py_tests.py test suite. + raw_ptr<Observer, DanglingUntriaged> observer_{nullptr}; // Callback to create an identity registry. IdentityRegistryCallback identity_registry_callback_;
diff --git a/chrome/browser/ui/webui/BUILD.gn b/chrome/browser/ui/webui/BUILD.gn index 9a9104b..253b136 100644 --- a/chrome/browser/ui/webui/BUILD.gn +++ b/chrome/browser/ui/webui/BUILD.gn
@@ -24,13 +24,6 @@ "//third_party/abseil-cpp:absl", ] - if (is_android) { - sources += [ - "chrome_untrusted_web_ui_configs_android.cc", - "chrome_untrusted_web_ui_configs_android.h", - ] - } - if (is_mac || is_win || is_linux || is_chromeos || is_fuchsia) { sources += [ "chrome_untrusted_web_ui_configs_desktop.cc",
diff --git a/chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui_browsertest.cc b/chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui_browsertest.cc index 631b51f8..3ea76a9 100644 --- a/chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui_browsertest.cc +++ b/chrome/browser/ui/webui/ash/add_supervision/add_supervision_ui_browsertest.cc
@@ -154,7 +154,7 @@ EXPECT_FALSE(IsScreenActive(std::string(kGetSupervisedUserOfflineElementJS))); // Simulate going offline. - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( contents(), "window.dispatchEvent(new CustomEvent('offline'));")); // Ensure only the offline screen is active. @@ -163,7 +163,7 @@ EXPECT_FALSE(IsScreenActive(std::string(kGetAddSupervisionUIElementJS))); // Simulate going online. - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( contents(), "window.dispatchEvent(new CustomEvent('online'));")); // Ensure only the online screen is active. @@ -179,21 +179,21 @@ EXPECT_TRUE(content::WaitForLoadStop(contents())); // Request that the dialog close before supervision has been enabled. - ASSERT_TRUE(content::ExecuteScript( - contents(), std::string(kGetAddSupervisionUIElementJS) + - std::string(".server.requestClose()"))); + ASSERT_TRUE( + content::ExecJs(contents(), std::string(kGetAddSupervisionUIElementJS) + + std::string(".server.requestClose()"))); // Confirm that the signout dialog isn't showing ASSERT_FALSE(ConfirmSignoutDialog::IsShowing()); // Simulate supervision being enabled. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( contents(), std::string(kGetAddSupervisionUIElementJS) + std::string(".server.notifySupervisionEnabled()"))); // Request that the dialog is closed again. - ASSERT_TRUE(content::ExecuteScript( - contents(), std::string(kGetAddSupervisionUIElementJS) + - std::string(".server.requestClose()"))); + ASSERT_TRUE( + content::ExecJs(contents(), std::string(kGetAddSupervisionUIElementJS) + + std::string(".server.requestClose()"))); // Confirm that the dialog is showing. ASSERT_TRUE(ConfirmSignoutDialog::IsShowing()); @@ -217,7 +217,7 @@ EXPECT_TRUE(content::WaitForLoadStop(contents())); // Simulate supervision being enabled. - ASSERT_TRUE(content::ExecuteScript( + ASSERT_TRUE(content::ExecJs( contents(), std::string(kGetAddSupervisionUIElementJS) + std::string(".server.notifySupervisionEnabled()"))); @@ -243,7 +243,7 @@ EXPECT_TRUE(IsScreenActive(std::string(kGetAddSupervisionUIElementJS))); // Simulate an error event. - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( contents(), std::string(kGetAddSupervisionAppElementJS) + std::string(".dispatchEvent(new CustomEvent('show-error'," "{bubbles: true, composed: true}));"))); @@ -254,7 +254,7 @@ EXPECT_FALSE(IsScreenActive(std::string(kGetAddSupervisionUIElementJS))); // Simulate an offline event. - EXPECT_TRUE(content::ExecuteScript( + EXPECT_TRUE(content::ExecJs( contents(), "window.dispatchEvent(new CustomEvent('offline'));")); // Ensure that the error screen remains active.
diff --git a/chrome/browser/ui/webui/ash/certificate_manager_dialog_ui.cc b/chrome/browser/ui/webui/ash/certificate_manager_dialog_ui.cc index 5d0a135..cc175a8d2 100644 --- a/chrome/browser/ui/webui/ash/certificate_manager_dialog_ui.cc +++ b/chrome/browser/ui/webui/ash/certificate_manager_dialog_ui.cc
@@ -10,6 +10,7 @@ #include "chrome/browser/ui/webui/certificate_manager_localized_strings_provider.h" #include "chrome/browser/ui/webui/certificate_provisioning_ui_handler.h" #include "chrome/browser/ui/webui/certificates_handler.h" +#include "chrome/browser/ui/webui/webui_util.h" #include "chrome/common/url_constants.h" #include "chrome/grit/browser_resources.h" #include "chrome/grit/generated_resources.h" @@ -45,8 +46,7 @@ Profile* profile = Profile::FromWebUI(web_ui); content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd( profile, chrome::kChromeUICertificateManagerHost); - - source->DisableTrustedTypesCSP(); + webui::EnableTrustedTypesCSP(source); AddCertificateManagerStrings(source); source->AddBoolean( @@ -58,7 +58,6 @@ source->UseStringsJs(); source->SetDefaultResource(IDR_CERT_MANAGER_DIALOG_HTML); - source->DisableContentSecurityPolicy(); web_ui->AddMessageHandler( std::make_unique<certificate_manager::CertificatesHandler>());
diff --git a/chrome/browser/ui/webui/ash/login/oobe_ui.cc b/chrome/browser/ui/webui/ash/login/oobe_ui.cc index 219ebce5a..15a184f 100644 --- a/chrome/browser/ui/webui/ash/login/oobe_ui.cc +++ b/chrome/browser/ui/webui/ash/login/oobe_ui.cc
@@ -376,9 +376,7 @@ AddScreenHandler(std::make_unique<DemoPreferencesScreenHandler>()); - if (features::IsOobeQuickStartEnabled()) { - AddScreenHandler(std::make_unique<QuickStartScreenHandler>()); - } + AddScreenHandler(std::make_unique<QuickStartScreenHandler>()); } AddScreenHandler(std::make_unique<NetworkScreenHandler>());
diff --git a/chrome/browser/ui/webui/ash/login/welcome_screen_handler.cc b/chrome/browser/ui/webui/ash/login/welcome_screen_handler.cc index 4219c25..6d6d1b5 100644 --- a/chrome/browser/ui/webui/ash/login/welcome_screen_handler.cc +++ b/chrome/browser/ui/webui/ash/login/welcome_screen_handler.cc
@@ -278,7 +278,6 @@ } void WelcomeScreenHandler::SetQuickStartEnabled() { - DCHECK(features::IsOobeQuickStartEnabled()); CallExternalAPI("setQuickStartEnabled"); }
diff --git a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc b/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc index e9783e0..f374d77c 100644 --- a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc +++ b/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.cc
@@ -8,10 +8,6 @@ #include "build/chromeos_buildflags.h" #include "chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_common.h" -#if BUILDFLAG(IS_ANDROID) -#include "chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_android.h" -#endif // BUILDFLAG(IS_ANDROID) - #if !BUILDFLAG(IS_ANDROID) #include "chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_desktop.h" #endif // !BUILDFLAG(IS_ANDROID) @@ -23,17 +19,12 @@ void RegisterChromeUntrustedWebUIConfigs() { // Don't add calls to `AddUntrustedWebUIConfig()` here. Add it in one of // the corresponding files: - // - chrome_untrusted_web_ui_configs_android.cc // - chrome_untrusted_web_ui_configs_common.cc // - chrome_untrusted_web_ui_configs_desktop.cc // - chrome_untrusted_web_ui_configs_chromeos.cc RegisterCommonChromeUntrustedWebUIConfigs(); -#if BUILDFLAG(IS_ANDROID) - RegisterAndroidChromeUntrustedWebUIConfigs(); -#endif // BUILDFLAG(IS_ANDROID) - #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA) RegisterDesktopChromeUntrustedWebUIConfigs();
diff --git a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_android.cc b/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_android.cc deleted file mode 100644 index dd638bf..0000000 --- a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_android.cc +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_android.h" - -#include "chrome/browser/ui/webui/video_tutorials/video_player_ui.h" -#include "content/public/browser/webui_config_map.h" - -void RegisterAndroidChromeUntrustedWebUIConfigs() { - auto& map = content::WebUIConfigMap::GetInstance(); - - // Add untrusted `WebUIConfig`s for Android to the list here. - map.AddUntrustedWebUIConfig( - std::make_unique<video_tutorials::VideoPlayerUIConfig>()); -}
diff --git a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_android.h b/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_android.h deleted file mode 100644 index f552ddf..0000000 --- a/chrome/browser/ui/webui/chrome_untrusted_web_ui_configs_android.h +++ /dev/null
@@ -1,11 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_CHROME_UNTRUSTED_WEB_UI_CONFIGS_ANDROID_H_ -#define CHROME_BROWSER_UI_WEBUI_CHROME_UNTRUSTED_WEB_UI_CONFIGS_ANDROID_H_ - -// Method that adds untrusted `WebUIConfig`s for Android to `WebUIConfigMap`. -void RegisterAndroidChromeUntrustedWebUIConfigs(); - -#endif // CHROME_BROWSER_UI_WEBUI_CHROME_UNTRUSTED_WEB_UI_CONFIGS_ANDROID_H_
diff --git a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc index e21c2294..f3f0ebc 100644 --- a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc +++ b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
@@ -370,6 +370,7 @@ // ArcGraphicsTracingHandler::ArcGraphicsTracingHandler. // "chrome://arc-graphics-tracing", "chrome://app-disabled", + "chrome://certificate-manager/", "chrome://cryptohome", "chrome://drive-internals", "chrome://emoji-picker",
diff --git a/chrome/browser/ui/webui/commander/commander_ui_browsertest.cc b/chrome/browser/ui/webui/commander/commander_ui_browsertest.cc index 469c3a97..df402377 100644 --- a/chrome/browser/ui/webui/commander/commander_ui_browsertest.cc +++ b/chrome/browser/ui/webui/commander/commander_ui_browsertest.cc
@@ -55,7 +55,7 @@ protected: void ExecuteJS(std::string js) { - ASSERT_TRUE(content::ExecuteScript(contents_.get(), js)); + ASSERT_TRUE(content::ExecJs(contents_.get(), js)); } // CommanderHandler::Delegate implementation. void OnTextChanged(const std::u16string& text) override {
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc index d51847d..6f57762 100644 --- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc +++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -235,7 +235,7 @@ // Attempt to add an event listener for the // activityLogPrivate.onExtensionActivity event. - ASSERT_TRUE(content::ExecuteScript(page_contents, R"( + ASSERT_TRUE(content::ExecJs(page_contents, R"( let activityLogListener = () => {}; chrome.activityLogPrivate.onExtensionActivity.addListener( activityLogListener);
diff --git a/chrome/browser/ui/webui/intro/intro_ui.cc b/chrome/browser/ui/webui/intro/intro_ui.cc index b76078b..30f722e9 100644 --- a/chrome/browser/ui/webui/intro/intro_ui.cc +++ b/chrome/browser/ui/webui/intro/intro_ui.cc
@@ -118,11 +118,6 @@ #endif #endif -#if BUILDFLAG(IS_CHROMEOS_LACROS) - source->AddBoolean("isTangibleSyncEnabled", - base::FeatureList::IsEnabled(switches::kTangibleSync)); -#endif - webui::SetupChromeRefresh2023(source); // Unretained ok: `this` owns the handler.
diff --git a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui_browsertest.cc b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui_browsertest.cc index a1b5d2f..d3ef4431 100644 --- a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui_browsertest.cc +++ b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui_browsertest.cc
@@ -96,19 +96,19 @@ // Calling 'close' before a Sharesheet controller is registered via // |SetSharesheetController| does not result in a crash. std::string script = BuildCloseScript(CloseReason::kCancelled); - EXPECT_TRUE(content::ExecuteScript(web_contents, script)); + EXPECT_TRUE(content::ExecJs(web_contents, script)); EXPECT_FALSE(sharesheet_controller_.last_result); // The Sharesheet controller gets called on 'close' if it's been registered. nearby_ui->SetSharesheetController(&sharesheet_controller_); - EXPECT_TRUE(content::ExecuteScript(web_contents, script)); + EXPECT_TRUE(content::ExecJs(web_contents, script)); EXPECT_EQ(::sharesheet::SharesheetResult::kCancel, sharesheet_controller_.last_result); // Any subsequent calls to 'close' do not call the Sharesheet controller, // since that would result in a crash. sharesheet_controller_.last_result.reset(); - EXPECT_TRUE(content::ExecuteScript(web_contents, script)); + EXPECT_TRUE(content::ExecJs(web_contents, script)); EXPECT_FALSE(sharesheet_controller_.last_result); } @@ -124,7 +124,7 @@ sharesheet_controller_.last_result.reset(); nearby_ui->SetSharesheetController(&sharesheet_controller_); - EXPECT_TRUE(content::ExecuteScript(web_contents, BuildCloseScript(reason))); + EXPECT_TRUE(content::ExecJs(web_contents, BuildCloseScript(reason))); // Verify that the page-closed reason is translated into the correct // SharesheetResult and passed into CloseBubble().
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc index adb1ed3..614b730 100644 --- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -515,6 +515,8 @@ // being set. ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_USER_CHOICE)); + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault(Return(syncer::SyncService::TransportState::DISABLED)); @@ -525,6 +527,8 @@ // immediately starts initializing the engine. ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault( Return(syncer::SyncService::TransportState::INITIALIZING)); @@ -545,6 +549,8 @@ // mode. ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_USER_CHOICE)); + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault(Return(syncer::SyncService::TransportState::ACTIVE)); @@ -555,6 +561,8 @@ // the engine is already running, it just gets reconfigured. ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault( Return(syncer::SyncService::TransportState::CONFIGURING)); @@ -1119,6 +1127,8 @@ // bits being cleared. ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_USER_CHOICE)); + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) .WillByDefault(Return(false)); // Sync will eventually start again in transport mode. @@ -1136,6 +1146,8 @@ // immediately starts initializing the engine. ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault( Return(syncer::SyncService::TransportState::INITIALIZING)); @@ -1169,6 +1181,8 @@ // bits being cleared. ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DISABLE_REASON_USER_CHOICE)); + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(true)); ON_CALL(*mock_sync_service_->GetMockUserSettings(), IsFirstSetupComplete()) .WillByDefault(Return(false)); // Sync will eventually start again in transport mode. @@ -1199,6 +1213,8 @@ // immediately starts initializing the engine. ON_CALL(*mock_sync_service_, GetDisableReasons()) .WillByDefault(Return(syncer::SyncService::DisableReasonSet())); + ON_CALL(*mock_sync_service_, IsSyncFeatureDisabledViaDashboard()) + .WillByDefault(Return(false)); ON_CALL(*mock_sync_service_, GetTransportState()) .WillByDefault( Return(syncer::SyncService::TransportState::INITIALIZING));
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc index aed6170..feb5b682 100644 --- a/chrome/browser/ui/webui/settings/site_settings_handler.cc +++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -1764,6 +1764,10 @@ "SoundContentSetting.UnmuteBy.SiteSettings")); } } + + permissions::PermissionUmaUtil::RecordPermissionRegrantForUnusedSites( + origin, content_type, permissions::PermissionSourceUI::SITE_SETTINGS, + profile_, base::Time::Now()); } // Show an infobar reminding the user to reload tabs where their site
diff --git a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler_unittest.cc b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler_unittest.cc index 069833d..5340148 100644 --- a/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler_unittest.cc +++ b/chrome/browser/ui/webui/signin/dice_web_signin_intercept_handler_unittest.cc
@@ -303,6 +303,8 @@ }; TEST_P(DiceWebSigninInterceptHandlerTest, CheckStrings) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(kSigninInterceptBubbleV2); base::Value::Dict parameters = GetInterceptionParameters(); EXPECT_FALSE(*parameters.FindBool("useV2Design"));
diff --git a/chrome/browser/ui/webui/video_tutorials/DIR_METADATA b/chrome/browser/ui/webui/video_tutorials/DIR_METADATA deleted file mode 100644 index 00888370..0000000 --- a/chrome/browser/ui/webui/video_tutorials/DIR_METADATA +++ /dev/null
@@ -1 +0,0 @@ -mixins: "//chrome/browser/video_tutorials/COMMON_METADATA"
diff --git a/chrome/browser/ui/webui/video_tutorials/OWNERS b/chrome/browser/ui/webui/video_tutorials/OWNERS deleted file mode 100644 index 36c3bec..0000000 --- a/chrome/browser/ui/webui/video_tutorials/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -file://chrome/browser/video_tutorials/OWNERS
diff --git a/chrome/browser/ui/webui/video_tutorials/video_player_ui.cc b/chrome/browser/ui/webui/video_tutorials/video_player_ui.cc deleted file mode 100644 index ded63e2e..0000000 --- a/chrome/browser/ui/webui/video_tutorials/video_player_ui.cc +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/ui/webui/video_tutorials/video_player_ui.h" - -#include "chrome/common/webui_url_constants.h" -#include "chrome/grit/browser_resources.h" -#include "content/public/browser/web_contents.h" -#include "content/public/browser/web_ui.h" -#include "content/public/browser/web_ui_data_source.h" -#include "services/network/public/mojom/content_security_policy.mojom.h" - -namespace video_tutorials { - -VideoPlayerUIConfig::VideoPlayerUIConfig() - : WebUIConfig(content::kChromeUIUntrustedScheme, - chrome::kChromeUIUntrustedVideoTutorialsHost) {} - -VideoPlayerUIConfig::~VideoPlayerUIConfig() = default; - -std::unique_ptr<content::WebUIController> -VideoPlayerUIConfig::CreateWebUIController(content::WebUI* web_ui, - const GURL& url) { - return std::make_unique<VideoPlayerUI>(web_ui); -} - -VideoPlayerUI::VideoPlayerUI(content::WebUI* web_ui) - : ui::UntrustedWebUIController(web_ui) { - content::WebUIDataSource* source = content::WebUIDataSource::CreateAndAdd( - web_ui->GetWebContents()->GetBrowserContext(), - chrome::kChromeUIUntrustedVideoPlayerUrl); - source->AddResourcePath("", IDR_VIDEO_PLAYER_HTML); - source->AddResourcePath("video_player.css", IDR_VIDEO_PLAYER_CSS); - source->AddResourcePath("video_player.js", IDR_VIDEO_PLAYER_JS); - - source->OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::ConnectSrc, "connect-src https:;"); - source->OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::ImgSrc, "img-src https:;"); - source->OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::MediaSrc, "media-src https:;"); - source->OverrideContentSecurityPolicy( - network::mojom::CSPDirectiveName::StyleSrc, "style-src 'self';"); -} - -VideoPlayerUI::~VideoPlayerUI() = default; - -} // namespace video_tutorials
diff --git a/chrome/browser/ui/webui/video_tutorials/video_player_ui.h b/chrome/browser/ui/webui/video_tutorials/video_player_ui.h deleted file mode 100644 index 53fd2c3..0000000 --- a/chrome/browser/ui/webui/video_tutorials/video_player_ui.h +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2021 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_VIDEO_TUTORIALS_VIDEO_PLAYER_UI_H_ -#define CHROME_BROWSER_UI_WEBUI_VIDEO_TUTORIALS_VIDEO_PLAYER_UI_H_ - -#include "content/public/browser/webui_config.h" -#include "ui/webui/untrusted_web_ui_controller.h" - -namespace content { -class WebUI; -} // namespace content - -namespace video_tutorials { - -class VideoPlayerUIConfig : public content::WebUIConfig { - public: - VideoPlayerUIConfig(); - ~VideoPlayerUIConfig() override; - - std::unique_ptr<content::WebUIController> CreateWebUIController( - content::WebUI* web_ui, - const GURL& url) override; -}; - -class VideoPlayerUI : public ui::UntrustedWebUIController { - public: - explicit VideoPlayerUI(content::WebUI* web_ui); - VideoPlayerUI(const VideoPlayerUI&) = delete; - VideoPlayerUI& operator=(const VideoPlayerUI&) = delete; - ~VideoPlayerUI() override; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_UI_WEBUI_VIDEO_TUTORIALS_VIDEO_PLAYER_UI_H_
diff --git a/chrome/browser/unload_browsertest.cc b/chrome/browser/unload_browsertest.cc index be14d0364..fe2dc6d0 100644 --- a/chrome/browser/unload_browsertest.cc +++ b/chrome/browser/unload_browsertest.cc
@@ -661,8 +661,8 @@ GURL popup_url(embedded_test_server()->GetURL("a.com", "/title2.html")); content::TestNavigationObserver popup_observer(nullptr); popup_observer.StartWatchingNewWebContents(); - EXPECT_TRUE(ExecuteScript(opener_contents, - "window.open('" + popup_url.spec() + "');")); + EXPECT_TRUE( + ExecJs(opener_contents, "window.open('" + popup_url.spec() + "');")); popup_observer.Wait(); ASSERT_EQ(2, browser()->tab_strip_model()->count()); content::WebContents* popup_contents = @@ -693,7 +693,7 @@ // Close the popup. content::WebContentsDestroyedWatcher destroyed_watcher(popup_contents); - EXPECT_TRUE(ExecuteScript(popup_contents, "window.close();")); + EXPECT_TRUE(ExecJs(popup_contents, "window.close();")); destroyed_watcher.Wait(); // Check that we've only dispatched visibilitychange once. @@ -743,8 +743,7 @@ // Install a dialog-showing beforeunload handler in the iframe. content::RenderFrameHost* child = ChildFrameAt(web_contents->GetPrimaryMainFrame(), 0); - EXPECT_TRUE( - ExecuteScript(child, "window.onbeforeunload = () => { return 'x' };")); + EXPECT_TRUE(ExecJs(child, "window.onbeforeunload = () => { return 'x' };")); // Close the browser and make sure the beforeunload dialog is shown and can // be clicked. @@ -768,8 +767,7 @@ web_contents->GetPrimaryMainFrame()->GetSiteInstance()); // Install a dialog-showing beforeunload handler in the iframe. - EXPECT_TRUE( - ExecuteScript(child, "window.onbeforeunload = () => { return 'x' };")); + EXPECT_TRUE(ExecJs(child, "window.onbeforeunload = () => { return 'x' };")); // Close the browser and make sure the beforeunload dialog is shown and can // be clicked.
diff --git a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommand.java b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommand.java index f918d7b..aaf608d 100644 --- a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommand.java +++ b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommand.java
@@ -95,30 +95,4 @@ this.removeArrow = removeArrow; this.preferredVerticalOrientation = preferredVerticalOrientation; } - - // TODO(peilinwang): Remove this constructor after ANDROID_SCROLL_OPTIMIZATIONS fully rolls out. - IPHCommand(String featureName, String contentString, String accessibilityText, - boolean dismissOnTouch, View anchorView, Runnable onDismissCallback, - Runnable onShowCallback, Runnable onBlockedCallback, Rect insetRect, - long autoDismissTimeout, ViewRectProvider viewRectProvider, HighlightParams params, - Rect anchorRect, boolean removeArrow, - @AnchoredPopupWindow.VerticalOrientation int preferredVerticalOrientation) { - this.stringId = 0; - this.accessibilityStringId = 0; - this.featureName = featureName; - this.contentString = contentString; - this.accessibilityText = accessibilityText; - this.dismissOnTouch = dismissOnTouch; - this.anchorView = anchorView; - this.onDismissCallback = onDismissCallback; - this.onShowCallback = onShowCallback; - this.onBlockedCallback = onBlockedCallback; - this.insetRect = insetRect; - this.autoDismissTimeout = autoDismissTimeout; - this.viewRectProvider = viewRectProvider; - this.highlightParams = params; - this.anchorRect = anchorRect; - this.removeArrow = removeArrow; - this.preferredVerticalOrientation = preferredVerticalOrientation; - } }
diff --git a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommandBuilder.java b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommandBuilder.java index d89bdfb..dd4a1620 100644 --- a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommandBuilder.java +++ b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/IPHCommandBuilder.java
@@ -12,7 +12,6 @@ import androidx.annotation.StringRes; import org.chromium.base.TraceEvent; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter.HighlightParams; import org.chromium.components.browser_ui.widget.textbubble.TextBubble; import org.chromium.ui.widget.AnchoredPopupWindow; @@ -233,10 +232,6 @@ * @return an (@see IPHCommand) containing the accumulated state of this builder. */ public IPHCommand build() { - if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS)) { - return buildLazy(); - } - try (TraceEvent te = TraceEvent.scoped("IPHCommandBuilder::build")) { if (mOnDismissCallback == null) { mOnDismissCallback = NO_OP_RUNNABLE; @@ -249,51 +244,6 @@ mOnBlockedCallback = NO_OP_RUNNABLE; } - if (mContentString == null) { - assert mResources != null; - if (mStringArgs != null) { - mContentString = mResources.getString(mStringId, mStringArgs); - } else { - mContentString = mResources.getString(mStringId); - } - } - - if (mAccessibilityText == null) { - assert mResources != null; - if (mAccessibilityStringArgs != null) { - mAccessibilityText = - mResources.getString(mAccessibilityStringId, mAccessibilityStringArgs); - } else { - mAccessibilityText = mResources.getString(mAccessibilityStringId); - } - } - - if (mInsetRect == null && mAnchorRect == null) { - int yInsetPx = mResources.getDimensionPixelOffset( - R.dimen.iph_text_bubble_menu_anchor_y_inset); - mInsetRect = new Rect(0, 0, 0, yInsetPx); - } - - return new IPHCommand(mFeatureName, mContentString, mAccessibilityText, mDismissOnTouch, - mAnchorView, mOnDismissCallback, mOnShowCallback, mOnBlockedCallback, - mInsetRect, mAutoDismissTimeout, mViewRectProvider, mHighlightParams, - mAnchorRect, mRemoveArrow, mPreferredVerticalOrientation); - } - } - - public IPHCommand buildLazy() { - try (TraceEvent te = TraceEvent.scoped("IPHCommandBuilder::buildLazy")) { - if (mOnDismissCallback == null) { - mOnDismissCallback = NO_OP_RUNNABLE; - } - if (mOnShowCallback == null) { - mOnShowCallback = NO_OP_RUNNABLE; - } - - if (mOnBlockedCallback == null) { - mOnBlockedCallback = NO_OP_RUNNABLE; - } - return new IPHCommand(mResources, mFeatureName, mStringId, mStringArgs, mAccessibilityStringId, mAccessibilityStringArgs, mDismissOnTouch, mAnchorView, mOnDismissCallback, mOnShowCallback, mOnBlockedCallback, mAutoDismissTimeout,
diff --git a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java index 961a2cb..095b5947 100644 --- a/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java +++ b/chrome/browser/user_education/java/src/org/chromium/chrome/browser/user_education/UserEducationHelper.java
@@ -10,7 +10,6 @@ import org.chromium.base.TraceEvent; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.util.ChromeAccessibilityUtil; import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter; @@ -100,11 +99,9 @@ return; } - // If scroll optimizations were enabled, iphCommand would have been built lazily, and we - // would have to fetch the data that is needed from this point on. - if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_SCROLL_OPTIMIZATIONS)) { - iphCommand.fetchFromResources(); - } + // iphCommand would have been built lazily, and we would have to fetch the data that is + // needed from this point on. + iphCommand.fetchFromResources(); String contentString = iphCommand.contentString; String accessibilityString = iphCommand.accessibilityText;
diff --git a/chrome/browser/video_tutorials/BUILD.gn b/chrome/browser/video_tutorials/BUILD.gn deleted file mode 100644 index 869cb0ad..0000000 --- a/chrome/browser/video_tutorials/BUILD.gn +++ /dev/null
@@ -1,159 +0,0 @@ -# Copyright 2020 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -if (is_android) { - import("//build/config/android/config.gni") - import("//build/config/android/rules.gni") - import("//chrome/android/features/android_library_factory_tmpl.gni") -} - -group("video_tutorials") { - public_deps = [ - ":factory", - ":public", - ] - - deps = [ "internal" ] -} - -source_set("public") { - sources = [ - "prefs.cc", - "prefs.h", - "switches.cc", - "switches.h", - "tutorial.cc", - "tutorial.h", - "video_tutorial_service.h", - "video_tutorial_tab_helper.cc", - "video_tutorial_tab_helper.h", - ] - - deps = [ - "//chrome/common", - "//content/public/browser", - ] - - public_deps = [ - "//base", - "//components/keyed_service/core", - "//components/prefs", - "//url:url", - ] -} - -source_set("factory") { - sources = [ - "tutorial_factory_helper.cc", - "tutorial_factory_helper.h", - ] - - deps = [ - ":public", - "internal:internal", - "//chrome/browser/video_tutorials/proto", - "//components/leveldb_proto", - ] -} - -if (is_android) { - android_library("java") { - sources = [ - "android/java/src/org/chromium/chrome/browser/video_tutorials/Language.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/LanguageInfoProvider.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialService.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinator.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialIPHUtils.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialTryNowTracker.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinator.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinator.java", - ] - - deps = [ - ":java_resources", - "//base:base_java", - "//components/browser_ui/widget/android:java", - "//components/feature_engagement/public:public_java", - "//components/image_fetcher:java", - "//content/public/android:content_java", - "//third_party/androidx:androidx_annotation_annotation_java", - "//ui/android:ui_java", - ] - - resources_package = "org.chromium.chrome.browser.video_tutorials" - srcjar_deps = [ ":jni_enums" ] - } - - android_resources("java_resources") { - sources = [ - "android/java/res/layout/video_tutorial_iph_card.xml", - "android/java/res/layout/video_tutorial_list.xml", - ] - - deps = [ - "//chrome/browser/ui/android/strings:ui_strings_grd", - "//components/browser_ui/widget/android:java_resources", - "//ui/android:ui_java_resources", - ] - } - - java_cpp_enum("jni_enums") { - visibility = [ "*" ] - - sources = [ "tutorial.h" ] - } - - android_library_factory("factory_java") { - # These deps will be inherited by the resulting android_library target. - deps = [ - ":java", - "//chrome/browser/profiles/android:java", - "//components/embedder_support/android:content_view_java", - "//components/image_fetcher:java", - "//content/public/android:content_java", - "//third_party/androidx:androidx_recyclerview_recyclerview_java", - "//ui/android:ui_no_recycler_view_java", - ] - - # This internal file will be replaced by a generated file so the resulting - # android_library target does not actually depend on this internal file. - sources = [ "internal/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialServiceFactory.java" ] - } - - android_library("test_support_java") { - sources = [ - "android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestImageFetcher.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java", - ] - - deps = [ - ":java", - "//base:base_java", - "//components/image_fetcher:java", - "//third_party/androidx:androidx_annotation_annotation_java", - "//third_party/gif_player:gif_player_java", - ] - } -} - -group("unit_tests") { - testonly = true - - deps = [ - ":video_tutorials_unit_tests", - "internal:unit_tests", - ] -} - -source_set("video_tutorials_unit_tests") { - testonly = true - sources = [ "tutorial_unittest.cc" ] - deps = [ - ":public", - "//base/test:test_support", - "//testing/gtest", - ] -}
diff --git a/chrome/browser/video_tutorials/COMMON_METADATA b/chrome/browser/video_tutorials/COMMON_METADATA deleted file mode 100644 index e6c59a32..0000000 --- a/chrome/browser/video_tutorials/COMMON_METADATA +++ /dev/null
@@ -1,5 +0,0 @@ -monorail: { - component: "Upboarding>VideoTutorials" -} -team_email: "chrome-upboarding-eng@google.com" -os: ANDROID
diff --git a/chrome/browser/video_tutorials/DEPS b/chrome/browser/video_tutorials/DEPS deleted file mode 100644 index 57ea641..0000000 --- a/chrome/browser/video_tutorials/DEPS +++ /dev/null
@@ -1,8 +0,0 @@ -include_rules = [ - "+components/browser_ui/widget", - "+components/image_fetcher/android", - "+components/keyed_service", - "+components/leveldb_proto", - "+components/thin_webview/java", - "+content/public/android/java/src/org/chromium/content_public", -]
diff --git a/chrome/browser/video_tutorials/DIR_METADATA b/chrome/browser/video_tutorials/DIR_METADATA deleted file mode 100644 index 00888370..0000000 --- a/chrome/browser/video_tutorials/DIR_METADATA +++ /dev/null
@@ -1 +0,0 @@ -mixins: "//chrome/browser/video_tutorials/COMMON_METADATA"
diff --git a/chrome/browser/video_tutorials/OWNERS b/chrome/browser/video_tutorials/OWNERS deleted file mode 100644 index ffc05827..0000000 --- a/chrome/browser/video_tutorials/OWNERS +++ /dev/null
@@ -1 +0,0 @@ -shaktisahu@chromium.org
diff --git a/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_iph_card.xml b/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_iph_card.xml deleted file mode 100644 index e3433f4..0000000 --- a/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_iph_card.xml +++ /dev/null
@@ -1,81 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2020 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<org.chromium.components.browser_ui.widget.MaterialCardViewNoShadow - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/MaterialCardStyle"> - - <RelativeLayout - android:id="@+id/video_tutorial_card" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingStart="12dp" - android:paddingBottom="12dp" > - - <androidx.cardview.widget.CardView - android:id="@+id/thumbnail_wrapper" - android:layout_width="77dp" - android:layout_height="58dp" - android:layout_gravity="center_vertical" - android:layout_marginTop="12dp" - app:cardCornerRadius="8dp" - app:cardElevation="0dp" - app:cardBackgroundColor="@android:color/transparent"> - - <org.chromium.components.browser_ui.widget.async_image.AsyncImageView - android:id="@+id/thumbnail" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:importantForAccessibility="no" - app:unavailableSrc="@color/image_loading_color" - app:waitingSrc="@color/image_loading_color" - app:roundedfillColor="@color/modern_grey_300" /> - - </androidx.cardview.widget.CardView> - - <TextView - android:id="@+id/video_length" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignBottom="@id/thumbnail_wrapper" - android:layout_marginStart="6dp" - android:layout_marginBottom="6dp" - android:paddingStart="4dp" - android:paddingEnd="4dp" - android:background="@color/modern_grey_900" - android:importantForAccessibility="no" - android:textAppearance="@style/TextAppearance.TextSmall.Primary.Baseline.Light" /> - - <TextView - android:id="@+id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_toEndOf="@id/thumbnail_wrapper" - android:layout_toStartOf="@id/close_button" - android:layout_centerVertical="true" - android:layout_marginStart="12dp" - android:layout_marginEnd="12dp" - android:ellipsize="end" - android:maxLines="3" - android:textAppearance="@style/TextAppearance.TextLarge.Primary" /> - - <org.chromium.ui.widget.ChromeImageButton - android:id="@+id/close_button" - android:layout_height="48dp" - android:layout_width="48dp" - android:layout_alignParentEnd="true" - android:background="?attr/selectableItemBackground" - android:contentDescription="@string/close" - android:scaleType="center" - android:src="@drawable/btn_close" - app:tint="@color/default_icon_color_tint_list" /> - - </RelativeLayout> -</org.chromium.components.browser_ui.widget.MaterialCardViewNoShadow>
diff --git a/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_list.xml b/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_list.xml deleted file mode 100644 index f111946..0000000 --- a/chrome/browser/video_tutorials/android/java/res/layout/video_tutorial_list.xml +++ /dev/null
@@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2020 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/video_tutorial_list" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingTop="4dp" > - - <LinearLayout - android:id="@+id/toolbar" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" > - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="16dp" - android:layout_gravity="center_vertical" - android:text="@string/video_tutorials_learn_chrome" - android:textAppearance="@style/TextAppearance.Headline.Primary" /> - - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="1" /> - - <org.chromium.ui.widget.ChromeImageButton - android:id="@+id/close_button" - android:layout_height="48dp" - android:layout_width="48dp" - android:layout_marginEnd="4dp" - android:background="?attr/selectableItemBackground" - android:contentDescription="@string/close" - android:scaleType="center" - android:src="@drawable/btn_close" - app:tint="@color/default_icon_color_tint_list" /> - </LinearLayout> - - <FrameLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginTop="4dp" > - - <androidx.recyclerview.widget.RecyclerView - android:id="@+id/recycler_view" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - - <org.chromium.components.browser_ui.widget.FadingShadowView - android:id="@+id/toolbar_shadow" - android:layout_width="match_parent" - android:layout_height="@dimen/action_bar_shadow_height"/> - </FrameLayout> -</LinearLayout>
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Language.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Language.java deleted file mode 100644 index 194e51d..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Language.java +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials; - -/** - * Class encapsulating data needed to show a language on the language selection UI. - */ -public class Language { - /** The locale associated with the language. */ - public final String locale; - - /** The name of the language. */ - public final String name; - - /** The name of the language in native text. */ - public final String nativeName; - - /** Constructor */ - public Language(String locale, String name, String nativeName) { - this.locale = locale; - this.name = name; - this.nativeName = nativeName; - } -}
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/LanguageInfoProvider.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/LanguageInfoProvider.java deleted file mode 100644 index 59b7fff..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/LanguageInfoProvider.java +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials; - -/** - * Interface for obtaining the language information for a given locale in order to display on the - * UI. - */ -public interface LanguageInfoProvider { - /** -x * @return The language info for a given {@code locale}. - */ - Language getLanguageInfo(String locale); -}
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java deleted file mode 100644 index 165ec4a..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials; - -/** - * Class encapsulating data needed to show a video tutorial on the UI. - */ -public class Tutorial { - public final @FeatureType int featureType; - public final String title; - public final String accessibilityText; - public final String videoUrl; - public final String posterUrl; - public final String animatedGifUrl; - public final String thumbnailUrl; - public final String captionUrl; - public final String shareUrl; - public final int videoLength; - - /** Constructor */ - public Tutorial(@FeatureType int featureType, String title, String videoUrl, String posterUrl, - String animatedGifUrl, String thumbnailUrl, String captionUrl, String shareUrl, - int videoLength) { - this.featureType = featureType; - this.title = title; - this.accessibilityText = title; - this.videoUrl = videoUrl; - this.posterUrl = posterUrl; - this.animatedGifUrl = animatedGifUrl; - this.thumbnailUrl = thumbnailUrl; - this.captionUrl = captionUrl; - this.shareUrl = shareUrl; - this.videoLength = videoLength; - } -}
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialService.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialService.java deleted file mode 100644 index 1001594..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialService.java +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials; - -import org.chromium.base.Callback; - -import java.util.List; - -/** - * Java interface for interacting with the native video tutorial service. Responsible for - * initializing and fetching data fo be shown on the UI. - */ -public interface VideoTutorialService { - /** - * Called to get the list of video tutorials available. - */ - void getTutorials(Callback<List<Tutorial>> callback); - - /** - * Called to get the tutorial for a given feature. - */ - void getTutorial(@FeatureType int featureType, Callback<Tutorial> callback); - - /** - * Called to get the list of supported languages. - * Deprecated in favor of getAvailableLanguagesForVideo(@FeatureType). - */ - List<String> getSupportedLanguages(); - - /** - * Called to get the list of supported languages in which a tutorial is available. - * @param feature The associated tutorial. - */ - List<String> getAvailableLanguagesForTutorial(@FeatureType int feature); - - /** - * @return The user's language of choice for watching the video tutorials, or null user hasn't - * set it yet. - */ - String getPreferredLocale(); - - /** - * Called to set the user's preferred {@link locale} for watching the videos. The caller - * should make another getTutorial() method call immediately to get the new list of tutorials in - * the newly selected language. - */ - void setPreferredLocale(String locale); -}
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinator.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinator.java deleted file mode 100644 index 1dff9c10..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinator.java +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.iph; - -import android.view.ViewStub; - -import org.chromium.chrome.browser.video_tutorials.Tutorial; - -/** - * Creates and shows a video tutorial IPH. Requires a {@link ViewStub} to be passed which will - * inflate when the IPH is shown. - */ -public interface VideoIPHCoordinator { - /** - * Shows an IPH card featuring the given {@link Tutorial}. Can be called multiple times with - * different tutorials. The ViewStub will inflate and create the card on the first invocation. - * @param tutorial The tutorial to be featured in the IPH. - */ - void showVideoIPH(Tutorial tutorial); - - /** - * Hides the IPH card. Should be called after it has been clicked. - */ - void hideVideoIPH(); -} \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialIPHUtils.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialIPHUtils.java deleted file mode 100644 index f59a07a..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialIPHUtils.java +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.iph; - -import androidx.annotation.Nullable; - -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.components.feature_engagement.EventConstants; -import org.chromium.components.feature_engagement.FeatureConstants; - -/** - * Handles various feature utility functions associated with video tutorials IPH. - */ -public class VideoTutorialIPHUtils { - /** - * @return The feature name to be used in IPH backend for the given {@code featureType} in order - * to show the feature IPH on NTP. - */ - public static @Nullable String getFeatureNameForNTP(@FeatureType int featureType) { - switch (featureType) { - case FeatureType.SUMMARY: - return FeatureConstants.VIDEO_TUTORIAL_NTP_SUMMARY_FEATURE; - case FeatureType.CHROME_INTRO: - return FeatureConstants.VIDEO_TUTORIAL_NTP_CHROME_INTRO_FEATURE; - case FeatureType.DOWNLOAD: - return FeatureConstants.VIDEO_TUTORIAL_NTP_DOWNLOAD_FEATURE; - case FeatureType.SEARCH: - return FeatureConstants.VIDEO_TUTORIAL_NTP_SEARCH_FEATURE; - case FeatureType.VOICE_SEARCH: - return FeatureConstants.VIDEO_TUTORIAL_NTP_VOICE_SEARCH_FEATURE; - default: - // It's possible that there are more feature types known to server than the client. - // Don't show an IPH for those tutorials. - return null; - } - } - - /** - * @return The event used in IPH backend when the IPH associated with the {@code featureType} - * on NTP is clicked. - */ - public static String getClickEvent(@FeatureType int featureType) { - switch (featureType) { - case FeatureType.SUMMARY: - return EventConstants.VIDEO_TUTORIAL_CLICKED_SUMMARY; - case FeatureType.CHROME_INTRO: - return EventConstants.VIDEO_TUTORIAL_CLICKED_CHROME_INTRO; - case FeatureType.DOWNLOAD: - return EventConstants.VIDEO_TUTORIAL_CLICKED_DOWNLOAD; - case FeatureType.SEARCH: - return EventConstants.VIDEO_TUTORIAL_CLICKED_SEARCH; - case FeatureType.VOICE_SEARCH: - return EventConstants.VIDEO_TUTORIAL_CLICKED_VOICE_SEARCH; - default: - assert false; - return null; - } - } - - /** - * @return The event used in IPH backend when the IPH associated with the {@code featureType} - * on NTP is dismissed. - */ - public static String getDismissEvent(@FeatureType int featureType) { - switch (featureType) { - case FeatureType.SUMMARY: - return EventConstants.VIDEO_TUTORIAL_DISMISSED_SUMMARY; - case FeatureType.CHROME_INTRO: - return EventConstants.VIDEO_TUTORIAL_DISMISSED_CHROME_INTRO; - case FeatureType.DOWNLOAD: - return EventConstants.VIDEO_TUTORIAL_DISMISSED_DOWNLOAD; - case FeatureType.SEARCH: - return EventConstants.VIDEO_TUTORIAL_DISMISSED_SEARCH; - case FeatureType.VOICE_SEARCH: - return EventConstants.VIDEO_TUTORIAL_DISMISSED_VOICE_SEARCH; - default: - assert false; - return null; - } - } - -}
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialTryNowTracker.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialTryNowTracker.java deleted file mode 100644 index 10eed8e..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoTutorialTryNowTracker.java +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.iph; - -import org.chromium.chrome.browser.video_tutorials.FeatureType; - -/** - * This class acts as a temporary tracker of the user click on Try Now button on the video player - * during a chrome session. As soon as a - */ -public interface VideoTutorialTryNowTracker { - /** - * Called to record that the Try Now button has been clicked by the user, and we should show the - * appropriate UI. - * @param featureType The feature type associated with the tutorial. - */ - void recordTryNowButtonClicked(@FeatureType int featureType); - - /** - * Called to determine whether or not the Try Now button was clicked by the user. - * @param featureType The feature type associated with the tutorial. - * @return Whether or not the Try Now button was clicked for a video tutorial. - */ - boolean didClickTryNowButton(@FeatureType int featureType); - - /** - * Called when the try now UI was shown. Serves as a signal to reset the internal state of the - * tracker. - */ - void tryNowUIShown(@FeatureType int featureType); -} \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinator.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinator.java deleted file mode 100644 index 460219f4..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinator.java +++ /dev/null
@@ -1,10 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.list; - -/** - * The top level coordinator for the video tutorials list UI. - */ -public interface TutorialListCoordinator {} \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java deleted file mode 100644 index 0812c8f..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetrics.java +++ /dev/null
@@ -1,121 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.metrics; - -import androidx.annotation.IntDef; - -import org.chromium.base.metrics.RecordHistogram; -import org.chromium.chrome.browser.video_tutorials.FeatureType; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Responsible for collecting metrics associated with video tutorials. - */ -public class VideoTutorialMetrics { - // These values are persisted to logs. Entries should not be renumbered and numeric values - // should never be reused. Must be kept in sync with VideoTutorials.WatchState in enums.xml. - @IntDef({WatchState.STARTED, WatchState.COMPLETED, WatchState.PAUSED, WatchState.RESUMED, - WatchState.WATCHED}) - @Retention(RetentionPolicy.SOURCE) - public @interface WatchState { - int STARTED = 0; - int COMPLETED = 1; - int PAUSED = 2; - int RESUMED = 3; - int WATCHED = 4; - int NUM_ENTRIES = 5; - } - - // These values are persisted to logs. Entries should not be renumbered and numeric values - // should never be reused. Must be kept in sync with VideoTutorials.UserAction in enums.xml. - @IntDef({UserAction.CHANGE_LANGUAGE, UserAction.WATCH_NEXT_VIDEO, UserAction.TRY_NOW, - UserAction.SHARE, UserAction.CLOSE, UserAction.BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER, - UserAction.OPEN_SHARED_VIDEO, UserAction.INVALID_SHARE_URL, UserAction.IPH_NTP_SHOWN, - UserAction.IPH_NTP_CLICKED, UserAction.IPH_NTP_DISMISSED, UserAction.PLAYED_FROM_RECAP}) - @Retention(RetentionPolicy.SOURCE) - public @interface UserAction { - int CHANGE_LANGUAGE = 0; - int WATCH_NEXT_VIDEO = 1; - int TRY_NOW = 2; - int SHARE = 3; - int CLOSE = 4; - int BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER = 5; - int OPEN_SHARED_VIDEO = 6; - int INVALID_SHARE_URL = 7; - int IPH_NTP_SHOWN = 8; - int IPH_NTP_CLICKED = 9; - int IPH_NTP_DISMISSED = 10; - int PLAYED_FROM_RECAP = 11; - int NUM_ENTRIES = 12; - } - - // These values are persisted to logs. Entries should not be renumbered and numeric values - // should never be reused. Must be kept in sync with VideoTutorials.LanguagePickerAction in - // enums.xml. - @IntDef({LanguagePickerAction.BACK_PRESS, LanguagePickerAction.CLOSE, - LanguagePickerAction.WATCH}) - @Retention(RetentionPolicy.SOURCE) - public @interface LanguagePickerAction { - int BACK_PRESS = 0; - int CLOSE = 1; - int WATCH = 2; - int NUM_ENTRIES = 3; - } - - /** Called to record various user actions on the video player. */ - public static void recordUserAction(@FeatureType int feature, @UserAction int action) { - String histogramSuffix = histogramSuffixFromFeatureType(feature); - RecordHistogram.recordEnumeratedHistogram( - "VideoTutorials." + histogramSuffix + ".Player.UserAction", action, - UserAction.NUM_ENTRIES); - } - - public static void recordVideoLoadTimeLatency(long videoLoadTime) { - RecordHistogram.recordMediumTimesHistogram( - "VideoTutorials.Player.LoadTimeLatency", videoLoadTime); - } - - public static void recordWatchStateUpdate(@FeatureType int feature, @WatchState int state) { - String histogramSuffix = histogramSuffixFromFeatureType(feature); - RecordHistogram.recordEnumeratedHistogram( - "VideoTutorials." + histogramSuffix + ".Player.Progress", state, - WatchState.NUM_ENTRIES); - } - - /** Called to record various user actions on the language picker. */ - public static void recordLanguagePickerAction(@LanguagePickerAction int action) { - RecordHistogram.recordEnumeratedHistogram( - "VideoTutorials.LanguagePicker.Action", action, LanguagePickerAction.NUM_ENTRIES); - } - - /** - * Called when the user selects a language from the list of available languages. The position of - * the language in the list will be recorded. - * @param position The position of the language in the list. - */ - public static void recordLanguageSelected(int position) { - RecordHistogram.recordLinearCountHistogram( - "VideoTutorials.LanguagePicker.LanguageSelected", position, 0, 20, 21); - } - - private static String histogramSuffixFromFeatureType(@FeatureType int feature) { - switch (feature) { - case FeatureType.CHROME_INTRO: - return "ChromeIntro"; - case FeatureType.DOWNLOAD: - return "Download"; - case FeatureType.SEARCH: - return "Search"; - case FeatureType.VOICE_SEARCH: - return "VoiceSearch"; - case FeatureType.SUMMARY: - return "Summary"; - default: - return "Unknown"; - } - } -}
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinator.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinator.java deleted file mode 100644 index 282962e..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinator.java +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.player; - -import android.view.View; - -import org.chromium.chrome.browser.video_tutorials.Tutorial; - -/** - * The top level coordinator for the video player. - */ -public interface VideoPlayerCoordinator { - /** - * Entry point for playing a video tutorial. - */ - void playVideoTutorial(Tutorial tutorial); - - /** @return The Android {@link View} representing this widget. */ - View getView(); - - /** To be called when the back button is pressed. */ - boolean onBackPressed(); - - /** Tears down this coordinator. */ - void destroy(); -}
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java deleted file mode 100644 index 6b37014..0000000 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java +++ /dev/null
@@ -1,120 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.test; - -import org.chromium.base.Callback; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.Language; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** A video tutorial service implementation for tests. */ -public class TestVideoTutorialService implements VideoTutorialService { - public static final Language HINDI = new Language("hi", "hindi", "हिंदी"); - public static final Language TAMIL = new Language("ta", "Tamil", "தமிழ்"); - public static final Language ENGLISH = new Language("en", "English", "English"); - - private final List<Tutorial> mTutorials = new ArrayList<>(); - private final List<String> mLanguages = new ArrayList<>(); - private String mPreferredLocale; - - public TestVideoTutorialService() { - initializeLanguages(); - mPreferredLocale = HINDI.locale; - initializeTutorialList(); - } - - @Override - public void getTutorials(Callback<List<Tutorial>> callback) { - callback.onResult(mTutorials); - } - - @Override - public void getTutorial(int featureType, Callback<Tutorial> callback) { - if (featureType == FeatureType.SUMMARY) { - Tutorial summary = new Tutorial(FeatureType.SUMMARY, "Videos on how to use chrome", - "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.mp4", - "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", - "https://www.gstatic.com/chrome/video-tutorials/gif/sample_anim.gif", - "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", - "caption url", "share url", 25); - callback.onResult(summary); - return; - } - - for (Tutorial tutorial : mTutorials) { - if (tutorial.featureType == featureType) callback.onResult(tutorial); - } - } - - @Override - public List<String> getSupportedLanguages() { - return mLanguages; - } - - @Override - public List<String> getAvailableLanguagesForTutorial(int feature) { - return mLanguages; - } - - @Override - public String getPreferredLocale() { - return mPreferredLocale; - } - - @Override - public void setPreferredLocale(String locale) { - mPreferredLocale = locale; - } - - public List<String> getTestLanguages() { - return mLanguages; - } - - public List<Tutorial> getTestTutorials() { - return mTutorials; - } - - private void initializeTutorialList() { - mTutorials.add(new Tutorial(FeatureType.CHROME_INTRO, "Introduction to chrome", - "https://www.gstatic.com/chrome/video-tutorials/webm/1_Search_english.mp4", - "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", - "https://www.gstatic.com/chrome/video-tutorials/gif/sample_anim.gif", - "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", - "caption url", "share url", 25)); - - mTutorials.add(new Tutorial(FeatureType.DOWNLOAD, - "How to use Google Chrome's download functionality", - "https://www.gstatic.com/chrome/video-tutorials/webm/1_Search_english.mp4", - "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", - "https://www.gstatic.com/chrome/video-tutorials/gif/sample_anim.gif", - "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", - "caption url", "share url", 35)); - - mTutorials.add(new Tutorial(FeatureType.SEARCH, - "How to efficiently search with Google Chrome", - "https://www.gstatic.com/chrome/video-tutorials/webm/1_Search_english.mp4", - "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", - "https://www.gstatic.com/chrome/video-tutorials/gif/sample_anim.gif", - "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png", - "caption url", "share url", 335)); - } - - private void initializeLanguages() { - mLanguages.add("hi"); - mLanguages.add("ta"); - mLanguages.add("en"); - } - - /** Initialized to a set of test languages. */ - public void initializeTestLanguages(String[] languages) { - mLanguages.clear(); - mLanguages.addAll(Arrays.asList(languages)); - } -}
diff --git a/chrome/browser/video_tutorials/internal/BUILD.gn b/chrome/browser/video_tutorials/internal/BUILD.gn deleted file mode 100644 index 64e3f31..0000000 --- a/chrome/browser/video_tutorials/internal/BUILD.gn +++ /dev/null
@@ -1,232 +0,0 @@ -# Copyright 2020 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -if (is_android) { - import("//build/config/android/config.gni") - import("//build/config/android/rules.gni") -} - -source_set("internal") { - sources = [ - "config.cc", - "config.h", - "proto_conversions.cc", - "proto_conversions.h", - "store.h", - "tutorial_fetcher.cc", - "tutorial_fetcher.h", - "tutorial_group.cc", - "tutorial_group.h", - "tutorial_manager.h", - "tutorial_manager_impl.cc", - "tutorial_manager_impl.h", - "tutorial_service_impl.cc", - "tutorial_service_impl.h", - "tutorial_store.cc", - "tutorial_store.h", - ] - - public_deps = [ "//components/image_fetcher/core" ] - - deps = [ - "//base", - "//chrome/browser/video_tutorials:public", - "//chrome/browser/video_tutorials/proto", - "//components/language/core/browser:browser", - "//components/leveldb_proto", - "//content/public/browser", - ] - - if (is_android) { - sources += [ - "android/tutorial_conversion_bridge.cc", - "android/tutorial_conversion_bridge.h", - "android/video_tutorial_service_bridge.cc", - "android/video_tutorial_service_bridge.h", - ] - - deps += [ ":jni_headers" ] - } -} - -if (is_android) { - android_library("java") { - visibility = [ - ":*", - "//chrome/android:chrome_all_java", - ] - - sources = [ - "android/java/src/org/chromium/chrome/browser/video_tutorials/PlaybackStateObserver.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialServiceFactory.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialUtils.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/iph/TryNowTrackerImpl.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHProperties.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHView.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguageItemProperties.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguageItemViewHolder.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerCoordinator.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerMediator.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerProperties.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerView.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialCardProperties.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialCardViewBinder.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorImpl.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinatorImpl.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerURLBuilder.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerView.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinder.java", - ] - - deps = [ - ":java_resources", - "//base:base_java", - "//base:jni_java", - "//build/android:build_java", - "//chrome/browser/flags:java", - "//chrome/browser/profiles/android:java", - "//chrome/browser/video_tutorials:java", - "//components/browser_ui/widget/android:java", - "//components/embedder_support/android:content_view_java", - "//components/embedder_support/android:web_contents_delegate_java", - "//components/image_fetcher:java", - "//components/thin_webview:factory_java", - "//components/thin_webview:java", - "//content/public/android:content_java", - "//services/media_session/public/cpp/android:media_session_java", - "//third_party/androidx:androidx_annotation_annotation_java", - "//third_party/androidx:androidx_core_core_java", - "//third_party/androidx:androidx_recyclerview_recyclerview_java", - "//third_party/gif_player:gif_player_java", - "//ui/android:ui_java", - ] - - resources_package = "org.chromium.chrome.browser.video_tutorials" - annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ] - } - - android_resources("java_resources") { - sources = [ - "android/java/res/drawable/circular_media_button_background.xml", - "android/java/res/layout/language_card.xml", - "android/java/res/layout/language_picker.xml", - "android/java/res/layout/video_player_controls.xml", - "android/java/res/layout/video_player_loading.xml", - "android/java/res/layout/video_tutorial_large_card.xml", - ] - - deps = [ - "//chrome/android:chrome_app_java_resources", - "//chrome/browser/ui/android/strings:ui_strings_grd", - "//chrome/browser/video_tutorials:java_resources", - "//components/browser_ui/widget/android:java_resources", - "//ui/android:ui_java_resources", - ] - } - - generate_jni("jni_headers") { - visibility = [ - ":*", - "//chrome/browser", - ] - - sources = [ - "android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialServiceFactory.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java", - ] - } - - robolectric_library("junit") { - resources_package = "org.chromium.chrome.browser.video_tutorials" - sources = [ - "android/java/src/org/chromium/chrome/browser/video_tutorials/PlaybackStateObserverUnitTest.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerMediatorUnitTest.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetricsUnitTest.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediatorUnitTest.java", - ] - - deps = [ - ":java", - "//base:base_java", - "//base:base_junit_test_support", - "//chrome/browser/video_tutorials:java", - "//chrome/browser/video_tutorials:test_support_java", - "//content/public/android:content_java", - "//services/media_session/public/cpp/android:media_session_java", - "//third_party/hamcrest:hamcrest_core_java", - "//third_party/junit", - "//third_party/mockito:mockito_java", - "//ui/android:ui_java", - ] - } - - android_library("unit_device_javatests") { - testonly = true - resources_package = "org.chromium.chrome.browser.video_tutorials" - - sources = [ - "android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerTest.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorTest.java", - "android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinderTest.java", - ] - deps = [ - ":java", - ":java_resources", - "//base:base_java", - "//base:base_java_test_support", - "//chrome/browser/flags:java", - "//chrome/browser/video_tutorials:java", - "//chrome/browser/video_tutorials:test_support_java", - "//chrome/test/android:chrome_java_unit_test_support", - "//components/thin_webview:java", - "//content/public/test/android:content_java_test_support", - "//third_party/android_deps:espresso_java", - "//third_party/androidx:androidx_recyclerview_recyclerview_java", - "//third_party/androidx:androidx_test_monitor_java", - "//third_party/androidx:androidx_test_runner_java", - "//third_party/gif_player:gif_player_java", - "//third_party/hamcrest:hamcrest_core_java", - "//third_party/junit", - "//third_party/mockito:mockito_java", - "//ui/android:ui_java", - "//ui/android:ui_java_test_support", - ] - } -} - -source_set("unit_tests") { - testonly = true - - sources = [ - "config_unittest.cc", - "proto_conversions_unittest.cc", - "tutorial_fetcher_unittest.cc", - "tutorial_group_unittest.cc", - "tutorial_manager_impl_unittest.cc", - "tutorial_store_unittest.cc", - ] - - deps = [ - ":internal", - "//base", - "//base/test:test_support", - "//chrome/browser/video_tutorials:public", - "//chrome/browser/video_tutorials/proto", - "//chrome/browser/video_tutorials/test:test_lib", - "//components/leveldb_proto", - "//components/leveldb_proto:test_support", - "//components/prefs:test_support", - "//services/network:test_support", - "//testing/gmock", - "//testing/gtest", - ] -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/res/drawable/circular_media_button_background.xml b/chrome/browser/video_tutorials/internal/android/java/res/drawable/circular_media_button_background.xml deleted file mode 100644 index b992fe7..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/res/drawable/circular_media_button_background.xml +++ /dev/null
@@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2020 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > - <item> - <shape - android:shape="oval"> - <solid android:color="@android:color/white" /> - <size android:width="48dp" - android:height="48dp" /> - </shape> - </item> -</layer-list> \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/internal/android/java/res/layout/language_card.xml b/chrome/browser/video_tutorials/internal/android/java/res/layout/language_card.xml deleted file mode 100644 index 6bae7b5..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/res/layout/language_card.xml +++ /dev/null
@@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2020 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:paddingStart="@dimen/promo_compact_padding" - android:paddingEnd="@dimen/promo_compact_padding" > - - <org.chromium.components.browser_ui.widget.RadioButtonWithDescription - android:id="@+id/language_radio_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - -</LinearLayout> \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/internal/android/java/res/layout/language_picker.xml b/chrome/browser/video_tutorials/internal/android/java/res/layout/language_picker.xml deleted file mode 100644 index dde7775..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/res/layout/language_picker.xml +++ /dev/null
@@ -1,63 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2020 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/language_picker" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@macro/default_bg_color" - android:paddingTop="12dp" > - - <org.chromium.ui.widget.ChromeImageButton - android:id="@+id/close_button" - android:layout_height="48dp" - android:layout_width="48dp" - android:layout_alignParentEnd="true" - android:background="?attr/selectableItemBackground" - android:contentDescription="@string/close" - android:scaleType="center" - android:src="@drawable/btn_close" - app:tint="@color/default_icon_color_tint_list" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:layout_centerHorizontal="true" - android:layout_centerVertical="true" - > - <TextView - android:id="@+id/title_view" - android:layout_weight="0" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="36dp" - android:layout_gravity="center_horizontal" - android:text="@string/video_tutorials_language_picker_title" - android:textAppearance="@style/TextAppearance.Headline.Primary" /> - - <androidx.recyclerview.widget.RecyclerView - android:id="@+id/recycler_view" - android:layout_weight="1" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - - <org.chromium.ui.widget.ButtonCompat - android:id="@+id/watch" - android:layout_weight="0" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginTop="36dp" - android:text="@string/video_tutorials_watch" - style="@style/FilledButton" /> - - </LinearLayout> - -</RelativeLayout>
diff --git a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml b/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml deleted file mode 100644 index 09b6d374..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_controls.xml +++ /dev/null
@@ -1,108 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2020 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/player_root" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@android:color/transparent"> - - <org.chromium.ui.widget.ChromeImageButton - android:id="@+id/close_button" - android:layout_height="48dp" - android:layout_width="48dp" - android:layout_alignParentEnd="true" - android:background="?attr/selectableItemBackground" - android:contentDescription="@string/close" - android:scaleType="center" - android:src="@drawable/btn_close_white" /> - - <org.chromium.ui.widget.ChromeImageButton - android:id="@+id/share_button" - android:layout_height="48dp" - android:layout_width="48dp" - android:layout_toStartOf="@id/close_button" - android:background="?attr/selectableItemBackground" - android:contentDescription="@string/share" - android:scaleType="center" - android:src="@drawable/ic_share_white_24dp" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" > - - <Space - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="0.36" /> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="0.64" - android:orientation="vertical" > - - <org.chromium.ui.widget.ChromeImageButton - android:id="@+id/play_button" - android:elevation="2dp" - android:clickable="false" - android:layout_gravity="center_horizontal" - style="@style/LargeMediaPlayButton" /> - </LinearLayout> - </LinearLayout> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" > - <Space - android:id="@+id/top_half" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="0.5" /> - - <LinearLayout - android:id="@+id/bottom_half" - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="0.5" - android:paddingTop="40dp" - android:orientation="vertical"> - - <org.chromium.ui.widget.ButtonCompat - android:id="@+id/try_now" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginTop="2dp" - android:layout_marginBottom="20dp" - android:text="@string/video_tutorials_try_now" - style="@style/FilledButton.Flat" /> - - <TextView - android:id="@+id/watch_next" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:layout_marginBottom="20dp" - android:text="@string/video_tutorials_watch_next_video" - android:textAppearance="@style/TextAppearance.Button.Text.Blue.Dark" /> - - <TextView - android:id="@+id/change_language" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:textAppearance="@style/TextAppearance.Button.Text.Blue.Dark" - android:text="@string/change_chrome_lang" /> - </LinearLayout> - - </LinearLayout> - -</RelativeLayout>
diff --git a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_loading.xml b/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_loading.xml deleted file mode 100644 index 51fd8b9d..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_player_loading.xml +++ /dev/null
@@ -1,34 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2020 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/loading_root" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@android:color/background_dark"> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_above="@id/progress_bar" - android:layout_centerHorizontal="true" - android:textAppearance="@style/TextAppearance.TextMedium.Primary.Baseline.Light" - android:text="@string/video_tutorials_loading"/> - - <ProgressBar - android:id="@+id/progress_bar" - android:layout_width="match_parent" - android:layout_height="10dp" - android:layout_marginTop="20dp" - android:layout_marginStart="60dp" - android:layout_marginEnd="60dp" - android:layout_centerVertical="true" - android:indeterminate="true" - style="?android:attr/progressBarStyleHorizontal" /> - -</RelativeLayout>
diff --git a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_tutorial_large_card.xml b/chrome/browser/video_tutorials/internal/android/java/res/layout/video_tutorial_large_card.xml deleted file mode 100644 index e10b86d..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/res/layout/video_tutorial_large_card.xml +++ /dev/null
@@ -1,86 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -Copyright 2020 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<org.chromium.components.browser_ui.widget.MaterialCardViewNoShadow - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:clickable="true" - android:focusable="true" - style="@style/MaterialCardStyle"> - - <androidx.gridlayout.widget.GridLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - app:columnCount="1" - app:rowCount="2"> - - <org.chromium.components.browser_ui.widget.async_image.AsyncImageView - android:id="@+id/thumbnail" - android:layout_width="match_parent" - android:layout_height="200dp" - android:layout_marginTop="1dp" - android:layout_marginStart="1dp" - android:layout_marginEnd="1dp" - android:scaleType="centerCrop" - android:adjustViewBounds="true" - android:importantForAccessibility="no" - app:unavailableSrc="@color/image_loading_color" - app:waitingSrc="@color/image_loading_color" - app:layout_column="0" - app:layout_row="0" - app:layout_gravity="center" - app:cornerRadiusTopStart="16dp" - app:cornerRadiusTopEnd="16dp" - app:roundedfillColor="@color/modern_grey_300"/> - - <org.chromium.ui.widget.ChromeImageButton - android:id="@+id/action_button" - android:layout_width="60dp" - android:layout_height="60dp" - android:src="@drawable/ic_play_arrow_white_36dp" - android:tint="@color/modern_grey_800" - android:contentDescription="@string/accessibility_play_video" - app:layout_column="0" - app:layout_row="0" - app:layout_gravity="center" - android:elevation="2dp" - android:clickable="false" - android:background="@drawable/circular_media_button_background" /> - - <TextView - android:id="@+id/video_length" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginStart="11dp" - android:layout_marginBottom="11dp" - android:background="@color/modern_grey_900" - android:paddingStart="4dp" - android:paddingEnd="4dp" - app:layout_column="0" - app:layout_row="0" - app:layout_gravity="bottom" - android:importantForAccessibility="no" - android:textAppearance="@style/TextAppearance.TextSmall.Primary.Baseline.Light" /> - - <TextView - android:id="@+id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginStart="12dp" - android:layout_marginEnd="12dp" - android:layout_marginTop="14dp" - android:layout_marginBottom="14dp" - android:maxLines="1" - android:ellipsize="end" - app:layout_column="0" - app:layout_row="1" - android:textAppearance="@style/TextAppearance.TextLarge.Primary" /> - - </androidx.gridlayout.widget.GridLayout> -</org.chromium.components.browser_ui.widget.MaterialCardViewNoShadow>
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/PlaybackStateObserver.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/PlaybackStateObserver.java deleted file mode 100644 index 3d08191c..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/PlaybackStateObserver.java +++ /dev/null
@@ -1,185 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials; - -import android.os.SystemClock; - -import androidx.annotation.VisibleForTesting; - -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo.State; -import org.chromium.content_public.browser.MediaSession; -import org.chromium.content_public.browser.MediaSessionObserver; -import org.chromium.services.media_session.MediaPosition; - -/** - * Responsible for observing a media session and notifying the observer about play/pause/end media - * events. - */ -public class PlaybackStateObserver extends MediaSessionObserver { - /** - * A ratio used for collecting metrics used to determine whether a video was sufficiently - * watched by the user. - */ - private static final float WATCH_COMPLETION_RATIO_THRESHOLD = 0.5f; - - /** Contains playback info about currently playing media. */ - public static class WatchStateInfo { - /** Contains various states during the media playback. */ - public enum State { - INITIAL, - PLAYING, - PAUSED, - ENDED, - ERROR, - } - - /** The current state. */ - public State state = State.INITIAL; - - /** The duration of the video. */ - public long videoLength; - - /** The current position of the video. */ - public long currentPosition; - - /** - * Whether the video has been watched up to a certain point so that it can be considered as - * completed. - */ - public boolean videoWatched() { - return currentPosition > videoLength * WATCH_COMPLETION_RATIO_THRESHOLD; - } - } - - /** - * Interface to be notified of playback state updates. - */ - public interface Observer { - /** Called when the player has started playing or resumed. */ - void onPlay(); - - /** Called when the player has been paused. */ - void onPause(); - - /** Called when the player has completed playing the video. */ - void onEnded(); - - /** Called when an error has occurred. */ - void onError(); - } - - private static Long sCurrentSystemTimeForTesting; - private final Supplier<Observer> mObserver; - private WatchStateInfo mWatchStateInfo = new WatchStateInfo(); - private MediaPosition mLastPosition; - private boolean mIsControllable; - private boolean mIsSuspended; - - /** Constructor. */ - public PlaybackStateObserver(MediaSession mediaSession, Supplier<Observer> observer) { - super(mediaSession); - mObserver = observer; - } - - /** - * Called to get the current media playback info, such as duration, current progress, playback - * state etc. - * @return The current watch state info. - */ - public WatchStateInfo getWatchStateInfo() { - return mWatchStateInfo; - } - - /** Reset internal state. */ - public void reset() { - mLastPosition = null; - mIsControllable = false; - mIsSuspended = false; - mWatchStateInfo = new WatchStateInfo(); - } - - @Override - public void mediaSessionPositionChanged(MediaPosition position) { - if (position != null) { - mWatchStateInfo.videoLength = position.getDuration(); - } - - updateState(position); - mWatchStateInfo.currentPosition = - computeCurrentPosition(position == null ? mLastPosition : position); - mLastPosition = position; - } - - @Override - public void mediaSessionStateChanged(boolean isControllable, boolean isSuspended) { - mIsControllable = isControllable; - mIsSuspended = isSuspended; - updateState(mLastPosition); - } - - private void updateState(MediaPosition newPosition) { - State nextState = mWatchStateInfo.state; - if (mIsControllable) { - nextState = mIsSuspended ? State.PAUSED : State.PLAYING; - } else if (newPosition == null) { - // TODO(shaktisahu): Determine error state. - if (mLastPosition == null) { - nextState = State.INITIAL; - } else if (mLastPosition.getDuration() == computeCurrentPosition(mLastPosition)) { - nextState = State.ENDED; - } - } - - updateObservers(nextState); - } - - private void updateObservers(State nextState) { - if (nextState == mWatchStateInfo.state) return; - - mWatchStateInfo.state = nextState; - switch (nextState) { - case INITIAL: - break; - case PLAYING: - mObserver.get().onPlay(); - break; - case PAUSED: - mObserver.get().onPause(); - break; - case ENDED: - mObserver.get().onEnded(); - break; - case ERROR: - mObserver.get().onError(); - break; - default: - assert false : "Unknown media playback state"; - } - } - - private static long computeCurrentPosition(MediaPosition mediaPosition) { - if (mediaPosition == null) return 0; - - long elapsedTime = getCurrentSystemTime() - mediaPosition.getLastUpdatedTime(); - long updatedPosition = (long) (mediaPosition.getPosition() - + (elapsedTime * mediaPosition.getPlaybackRate())); - updatedPosition = Math.min(updatedPosition, mediaPosition.getDuration()); - if (mediaPosition.getDuration() - updatedPosition < 100) { - updatedPosition = mediaPosition.getDuration(); - } - return updatedPosition; - } - - private static long getCurrentSystemTime() { - if (sCurrentSystemTimeForTesting != null) return sCurrentSystemTimeForTesting; - return SystemClock.elapsedRealtime(); - } - - @VisibleForTesting - protected static void setCurrentSystemTimeForTesting(Long currentTimeForTesting) { - sCurrentSystemTimeForTesting = currentTimeForTesting; - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/PlaybackStateObserverUnitTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/PlaybackStateObserverUnitTest.java deleted file mode 100644 index 9f8d0d2..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/PlaybackStateObserverUnitTest.java +++ /dev/null
@@ -1,114 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials; - -import static org.junit.Assert.assertEquals; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.metrics.UmaRecorderHolder; -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo.State; -import org.chromium.content_public.browser.MediaSession; -import org.chromium.services.media_session.MediaPosition; - -/** - * Tests for {@link PlaybackStateObserver}. - */ -@RunWith(BaseRobolectricTestRunner.class) -public class PlaybackStateObserverUnitTest { - private static final long DURATION_MS = 10000L; - - @Mock - private MediaSession mMediaSession; - @Mock - private PlaybackStateObserver.Observer mObserver; - - private PlaybackStateObserver mPlaybackStateObserver; - - @Before - public void setUp() { - UmaRecorderHolder.resetForTesting(); - MockitoAnnotations.initMocks(this); - - mPlaybackStateObserver = - new PlaybackStateObserver(mMediaSession, () -> { return mObserver; }); - } - - @Test - public void testInitialState() { - WatchStateInfo info = mPlaybackStateObserver.getWatchStateInfo(); - assertEquals(State.INITIAL, info.state); - } - - @Test - public void testPlaybackStarted() { - MediaPosition position = new MediaPosition(DURATION_MS, 0, 1.f, 2); - mPlaybackStateObserver.mediaSessionStateChanged(true, false); - mPlaybackStateObserver.mediaSessionPositionChanged(position); - WatchStateInfo info = mPlaybackStateObserver.getWatchStateInfo(); - assertEquals(State.PLAYING, info.state); - Mockito.verify(mObserver).onPlay(); - } - - @Test - public void testPlaybackPaused() { - MediaPosition position = new MediaPosition(DURATION_MS, 100, 1.f, 2); - mPlaybackStateObserver.mediaSessionStateChanged(true, true); - mPlaybackStateObserver.mediaSessionPositionChanged(position); - WatchStateInfo info = mPlaybackStateObserver.getWatchStateInfo(); - assertEquals(State.PAUSED, info.state); - Mockito.verify(mObserver).onPause(); - } - - @Test - public void testPlaybackComplete() { - mPlaybackStateObserver.reset(); - - long initialSystemTime = 30000L; - PlaybackStateObserver.setCurrentSystemTimeForTesting(initialSystemTime); - MediaPosition position = new MediaPosition(DURATION_MS, 0, 1.f, initialSystemTime); - mPlaybackStateObserver.mediaSessionStateChanged(true, false); - mPlaybackStateObserver.mediaSessionPositionChanged(position); - verifyWatchState(State.PLAYING, false, DURATION_MS, 0); - Mockito.verify(mObserver).onPlay(); - - // Slightly advance the playback to 100ms. - PlaybackStateObserver.setCurrentSystemTimeForTesting(initialSystemTime + 100); - MediaPosition position2 = new MediaPosition(DURATION_MS, 100, 1.f, initialSystemTime + 100); - mPlaybackStateObserver.mediaSessionStateChanged(true, false); - mPlaybackStateObserver.mediaSessionPositionChanged(position2); - Mockito.verify(mObserver).onPlay(); - - // Advance playback to almost completion with 100ms remaining. - PlaybackStateObserver.setCurrentSystemTimeForTesting(initialSystemTime + DURATION_MS - 100); - MediaPosition position3 = new MediaPosition( - DURATION_MS, DURATION_MS - 100, 1.f, initialSystemTime + DURATION_MS - 100); - mPlaybackStateObserver.mediaSessionStateChanged(true, false); - mPlaybackStateObserver.mediaSessionPositionChanged(position3); - Mockito.verify(mObserver).onPlay(); - - // Complete the video. - PlaybackStateObserver.setCurrentSystemTimeForTesting(initialSystemTime + DURATION_MS); - mPlaybackStateObserver.mediaSessionStateChanged(false, false); - mPlaybackStateObserver.mediaSessionPositionChanged(null); - verifyWatchState(State.ENDED, true, DURATION_MS, DURATION_MS); - Mockito.verify(mObserver).onEnded(); - } - - private void verifyWatchState( - State state, boolean videoWatched, long duration, long currentPosition) { - assertEquals(state, mPlaybackStateObserver.getWatchStateInfo().state); - assertEquals(duration, mPlaybackStateObserver.getWatchStateInfo().videoLength); - assertEquals(currentPosition, mPlaybackStateObserver.getWatchStateInfo().currentPosition); - assertEquals(videoWatched, mPlaybackStateObserver.getWatchStateInfo().videoWatched()); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialServiceFactory.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialServiceFactory.java deleted file mode 100644 index ecc1b6b..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialServiceFactory.java +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials; - -import android.content.Context; -import android.util.Pair; -import android.view.ViewGroup; -import android.view.ViewStub; - -import org.chromium.base.Callback; -import org.chromium.base.annotations.NativeMethods; -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.chrome.browser.video_tutorials.iph.TryNowTrackerImpl; -import org.chromium.chrome.browser.video_tutorials.iph.VideoIPHCoordinator; -import org.chromium.chrome.browser.video_tutorials.iph.VideoIPHCoordinatorImpl; -import org.chromium.chrome.browser.video_tutorials.iph.VideoTutorialTryNowTracker; -import org.chromium.chrome.browser.video_tutorials.list.TutorialListCoordinator; -import org.chromium.chrome.browser.video_tutorials.list.TutorialListCoordinatorImpl; -import org.chromium.chrome.browser.video_tutorials.player.VideoPlayerCoordinator; -import org.chromium.chrome.browser.video_tutorials.player.VideoPlayerCoordinatorImpl; -import org.chromium.components.embedder_support.view.ContentView; -import org.chromium.components.image_fetcher.ImageFetcher; -import org.chromium.content_public.browser.WebContents; -import org.chromium.ui.base.IntentRequestTracker; - -/** - * Basic factory that creates and returns an {@link VideoTutorialService} that is attached - * natively to the given {@link Profile}. - */ -public class VideoTutorialServiceFactory { - private static VideoTutorialService sVideoTutorialServiceForTesting; - - /** - * Used to get access to the video tutorials backend. - * @return An {@link VideoTutorialService} instance. - */ - public static VideoTutorialService getForProfile(Profile profile) { - if (sVideoTutorialServiceForTesting != null) return sVideoTutorialServiceForTesting; - return VideoTutorialServiceFactoryJni.get().getForProfile(profile); - } - - /** See {@link VideoIPHCoordinator} constructor.*/ - public static VideoIPHCoordinator createVideoIPHCoordinator(ViewStub viewStub, - ImageFetcher imageFetcher, Callback<Tutorial> onClickListener, - Callback<Tutorial> onDismissListener) { - return new VideoIPHCoordinatorImpl( - viewStub, imageFetcher, onClickListener, onDismissListener); - } - - /** See {@link VideoPlayerCoordinator}.*/ - public static VideoPlayerCoordinator createVideoPlayerCoordinator(Context context, - VideoTutorialService videoTutorialService, - Supplier<Pair<WebContents, ContentView>> webContentsFactory, - LanguageInfoProvider languageInfoProvider, Callback<Tutorial> tryNowCallback, - Runnable closeCallback, IntentRequestTracker intentRequestTracker) { - return new VideoPlayerCoordinatorImpl(context, videoTutorialService, webContentsFactory, - languageInfoProvider, tryNowCallback, closeCallback, intentRequestTracker); - } - - /** See {@link TutorialListCoordinator}.*/ - public static TutorialListCoordinator createTutorialListCoordinator(ViewGroup mainView, - VideoTutorialService videoTutorialService, ImageFetcher imageFetcher, - Callback<Tutorial> clickCallback) { - return new TutorialListCoordinatorImpl( - mainView, videoTutorialService, imageFetcher, clickCallback); - } - - /** @return The tracker to track Try Now button clicks. */ - public static VideoTutorialTryNowTracker getTryNowTracker() { - return LazyHolder.TRY_NOW_TRACKER; - } - - public static void setVideoTutorialServiceForTesting(VideoTutorialService provider) { - sVideoTutorialServiceForTesting = provider; - } - - private static final class LazyHolder { - private static final VideoTutorialTryNowTracker TRY_NOW_TRACKER = new TryNowTrackerImpl(); - } - - @NativeMethods - interface Natives { - VideoTutorialService getForProfile(Profile profile); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialUtils.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialUtils.java deleted file mode 100644 index fe0c1b47..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/VideoTutorialUtils.java +++ /dev/null
@@ -1,98 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials; - -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; - -import org.chromium.base.Callback; -import org.chromium.base.Log; - -import java.util.List; -import java.util.Locale; - -/** - * Handles various feature utility functions associated with video tutorials UI. - */ -public class VideoTutorialUtils { - private static final String TAG = "VideoTutorialShare"; - - /** - * Creates and launches an Intent that allows sharing a video tutorial. - */ - public static void launchShareIntent(Context context, Tutorial tutorial) { - Intent intent = new Intent(); - intent.setType("video/*"); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setAction(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_TEXT, tutorial.shareUrl); - startShareIntent(context, intent); - } - - private static void startShareIntent(Context context, Intent intent) { - try { - context.startActivity(Intent.createChooser( - intent, context.getString(R.string.share_link_chooser_title))); - } catch (ActivityNotFoundException e) { - Log.e(TAG, "Cannot find activity for sharing"); - } catch (Exception e) { - Log.e(TAG, "Cannot start activity for sharing, exception: " + e); - } - } - - /** - * Converts a duration string in ms to a human-readable form. - * @param videoLengthSeconds The video length in seconds. - * @return The video length in human-readable form. - */ - public static String getVideoLengthString(int videoLengthSeconds) { - int hours = videoLengthSeconds / 3600; - int minutes = (videoLengthSeconds / 60) % 60; - int seconds = videoLengthSeconds % 60; - - if (hours > 0) { - return String.format(Locale.US, "%d:%02d:%02d", hours, minutes, seconds); - } else { - return String.format(Locale.US, "%d:%02d", minutes, seconds); - } - } - - /** - * Finds the next video tutorial to be presented to the user after the user has completed one. - */ - public static void getNextTutorial(VideoTutorialService videoTutorialService, Tutorial tutorial, - Callback<Tutorial> callback) { - videoTutorialService.getTutorials(tutorials -> { - Tutorial nextTutorial = VideoTutorialUtils.getNextTutorial(tutorials, tutorial); - callback.onResult(nextTutorial); - }); - } - - /** @return Whether or not to show the Try Now button on the video player. */ - public static boolean shouldShowTryNow(@FeatureType int featureType) { - switch (featureType) { - case FeatureType.SEARCH: - case FeatureType.VOICE_SEARCH: - return true; - case FeatureType.CHROME_INTRO: - case FeatureType.DOWNLOAD: - default: - return false; - } - } - - private static Tutorial getNextTutorial(List<Tutorial> tutorials, Tutorial currentTutorial) { - int currentIndex = 0; - for (int i = 0; i < tutorials.size(); i++) { - if (tutorials.get(i).featureType == currentTutorial.featureType) { - currentIndex = i; - break; - } - } - - return currentIndex < tutorials.size() - 1 ? tutorials.get(currentIndex + 1) : null; - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java deleted file mode 100644 index eea5f47..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.bridges; - -import androidx.annotation.Nullable; - -import org.chromium.base.annotations.CalledByNative; -import org.chromium.base.annotations.JNINamespace; -import org.chromium.chrome.browser.video_tutorials.Tutorial; - -import java.util.ArrayList; -import java.util.List; - -/** - * Helper class to provide conversion methods between C++ and Java for video tutorials. - */ -@JNINamespace("video_tutorials") -public class TutorialConversionBridge { - @CalledByNative - private static List<Tutorial> createTutorialList() { - return new ArrayList<>(); - } - - @CalledByNative - private static Tutorial createTutorialAndMaybeAddToList(@Nullable List<Tutorial> list, - int featureType, String title, String videoUrl, String posterUrl, String animatedGifUrl, - String thumbnailUrl, String captionUrl, String shareUrl, int videoLength) { - Tutorial tutorial = new Tutorial(featureType, title, videoUrl, posterUrl, animatedGifUrl, - thumbnailUrl, captionUrl, shareUrl, videoLength); - if (list != null) list.add(tutorial); - return tutorial; - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java deleted file mode 100644 index d6f7447..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java +++ /dev/null
@@ -1,98 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.bridges; - -import org.chromium.base.Callback; -import org.chromium.base.annotations.CalledByNative; -import org.chromium.base.annotations.JNINamespace; -import org.chromium.base.annotations.NativeMethods; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; - -import java.util.Arrays; -import java.util.List; - -/** - * Bridge to the native video tutorial service for the given {@link Profile}. - */ -@JNINamespace("video_tutorials") -public class VideoTutorialServiceBridge implements VideoTutorialService { - private long mNativeVideoTutorialServiceBridge; - - @CalledByNative - private static VideoTutorialServiceBridge create(long nativePtr) { - return new VideoTutorialServiceBridge(nativePtr); - } - - private VideoTutorialServiceBridge(long nativePtr) { - mNativeVideoTutorialServiceBridge = nativePtr; - } - - @Override - public void getTutorials(Callback<List<Tutorial>> callback) { - if (mNativeVideoTutorialServiceBridge == 0) return; - VideoTutorialServiceBridgeJni.get().getTutorials( - mNativeVideoTutorialServiceBridge, this, callback); - } - - @Override - public void getTutorial(@FeatureType int feature, Callback<Tutorial> callback) { - if (mNativeVideoTutorialServiceBridge == 0) return; - VideoTutorialServiceBridgeJni.get().getTutorial( - mNativeVideoTutorialServiceBridge, this, feature, callback); - } - - @Override - public List<String> getSupportedLanguages() { - if (mNativeVideoTutorialServiceBridge == 0) return null; - String[] languages = VideoTutorialServiceBridgeJni.get().getSupportedLanguages( - mNativeVideoTutorialServiceBridge, this); - return Arrays.asList(languages); - } - - @Override - public List<String> getAvailableLanguagesForTutorial(@FeatureType int feature) { - if (mNativeVideoTutorialServiceBridge == 0) return null; - String[] languages = VideoTutorialServiceBridgeJni.get().getAvailableLanguagesForTutorial( - mNativeVideoTutorialServiceBridge, this, feature); - return Arrays.asList(languages); - } - - @Override - public String getPreferredLocale() { - if (mNativeVideoTutorialServiceBridge == 0) return null; - return VideoTutorialServiceBridgeJni.get().getPreferredLocale( - mNativeVideoTutorialServiceBridge, this); - } - - @Override - public void setPreferredLocale(String locale) { - if (mNativeVideoTutorialServiceBridge == 0) return; - VideoTutorialServiceBridgeJni.get().setPreferredLocale( - mNativeVideoTutorialServiceBridge, this, locale); - } - - @CalledByNative - private void clearNativePtr() { - mNativeVideoTutorialServiceBridge = 0; - } - - @NativeMethods - interface Natives { - void getTutorials(long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller, - Callback<List<Tutorial>> callback); - void getTutorial(long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller, - int feature, Callback<Tutorial> callback); - String[] getSupportedLanguages( - long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller); - String[] getAvailableLanguagesForTutorial(long nativeVideoTutorialServiceBridge, - VideoTutorialServiceBridge caller, int feature); - String getPreferredLocale( - long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller); - void setPreferredLocale(long nativeVideoTutorialServiceBridge, - VideoTutorialServiceBridge caller, String locale); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/TryNowTrackerImpl.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/TryNowTrackerImpl.java deleted file mode 100644 index 53d862d..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/TryNowTrackerImpl.java +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.iph; - -import org.chromium.chrome.browser.video_tutorials.FeatureType; - -/** - * {@link VideoTutorialTryNowTracker} implementation. - */ -public class TryNowTrackerImpl implements VideoTutorialTryNowTracker { - private @FeatureType int mFeatureType = FeatureType.INVALID; - - @Override - public void recordTryNowButtonClicked(@FeatureType int featureType) { - mFeatureType = featureType; - } - - @Override - public boolean didClickTryNowButton(@FeatureType int featureType) { - return mFeatureType == featureType; - } - - @Override - public void tryNowUIShown(@FeatureType int featureType) { - mFeatureType = FeatureType.INVALID; - } -} \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java deleted file mode 100644 index 9a99db6..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.iph; - -import android.content.Context; -import android.graphics.Bitmap.Config; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.view.ViewStub; - -import org.chromium.base.Callback; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialUtils; -import org.chromium.components.image_fetcher.ImageFetcher; -import org.chromium.ui.modelutil.PropertyModel; -import org.chromium.ui.modelutil.PropertyModelChangeProcessor; - -import jp.tomorrowkey.android.gifplayer.BaseGifDrawable; - -/** - * Creates and shows a video tutorial IPH. Requires a {@link ViewStub} to be passed which will - * inflate when the IPH is shown. - */ -public class VideoIPHCoordinatorImpl implements VideoIPHCoordinator { - private static final String VARIATION_USE_ANIMATED_GIF_URL = "use_animated_gif_url"; - private static final String VARIATION_USE_ANIMATED_GIF_URL_FOR_SUMMARY_CARD = - "use_animated_gif_url_for_summary_card"; - - private final Context mContext; - private final PropertyModel mModel; - private final VideoIPHView mView; - private final ImageFetcher mImageFetcher; - private final Callback<Tutorial> mOnClickListener; - private final Callback<Tutorial> mOnDismissListener; - - /** - * Constructor. - * @param viewStub The view stub which will inflate to show the IPH. - * @param imageFetcher The {@link ImageFetcher} to fetch thumbnail. - * @param onClickListener The on click listener that starts playing IPH. - * @param onDismissListener The listener to be invoked on dismissal. - */ - public VideoIPHCoordinatorImpl(ViewStub viewStub, ImageFetcher imageFetcher, - Callback<Tutorial> onClickListener, Callback<Tutorial> onDismissListener) { - mContext = viewStub.getContext(); - mImageFetcher = imageFetcher; - mOnClickListener = onClickListener; - mOnDismissListener = onDismissListener; - - mModel = new PropertyModel(VideoIPHProperties.ALL_KEYS); - mView = new VideoIPHView(viewStub); - PropertyModelChangeProcessor.create(mModel, mView, VideoIPHView::bind); - } - - @Override - public void showVideoIPH(Tutorial tutorial) { - mModel.set(VideoIPHProperties.VISIBILITY, true); - mModel.set(VideoIPHProperties.DISPLAY_TITLE, tutorial.title); - mModel.set(VideoIPHProperties.VIDEO_LENGTH, - VideoTutorialUtils.getVideoLengthString(tutorial.videoLength)); - mModel.set(VideoIPHProperties.SHOW_VIDEO_LENGTH, tutorial.videoLength != 0); - mModel.set(VideoIPHProperties.CLICK_LISTENER, () -> mOnClickListener.onResult(tutorial)); - mModel.set( - VideoIPHProperties.DISMISS_LISTENER, () -> mOnDismissListener.onResult(tutorial)); - - mModel.set(VideoIPHProperties.THUMBNAIL_PROVIDER, (consumer, widthPx, heightPx) -> { - fetchImage(consumer, widthPx, heightPx, tutorial); - return () -> {}; - }); - } - - @Override - public void hideVideoIPH() { - mModel.set(VideoIPHProperties.VISIBILITY, false); - } - - private void fetchImage( - Callback<Drawable> consumer, int widthPx, int heightPx, Tutorial tutorial) { - boolean isSummaryCard = tutorial.featureType == FeatureType.SUMMARY; - boolean useAnimatedGifUrl = ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( - ChromeFeatureList.VIDEO_TUTORIALS, - isSummaryCard ? VARIATION_USE_ANIMATED_GIF_URL_FOR_SUMMARY_CARD - : VARIATION_USE_ANIMATED_GIF_URL, - !isSummaryCard); - ImageFetcher.Params params = ImageFetcher.Params.create( - useAnimatedGifUrl ? tutorial.animatedGifUrl : tutorial.thumbnailUrl, - ImageFetcher.VIDEO_TUTORIALS_IPH_UMA_CLIENT_NAME, widthPx, heightPx); - if (useAnimatedGifUrl) { - mImageFetcher.fetchGif(params, gifImage -> { - BaseGifDrawable baseGifDrawable = - gifImage == null ? null : new BaseGifDrawable(gifImage, Config.ARGB_8888); - consumer.onResult(baseGifDrawable); - }); - } else { - mImageFetcher.fetchImage(params, bitmap -> { - consumer.onResult(new BitmapDrawable(mContext.getResources(), bitmap)); - }); - } - } -} \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHProperties.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHProperties.java deleted file mode 100644 index a13f197..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHProperties.java +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.iph; - -import org.chromium.components.browser_ui.widget.async_image.AsyncImageView; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; - -/** The properties needed to show the video tutorial IPH. */ -class VideoIPHProperties { - /** Whether or not the IPH should be shown. */ - public static final WritableBooleanPropertyKey VISIBILITY = new WritableBooleanPropertyKey(); - - /** The display title. */ - public static final WritableObjectPropertyKey<String> DISPLAY_TITLE = - new WritableObjectPropertyKey<>(); - - /** The text representing the length of the video. */ - public static final WritableObjectPropertyKey<String> VIDEO_LENGTH = - new WritableObjectPropertyKey<>(); - - /** - * Whether or not to show the video length text. Typically if the video length is zero, the - * view will be hidden, e.g. summary card. - */ - public static final WritableBooleanPropertyKey SHOW_VIDEO_LENGTH = - new WritableBooleanPropertyKey(); - - /** The thumbnail provider to supply thumbnail images. */ - public static final WritableObjectPropertyKey<AsyncImageView.Factory> THUMBNAIL_PROVIDER = - new WritableObjectPropertyKey<>(); - - /** The listener to be invoked when the IPH is clicked. */ - public static final WritableObjectPropertyKey<Runnable> CLICK_LISTENER = - new WritableObjectPropertyKey<>(); - - /** The listener to be invoked when the IPH is dismissed. */ - public static final WritableObjectPropertyKey<Runnable> DISMISS_LISTENER = - new WritableObjectPropertyKey<>(); - - /** All keys associated with the model. */ - public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {VISIBILITY, DISPLAY_TITLE, - VIDEO_LENGTH, SHOW_VIDEO_LENGTH, THUMBNAIL_PROVIDER, CLICK_LISTENER, DISMISS_LISTENER}; -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java deleted file mode 100644 index 0c651da..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java +++ /dev/null
@@ -1,102 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.iph; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import android.app.Activity; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.view.ViewStub; -import android.widget.FrameLayout; - -import androidx.test.espresso.action.ViewActions; -import androidx.test.filters.SmallTest; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.Callback; -import org.chromium.base.FeatureList; -import org.chromium.base.test.BaseActivityTestRule; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.test.TestImageFetcher; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.test.util.BlankUiTestActivity; - -import java.util.HashMap; - -/** - * Tests for {@link LanguagePickerCoordinator}. - */ -@RunWith(ChromeJUnit4ClassRunner.class) -public class VideoIPHTest { - @Rule - public BaseActivityTestRule<BlankUiTestActivity> mActivityTestRule = - new BaseActivityTestRule<>(BlankUiTestActivity.class); - - private Activity mActivity; - private VideoIPHCoordinator mCoordinator; - - @Mock - private Callback<Tutorial> mOnClickListener; - @Mock - private Callback<Tutorial> mOnDismissListener; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mActivityTestRule.launchActivity(null); - mActivity = mActivityTestRule.getActivity(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - FrameLayout parentView = new FrameLayout(mActivity); - mActivity.setContentView(parentView); - ViewStub viewStub = new ViewStub(mActivity); - viewStub.setLayoutResource(R.layout.video_tutorial_iph_card); - parentView.addView(viewStub); - - Bitmap testImage = - BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.btn_close); - TestImageFetcher imageFetcher = new TestImageFetcher(testImage); - mCoordinator = new VideoIPHCoordinatorImpl( - viewStub, imageFetcher, mOnClickListener, mOnDismissListener); - FeatureList.setTestFeatures(new HashMap<String, Boolean>()); - }); - } - - @Test - @SmallTest - public void testShowIPH() { - final Tutorial tutorial = createDummyTutorial(); - TestThreadUtils.runOnUiThreadBlocking(() -> { mCoordinator.showVideoIPH(tutorial); }); - onView(withText(tutorial.title)).check(matches(isDisplayed())); - onView(withText("5:35")).check(matches(isDisplayed())); - onView(withText(tutorial.title)).perform(ViewActions.click()); - Mockito.verify(mOnClickListener).onResult(Mockito.any()); - onView(withId(R.id.close_button)).perform(ViewActions.click()); - Mockito.verify(mOnDismissListener).onResult(Mockito.any()); - } - - private Tutorial createDummyTutorial() { - return new Tutorial(FeatureType.DOWNLOAD, - "How to use Google Chrome's download functionality", - "https://xyz.example.com/xyz.mp4", "https://xyz.example.com/xyz.png", - "https://xyz.example.com/xyz.gif", "https://xyz.example.com/xyz.png", - "https://xyz.example.com/xyz.vtt", "https://xyz.example.com/xyz.mp4", 335); - } - -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHView.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHView.java deleted file mode 100644 index 43ac3c4..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHView.java +++ /dev/null
@@ -1,86 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.iph; - -import android.view.View; -import android.view.ViewStub; -import android.widget.TextView; - -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.components.browser_ui.widget.async_image.AsyncImageView; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel; - -/** - * The View component of the video tutorial IPH. This takes the {@link ViewStub} and inflates it to - * show the UI. - */ -class VideoIPHView { - private final ViewStub mViewStub; - private View mCardView; - - /** Constructor. */ - public VideoIPHView(ViewStub viewStub) { - mViewStub = viewStub; - } - - private void setVisibility(boolean visible) { - if (visible && mCardView == null) mCardView = mViewStub.inflate(); - if (mCardView != null) mCardView.setVisibility(visible ? View.VISIBLE : View.GONE); - } - - private void setTitle(String title) { - TextView view = mCardView.findViewById(R.id.title); - view.setText(title); - } - - /** Called to set the video length text of an IPH. */ - private void setVideoLength(String videoLength) { - TextView view = mCardView.findViewById(R.id.video_length); - view.setText(videoLength); - } - - private void showVideoLength(boolean show) { - TextView view = mCardView.findViewById(R.id.video_length); - view.setVisibility(show ? View.VISIBLE : View.GONE); - } - - private View getThumbnailView() { - return mCardView.findViewById(R.id.thumbnail); - } - - private void setClickListener(Runnable clickListener) { - mCardView.setOnClickListener(v -> clickListener.run()); - } - - private void setDismissListener(Runnable dismissListener) { - View closeButton = mCardView.findViewById(R.id.close_button); - closeButton.setOnClickListener(view -> { - mCardView.setVisibility(View.GONE); - dismissListener.run(); - }); - } - - /** The view binder that propagates events from model to view. */ - public static void bind(PropertyModel model, VideoIPHView view, PropertyKey propertyKey) { - if (propertyKey == VideoIPHProperties.VISIBILITY) { - view.setVisibility(model.get(VideoIPHProperties.VISIBILITY)); - } else if (propertyKey == VideoIPHProperties.DISPLAY_TITLE) { - view.setTitle(model.get(VideoIPHProperties.DISPLAY_TITLE)); - } else if (propertyKey == VideoIPHProperties.VIDEO_LENGTH) { - view.setVideoLength(model.get(VideoIPHProperties.VIDEO_LENGTH)); - } else if (propertyKey == VideoIPHProperties.SHOW_VIDEO_LENGTH) { - view.showVideoLength(model.get(VideoIPHProperties.SHOW_VIDEO_LENGTH)); - } else if (propertyKey == VideoIPHProperties.CLICK_LISTENER) { - view.setClickListener(model.get(VideoIPHProperties.CLICK_LISTENER)); - } else if (propertyKey == VideoIPHProperties.DISMISS_LISTENER) { - view.setDismissListener(model.get(VideoIPHProperties.DISMISS_LISTENER)); - } else if (propertyKey == VideoIPHProperties.THUMBNAIL_PROVIDER) { - AsyncImageView thumbnailView = (AsyncImageView) view.getThumbnailView(); - thumbnailView.setAsyncImageDrawable( - model.get(VideoIPHProperties.THUMBNAIL_PROVIDER), null); - } - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguageItemProperties.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguageItemProperties.java deleted file mode 100644 index 62b5115..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguageItemProperties.java +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.languages; - -import org.chromium.base.Callback; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; - -/** - * The properties associated with the language list items. - */ -class LanguageItemProperties { - /** The view type used by the recycler view to show the language list item. */ - public static final int ITEM_VIEW_TYPE = 1; - - /** The associated locale.*/ - static final WritableObjectPropertyKey<String> LOCALE = new WritableObjectPropertyKey<>(); - - /** The language name. Shown in the system text. */ - static final WritableObjectPropertyKey<String> NAME = new WritableObjectPropertyKey<>(); - - /** The language name in its native text.*/ - static final WritableObjectPropertyKey<String> NATIVE_NAME = new WritableObjectPropertyKey<>(); - - /** Whether this language is currently selected.*/ - static final WritableBooleanPropertyKey IS_SELECTED = new WritableBooleanPropertyKey(); - - /** The callback to be invoked on selecting this language.*/ - static final WritableObjectPropertyKey<Callback<String>> SELECTION_CALLBACK = - new WritableObjectPropertyKey<>(); - - static final PropertyKey[] ALL_KEYS = - new PropertyKey[] {LOCALE, NAME, NATIVE_NAME, IS_SELECTED, SELECTION_CALLBACK}; -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguageItemViewHolder.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguageItemViewHolder.java deleted file mode 100644 index 889153c..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguageItemViewHolder.java +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.languages; - -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.components.browser_ui.widget.RadioButtonWithDescription; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel; - -/** - * The view holder for individual list items. - */ -class LanguageItemViewHolder { - /** Builder method to create the language item view. */ - public static View buildView(ViewGroup parent) { - return LayoutInflater.from(parent.getContext()) - .inflate(R.layout.language_card, parent, false); - } - - /** Binder method to bind the list view with the model properties. */ - public static void bindView(PropertyModel model, View view, PropertyKey propertyKey) { - final RadioButtonWithDescription radioButton = - view.findViewById(R.id.language_radio_button); - if (propertyKey == LanguageItemProperties.NAME) { - radioButton.setPrimaryText(model.get(LanguageItemProperties.NAME)); - } else if (propertyKey == LanguageItemProperties.NATIVE_NAME) { - radioButton.setDescriptionText(model.get(LanguageItemProperties.NATIVE_NAME)); - } else if (propertyKey == LanguageItemProperties.IS_SELECTED) { - radioButton.setChecked(model.get(LanguageItemProperties.IS_SELECTED)); - } else if (propertyKey == LanguageItemProperties.SELECTION_CALLBACK) { - radioButton.setOnCheckedChangeListener(checkedRadioButton -> { - if (!radioButton.isChecked()) return; - model.get(LanguageItemProperties.SELECTION_CALLBACK) - .onResult(model.get(LanguageItemProperties.LOCALE)); - }); - } - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerCoordinator.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerCoordinator.java deleted file mode 100644 index 11b5509..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerCoordinator.java +++ /dev/null
@@ -1,58 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.languages; - -import android.content.Context; -import android.view.View; - -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.LanguageInfoProvider; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.ui.modelutil.MVCListAdapter.ModelList; -import org.chromium.ui.modelutil.PropertyModel; - -/** - * The top level coordinator for the language picker UI. - */ -public class LanguagePickerCoordinator { - private final Context mContext; - private final VideoTutorialService mVideoTutorialService; - private final LanguagePickerMediator mMediator; - private final LanguagePickerView mView; - private final PropertyModel mModel; - private final ModelList mListModel; - - /** - * Constructor. - * @param view The view representing this language picker. - * @param videoTutorialService The video tutorial service backend. - */ - public LanguagePickerCoordinator(View view, VideoTutorialService videoTutorialService, - LanguageInfoProvider languageInfoProvider) { - mContext = view.getContext(); - mVideoTutorialService = videoTutorialService; - mModel = new PropertyModel(LanguagePickerProperties.ALL_KEYS); - mListModel = new ModelList(); - mView = new LanguagePickerView(view, mModel, mListModel); - mMediator = new LanguagePickerMediator( - mContext, mModel, mListModel, videoTutorialService, languageInfoProvider); - } - - /** - * Called to open the language picker UI. - * @param feature The tutorial for which the language options will be shown. - * @param doneCallback The callback to be invoked when the watch button is clicked. - * @param closeCallback The callback to be invoked when the close button is clicked. - */ - public void showLanguagePicker( - @FeatureType int feature, Runnable doneCallback, Runnable closeCallback) { - mMediator.showLanguagePicker(feature, doneCallback, closeCallback); - } - - /** @return A {@link View} representing this coordinator. */ - public View getView() { - return mView.getView(); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerMediator.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerMediator.java deleted file mode 100644 index 0e29c617..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerMediator.java +++ /dev/null
@@ -1,111 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.languages; - -import android.content.Context; -import android.text.TextUtils; - -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.Language; -import org.chromium.chrome.browser.video_tutorials.LanguageInfoProvider; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.LanguagePickerAction; -import org.chromium.ui.modelutil.MVCListAdapter.ListItem; -import org.chromium.ui.modelutil.MVCListAdapter.ModelList; -import org.chromium.ui.modelutil.PropertyModel; - -import java.util.ArrayList; -import java.util.List; - -/** - * The mediator for language selection UI. - */ -public class LanguagePickerMediator { - private final Context mContext; - private final VideoTutorialService mVideoTutorialService; - private final LanguageInfoProvider mLanguageInfoProvider; - private final PropertyModel mModel; - private final ModelList mListModel; - private String mSelectedLocale; - private @FeatureType int mFeature; - - /** - * Constructor. - * @param videoTutorialService The video tutorial service backend. - */ - public LanguagePickerMediator(Context context, PropertyModel model, ModelList listModel, - VideoTutorialService videoTutorialService, LanguageInfoProvider languageInfoProvider) { - mContext = context; - mVideoTutorialService = videoTutorialService; - mLanguageInfoProvider = languageInfoProvider; - mModel = model; - mListModel = listModel; - mSelectedLocale = mVideoTutorialService.getPreferredLocale(); - } - - /** - * See {@link LanguagePickerCoordinator#showLanguagePicker(Runnable, Runnable)}. - */ - public void showLanguagePicker( - @FeatureType int feature, Runnable doneCallback, Runnable closeCallback) { - mFeature = feature; - mModel.set(LanguagePickerProperties.CLOSE_CALLBACK, () -> { - mSelectedLocale = mVideoTutorialService.getPreferredLocale(); - VideoTutorialMetrics.recordLanguagePickerAction(LanguagePickerAction.CLOSE); - closeCallback.run(); - }); - mModel.set(LanguagePickerProperties.WATCH_CALLBACK, () -> { - onLanguageSelectionFinalized(); - doneCallback.run(); - }); - populateList(mVideoTutorialService.getAvailableLanguagesForTutorial(mFeature)); - } - - private void onLanguageSelected(String locale) { - mSelectedLocale = locale; - populateList(mVideoTutorialService.getAvailableLanguagesForTutorial(mFeature)); - } - - private void populateList(List<String> supportedLanguages) { - List<ListItem> listItems = new ArrayList<>(); - boolean hasPreferredLanguage = false; - for (String locale : supportedLanguages) { - Language language = mLanguageInfoProvider.getLanguageInfo(locale); - if (language == null) continue; - - ListItem listItem = new ListItem( - LanguageItemProperties.ITEM_VIEW_TYPE, buildListItemModelFromLocale(language)); - listItems.add(listItem); - hasPreferredLanguage |= listItem.model.get(LanguageItemProperties.IS_SELECTED); - } - mListModel.set(listItems); - mModel.set(LanguagePickerProperties.IS_ENABLED_WATCH_BUTTON, hasPreferredLanguage); - } - - private PropertyModel buildListItemModelFromLocale(Language language) { - return new PropertyModel.Builder(LanguageItemProperties.ALL_KEYS) - .with(LanguageItemProperties.LOCALE, language.locale) - .with(LanguageItemProperties.NAME, language.name) - .with(LanguageItemProperties.NATIVE_NAME, language.nativeName) - .with(LanguageItemProperties.IS_SELECTED, - TextUtils.equals(language.locale, mSelectedLocale)) - .with(LanguageItemProperties.SELECTION_CALLBACK, this::onLanguageSelected) - .build(); - } - - private void onLanguageSelectionFinalized() { - VideoTutorialMetrics.recordLanguagePickerAction(LanguagePickerAction.WATCH); - mVideoTutorialService.setPreferredLocale(mSelectedLocale); - List<String> supportedLanguages = - mVideoTutorialService.getAvailableLanguagesForTutorial(mFeature); - for (int i = 0; i < supportedLanguages.size(); i++) { - if (TextUtils.equals(supportedLanguages.get(i), mSelectedLocale)) { - VideoTutorialMetrics.recordLanguageSelected(i); - break; - } - } - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerMediatorUnitTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerMediatorUnitTest.java deleted file mode 100644 index 5b63eca..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerMediatorUnitTest.java +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.languages; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.Mockito.verify; - -import android.content.Context; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.metrics.UmaRecorderHolder; -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.LanguageInfoProvider; -import org.chromium.chrome.browser.video_tutorials.test.TestVideoTutorialService; -import org.chromium.ui.modelutil.MVCListAdapter.ListItem; -import org.chromium.ui.modelutil.MVCListAdapter.ModelList; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel; -import org.chromium.ui.modelutil.PropertyObservable; - -/** - * Tests for {@link LanguagePickerMediator}. - */ -@RunWith(BaseRobolectricTestRunner.class) -public class LanguagePickerMediatorUnitTest { - @Mock - Context mContext; - private TestVideoTutorialService mTestVideoTutorialService; - private PropertyModel mModel; - private ModelList mListModel; - private LanguagePickerMediator mMediator; - @Mock - private PropertyObservable.PropertyObserver<PropertyKey> mPropertyObserver; - @Mock - private LanguageInfoProvider mLanguageProvider; - - @Before - public void setUp() { - UmaRecorderHolder.resetForTesting(); - MockitoAnnotations.initMocks(this); - - mModel = new PropertyModel(LanguagePickerProperties.ALL_KEYS); - mModel.addObserver(mPropertyObserver); - - mListModel = new ModelList(); - mTestVideoTutorialService = new TestVideoTutorialService(); - mMediator = new LanguagePickerMediator( - mContext, mModel, mListModel, mTestVideoTutorialService, mLanguageProvider); - } - - @Test - public void checkCallbacks() { - mMediator.showLanguagePicker(FeatureType.CHROME_INTRO, () -> {}, () -> {}); - verify(mPropertyObserver) - .onPropertyChanged(mModel, LanguagePickerProperties.CLOSE_CALLBACK); - verify(mPropertyObserver) - .onPropertyChanged(mModel, LanguagePickerProperties.WATCH_CALLBACK); - } - - @Test - public void loadsLanguagesInTheList() { - Mockito.when(mLanguageProvider.getLanguageInfo("hi")) - .thenReturn(TestVideoTutorialService.HINDI); - Mockito.when(mLanguageProvider.getLanguageInfo("ta")) - .thenReturn(TestVideoTutorialService.TAMIL); - Mockito.when(mLanguageProvider.getLanguageInfo("en")) - .thenReturn(TestVideoTutorialService.ENGLISH); - - mMediator.showLanguagePicker(FeatureType.CHROME_INTRO, () -> {}, () -> {}); - - assertThat(mListModel.size(), equalTo(mTestVideoTutorialService.getTestLanguages().size())); - ListItem listItem = mListModel.get(0); - assertThat(listItem.model.get(LanguageItemProperties.NAME), - equalTo(TestVideoTutorialService.HINDI.name)); - assertThat(listItem.model.get(LanguageItemProperties.NATIVE_NAME), - equalTo(TestVideoTutorialService.HINDI.nativeName)); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerProperties.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerProperties.java deleted file mode 100644 index f89b330c..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerProperties.java +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.languages; - -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; - -/** - * The properties associated with the outer layout of the language picker view. - */ -interface LanguagePickerProperties { - /** The callback to run when the close button is clicked on the UI. */ - WritableObjectPropertyKey<Runnable> CLOSE_CALLBACK = new WritableObjectPropertyKey<>(); - - /** The callback to run when the watch button is clicked on the UI. */ - WritableObjectPropertyKey<Runnable> WATCH_CALLBACK = new WritableObjectPropertyKey<>(); - - /** Whether or not the watch button should be shown as enabled. */ - WritableBooleanPropertyKey IS_ENABLED_WATCH_BUTTON = new WritableBooleanPropertyKey(); - - PropertyKey[] ALL_KEYS = - new PropertyKey[] {CLOSE_CALLBACK, WATCH_CALLBACK, IS_ENABLED_WATCH_BUTTON}; -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerTest.java deleted file mode 100644 index 63fde27..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerTest.java +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.languages; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import android.app.Activity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.FrameLayout; - -import androidx.test.espresso.action.ViewActions; -import androidx.test.filters.SmallTest; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.test.BaseActivityTestRule; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.LanguageInfoProvider; -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.chrome.browser.video_tutorials.test.TestVideoTutorialService; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.test.util.BlankUiTestActivity; - -/** - * Tests for {@link LanguagePickerCoordinator}. - */ -@RunWith(ChromeJUnit4ClassRunner.class) -public class LanguagePickerTest { - @Rule - public BaseActivityTestRule<BlankUiTestActivity> mActivityTestRule = - new BaseActivityTestRule<>(BlankUiTestActivity.class); - - private Activity mActivity; - private View mContentView; - private VideoTutorialService mVideoTutorialService; - private LanguagePickerCoordinator mCoordinator; - @Mock - private LanguageInfoProvider mLanguageProvider; - - @Mock - private Runnable mWatchCallback; - @Mock - private Runnable mCloseCallback; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mActivityTestRule.launchActivity(null); - mActivity = mActivityTestRule.getActivity(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - FrameLayout parentView = new FrameLayout(mActivity); - mActivity.setContentView(parentView); - mVideoTutorialService = new TestVideoTutorialService(); - mContentView = - LayoutInflater.from(mActivity).inflate(R.layout.language_picker, null, false); - parentView.addView(mContentView); - Mockito.when(mLanguageProvider.getLanguageInfo("hi")) - .thenReturn(TestVideoTutorialService.HINDI); - mCoordinator = new LanguagePickerCoordinator( - mContentView, mVideoTutorialService, mLanguageProvider); - mCoordinator.showLanguagePicker( - FeatureType.CHROME_INTRO, mWatchCallback, mCloseCallback); - }); - } - - @Test - @SmallTest - public void testShowLanguages() { - onView(withText(TestVideoTutorialService.HINDI.name)).check(matches(isDisplayed())); - onView(withText(TestVideoTutorialService.HINDI.nativeName)).check(matches(isDisplayed())); - onView(withText("Watch")).check(matches(isDisplayed())).perform(ViewActions.click()); - Mockito.verify(mWatchCallback).run(); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerView.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerView.java deleted file mode 100644 index 57d815c8..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/languages/LanguagePickerView.java +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.languages; - -import android.view.View; - -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.ui.modelutil.MVCListAdapter; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel; -import org.chromium.ui.modelutil.PropertyModelChangeProcessor; -import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter; - -/** - * The View component of the language picker UI which contains the recycler view and the outer - * layout. - */ -class LanguagePickerView { - private final PropertyModel mModel; - private final MVCListAdapter.ModelList mListModel; - private final View mView; - private final PropertyModelChangeProcessor<PropertyModel, View, PropertyKey> - mPropertyModelChangeProcessor; - - /** - * Constructor. - * @param view The associated view. - * @param model The model associated with the outer layout. - * @param listModel The model associated with the list view. - */ - public LanguagePickerView(View view, PropertyModel model, MVCListAdapter.ModelList listModel) { - mView = view; - mModel = model; - mListModel = listModel; - - mPropertyModelChangeProcessor = - PropertyModelChangeProcessor.create(mModel, mView, LanguagePickerView::bind); - RecyclerView recyclerView = mView.findViewById(R.id.recycler_view); - LinearLayoutManager layoutManager = - new LinearLayoutManager(mView.getContext(), LinearLayoutManager.VERTICAL, false); - recyclerView.setLayoutManager(layoutManager); - SimpleRecyclerViewAdapter adapter = new SimpleRecyclerViewAdapter(mListModel); - adapter.registerType(LanguageItemProperties.ITEM_VIEW_TYPE, - LanguageItemViewHolder::buildView, LanguageItemViewHolder::bindView); - recyclerView.setAdapter(adapter); - } - - /** @return The Android {@link View} representing this widget. */ - public View getView() { - return mView; - } - - /** - * The view binder to bind the model with the outer layout. - */ - public static void bind(PropertyModel model, View view, PropertyKey propertyKey) { - if (propertyKey == LanguagePickerProperties.WATCH_CALLBACK) { - View watchButton = view.findViewById(R.id.watch); - watchButton.setOnClickListener( - v -> { model.get(LanguagePickerProperties.WATCH_CALLBACK).run(); }); - } else if (propertyKey == LanguagePickerProperties.CLOSE_CALLBACK) { - View closeButton = view.findViewById(R.id.close_button); - closeButton.setOnClickListener( - v -> { model.get(LanguagePickerProperties.CLOSE_CALLBACK).run(); }); - } else if (propertyKey == LanguagePickerProperties.IS_ENABLED_WATCH_BUTTON) { - View watchButton = view.findViewById(R.id.watch); - watchButton.setEnabled(model.get(LanguagePickerProperties.IS_ENABLED_WATCH_BUTTON)); - } - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialCardProperties.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialCardProperties.java deleted file mode 100644 index 778728b..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialCardProperties.java +++ /dev/null
@@ -1,34 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.list; - -import org.chromium.components.browser_ui.widget.async_image.AsyncImageView; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; - -/** - * Properties for a video tutorial card. - */ -class TutorialCardProperties { - /** The view type used by the recycler view to show the tutorial cards. */ - public static final int VIDEO_TUTORIAL_CARD_VIEW_TYPE = 3; - - /** The title to be shown.*/ - static final WritableObjectPropertyKey<String> TITLE = new WritableObjectPropertyKey<>(); - - /** Text representing the length of the video.*/ - static final WritableObjectPropertyKey<String> VIDEO_LENGTH = new WritableObjectPropertyKey<>(); - - /** The callback to invoke when the card is clicked.*/ - static final WritableObjectPropertyKey<Runnable> CLICK_CALLBACK = - new WritableObjectPropertyKey<>(); - - /** The thumbnail provider to supply thumbnail images. */ - public static final WritableObjectPropertyKey<AsyncImageView.Factory> VISUALS_PROVIDER = - new WritableObjectPropertyKey<>(); - - static final PropertyKey[] ALL_KEYS = - new PropertyKey[] {TITLE, VIDEO_LENGTH, CLICK_CALLBACK, VISUALS_PROVIDER}; -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialCardViewBinder.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialCardViewBinder.java deleted file mode 100644 index 0ea9ed6..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialCardViewBinder.java +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.list; - -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.components.browser_ui.widget.async_image.AsyncImageView; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel; - -/** - * This class is responsible for building and binding the video tutorial card. - */ -class TutorialCardViewBinder { - /** Builder method to create the card view. */ - static View buildView(ViewGroup parent) { - return LayoutInflater.from(parent.getContext()) - .inflate(R.layout.video_tutorial_large_card, parent, false); - } - - /** Binder method to bind the card view with the model properties. */ - static void bindView(PropertyModel model, View view, PropertyKey propertyKey) { - if (propertyKey == TutorialCardProperties.TITLE) { - TextView title = view.findViewById((R.id.title)); - title.setText(model.get(TutorialCardProperties.TITLE)); - } else if (propertyKey == TutorialCardProperties.VIDEO_LENGTH) { - TextView title = view.findViewById((R.id.video_length)); - title.setText(model.get(TutorialCardProperties.VIDEO_LENGTH)); - } else if (propertyKey == TutorialCardProperties.CLICK_CALLBACK) { - view.setOnClickListener( - v -> { model.get(TutorialCardProperties.CLICK_CALLBACK).run(); }); - } else if (propertyKey == TutorialCardProperties.VISUALS_PROVIDER) { - AsyncImageView thumbnailView = (AsyncImageView) view.findViewById(R.id.thumbnail); - thumbnailView.setAsyncImageDrawable( - model.get(TutorialCardProperties.VISUALS_PROVIDER), null); - } else { - throw new IllegalArgumentException( - "Cannot update the view for propertyKey: " + propertyKey); - } - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorImpl.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorImpl.java deleted file mode 100644 index 5762a37e..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorImpl.java +++ /dev/null
@@ -1,131 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.list; - -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Rect; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.core.view.ViewCompat; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerView.ItemDecoration; -import androidx.recyclerview.widget.RecyclerView.OnScrollListener; -import androidx.recyclerview.widget.RecyclerView.State; - -import org.chromium.base.Callback; -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.components.browser_ui.widget.FadingShadow; -import org.chromium.components.browser_ui.widget.FadingShadowView; -import org.chromium.components.browser_ui.widget.displaystyle.HorizontalDisplayStyle; -import org.chromium.components.browser_ui.widget.displaystyle.UiConfig; -import org.chromium.components.browser_ui.widget.displaystyle.UiConfig.DisplayStyle; -import org.chromium.components.image_fetcher.ImageFetcher; -import org.chromium.ui.modelutil.MVCListAdapter; -import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter; - -/** - * The top level coordinator for the video tutorials list UI. - */ -public class TutorialListCoordinatorImpl implements TutorialListCoordinator { - private final TutorialListMediator mMediator; - private final ViewGroup mMainView; - private UiConfig mUiConfig; - - /** - * Constructor. - * @param mainView The {@link View} associated with this coordinator. - * @param videoTutorialService The video tutorial service backend. - * @param imageFetcher An {@link ImageFetcher} to provide thumbnail images. - * @param clickCallback A callback to be invoked when a tutorial is clicked. - */ - public TutorialListCoordinatorImpl(ViewGroup mainView, - VideoTutorialService videoTutorialService, ImageFetcher imageFetcher, - Callback<Tutorial> clickCallback) { - mMainView = mainView; - MVCListAdapter.ModelList listModel = new MVCListAdapter.ModelList(); - SimpleRecyclerViewAdapter adapter = new SimpleRecyclerViewAdapter(listModel); - adapter.registerType(TutorialCardProperties.VIDEO_TUTORIAL_CARD_VIEW_TYPE, - TutorialCardViewBinder::buildView, TutorialCardViewBinder::bindView); - final RecyclerView recyclerView = mainView.findViewById(R.id.recycler_view); - recyclerView.setAdapter(adapter); - recyclerView.setLayoutManager(new LinearLayoutManager( - recyclerView.getContext(), LinearLayoutManager.VERTICAL, false)); - recyclerView.addItemDecoration(new ItemDecorationImpl(recyclerView.getResources())); - - mMediator = new TutorialListMediator(listModel, recyclerView.getContext(), - videoTutorialService, imageFetcher, clickCallback); - - FadingShadowView toolbarShadow = mainView.findViewById(R.id.toolbar_shadow); - toolbarShadow.init(toolbarShadow.getContext().getColor(R.color.toolbar_shadow_color), - FadingShadow.POSITION_TOP); - - recyclerView.addOnScrollListener(new OnScrollListener() { - @Override - public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - boolean showShadow = recyclerView.canScrollVertically(-1); - toolbarShadow.setVisibility(showShadow ? View.VISIBLE : View.GONE); - } - }); - - configureWideDisplayStyle(); - } - - private void configureWideDisplayStyle() { - mUiConfig = new UiConfig(mMainView); - mUiConfig.addObserver(newDisplayStyle -> { - int padding = getPaddingForDisplayStyle(newDisplayStyle, mMainView.getResources()); - View recyclerView = mMainView.findViewById(R.id.recycler_view); - View toolbar = mMainView.findViewById(R.id.toolbar); - ViewCompat.setPaddingRelative(recyclerView, padding, recyclerView.getPaddingTop(), - padding, recyclerView.getPaddingBottom()); - ViewCompat.setPaddingRelative( - toolbar, padding, toolbar.getPaddingTop(), padding, toolbar.getPaddingBottom()); - }); - - mMainView.addView(new View(mMainView.getContext()) { - @Override - protected void onConfigurationChanged(Configuration newConfig) { - mUiConfig.updateDisplayStyle(); - } - }); - } - - private static int getPaddingForDisplayStyle(DisplayStyle displayStyle, Resources resources) { - int padding = 0; - if (displayStyle.horizontal == HorizontalDisplayStyle.WIDE) { - int screenWidthDp = resources.getConfiguration().screenWidthDp; - padding = (int) (((screenWidthDp - UiConfig.WIDE_DISPLAY_STYLE_MIN_WIDTH_DP) / 2.f) - * resources.getDisplayMetrics().density); - padding = - (int) Math.max(resources.getDimensionPixelSize(R.dimen.card_padding), padding); - } - return padding; - } - - private class ItemDecorationImpl extends ItemDecoration { - private final int mVerticalInterCardPaddingPx; - private final int mHorizontalStartPaddingPx; - - public ItemDecorationImpl(Resources resources) { - mVerticalInterCardPaddingPx = resources.getDimensionPixelOffset(R.dimen.card_padding); - mHorizontalStartPaddingPx = resources.getDimensionPixelOffset(R.dimen.card_padding); - } - - @Override - public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, - @NonNull RecyclerView parent, @NonNull State state) { - outRect.top = mVerticalInterCardPaddingPx / 2; - outRect.bottom = mVerticalInterCardPaddingPx / 2; - outRect.left = mHorizontalStartPaddingPx; - outRect.right = mHorizontalStartPaddingPx; - } - } -} \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorTest.java deleted file mode 100644 index 19c9a15d..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListCoordinatorTest.java +++ /dev/null
@@ -1,90 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.list; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withText; - -import android.app.Activity; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.FrameLayout; - -import androidx.test.espresso.action.ViewActions; -import androidx.test.filters.SmallTest; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.Callback; -import org.chromium.base.test.BaseActivityTestRule; -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialUtils; -import org.chromium.chrome.browser.video_tutorials.test.TestImageFetcher; -import org.chromium.chrome.browser.video_tutorials.test.TestVideoTutorialService; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.test.util.BlankUiTestActivity; - -/** - * Tests for {@link TutorialListCoordinator}. - */ -@RunWith(ChromeJUnit4ClassRunner.class) -public class TutorialListCoordinatorTest { - @Rule - public BaseActivityTestRule<BlankUiTestActivity> mActivityTestRule = - new BaseActivityTestRule<>(BlankUiTestActivity.class); - - private Activity mActivity; - private View mContentView; - private TestVideoTutorialService mTestVideoTutorialService; - private TutorialListCoordinator mCoordinator; - - @Mock - private Callback<Tutorial> mClickCallback; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mActivityTestRule.launchActivity(null); - mActivity = mActivityTestRule.getActivity(); - TestThreadUtils.runOnUiThreadBlocking(() -> { - FrameLayout parentView = new FrameLayout(mActivity); - mActivity.setContentView(parentView); - mTestVideoTutorialService = new TestVideoTutorialService(); - mContentView = LayoutInflater.from(mActivity).inflate( - R.layout.video_tutorial_list, null, false); - parentView.addView(mContentView); - - Bitmap testImage = BitmapFactory.decodeResource(mActivity.getResources(), - org.chromium.chrome.browser.video_tutorials.R.drawable.btn_close); - TestImageFetcher imageFetcher = new TestImageFetcher(testImage); - mCoordinator = new TutorialListCoordinatorImpl( - mContentView.findViewById(R.id.video_tutorial_list), mTestVideoTutorialService, - imageFetcher, mClickCallback); - }); - } - - @Test - @SmallTest - public void testShowList() { - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - onView(withText(tutorial.title)).check(matches(isDisplayed())); - onView(withText(VideoTutorialUtils.getVideoLengthString(tutorial.videoLength))) - .check(matches(isDisplayed())); - onView(withText(tutorial.title)).perform(ViewActions.click()); - Mockito.verify(mClickCallback).onResult(tutorial); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java deleted file mode 100644 index e73092d..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java +++ /dev/null
@@ -1,88 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.list; - -import android.content.Context; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; - -import org.chromium.base.Callback; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialUtils; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.UserAction; -import org.chromium.components.image_fetcher.ImageFetcher; -import org.chromium.ui.modelutil.MVCListAdapter; -import org.chromium.ui.modelutil.MVCListAdapter.ListItem; -import org.chromium.ui.modelutil.PropertyModel; - -import java.util.List; - -/** - * The mediator associated with the recycler view in the video tutorials home UI. - */ -public class TutorialListMediator { - private final Context mContext; - private final MVCListAdapter.ModelList mListModel; - private final VideoTutorialService mVideoTutorialService; - private final ImageFetcher mImageFetcher; - private final Callback<Tutorial> mClickCallback; - - /** - * Constructor. - * @param context The activity context. - * @param videoTutorialService The video tutorial service backend. - */ - public TutorialListMediator(MVCListAdapter.ModelList listModel, Context context, - VideoTutorialService videoTutorialService, ImageFetcher imageFetcher, - Callback<Tutorial> clickCallback) { - mListModel = listModel; - mContext = context; - mVideoTutorialService = videoTutorialService; - mImageFetcher = imageFetcher; - mClickCallback = clickCallback; - videoTutorialService.getTutorials(this::populateList); - } - - private void populateList(List<Tutorial> tutorials) { - assert mListModel.size() == 0; - for (Tutorial tutorial : tutorials) { - ListItem listItem = new ListItem(TutorialCardProperties.VIDEO_TUTORIAL_CARD_VIEW_TYPE, - buildModelFromTutorial(tutorial)); - mListModel.add(listItem); - } - } - - private PropertyModel buildModelFromTutorial(Tutorial tutorial) { - PropertyModel.Builder builder = - new PropertyModel.Builder(TutorialCardProperties.ALL_KEYS) - .with(TutorialCardProperties.TITLE, tutorial.title) - .with(TutorialCardProperties.VIDEO_LENGTH, - VideoTutorialUtils.getVideoLengthString(tutorial.videoLength)) - .with(TutorialCardProperties.CLICK_CALLBACK, () -> onCardClicked(tutorial)); - - builder.with(TutorialCardProperties.VISUALS_PROVIDER, (consumer, widthPx, heightPx) -> { - fetchImage(consumer, widthPx, heightPx, tutorial); - return () -> {}; - }); - return builder.build(); - } - - private void onCardClicked(Tutorial tutorial) { - VideoTutorialMetrics.recordUserAction(tutorial.featureType, UserAction.PLAYED_FROM_RECAP); - mClickCallback.onResult(tutorial); - } - - private void fetchImage( - Callback<Drawable> consumer, int widthPx, int heightPx, Tutorial tutorial) { - ImageFetcher.Params params = ImageFetcher.Params.create(tutorial.thumbnailUrl, - ImageFetcher.VIDEO_TUTORIALS_LIST_UMA_CLIENT_NAME, widthPx, heightPx); - mImageFetcher.fetchImage(params, bitmap -> { - Drawable drawable = new BitmapDrawable(mContext.getResources(), bitmap); - consumer.onResult(drawable); - }); - } -} \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetricsUnitTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetricsUnitTest.java deleted file mode 100644 index 9c8713c..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/metrics/VideoTutorialMetricsUnitTest.java +++ /dev/null
@@ -1,92 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.metrics; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.metrics.RecordHistogram; -import org.chromium.base.metrics.UmaRecorderHolder; -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.UserAction; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.WatchState; - -/** - * Tests for {@link VideoTutorialMetrics}. - */ -@RunWith(BaseRobolectricTestRunner.class) -public class VideoTutorialMetricsUnitTest { - @Before - public void setUp() { - UmaRecorderHolder.resetForTesting(); - } - - @After - public void tearDown() { - UmaRecorderHolder.resetForTesting(); - } - - @Test - public void testUserActionHistogramNames() { - VideoTutorialMetrics.recordUserAction(FeatureType.CHROME_INTRO, UserAction.SHARE); - VideoTutorialMetrics.recordUserAction(FeatureType.DOWNLOAD, UserAction.CLOSE); - VideoTutorialMetrics.recordUserAction(FeatureType.SEARCH, UserAction.CHANGE_LANGUAGE); - VideoTutorialMetrics.recordUserAction( - FeatureType.VOICE_SEARCH, UserAction.WATCH_NEXT_VIDEO); - VideoTutorialMetrics.recordUserAction(FeatureType.SEARCH, UserAction.TRY_NOW); - VideoTutorialMetrics.recordUserAction( - FeatureType.VOICE_SEARCH, UserAction.BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.ChromeIntro.Player.UserAction", UserAction.SHARE)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.Download.Player.UserAction", UserAction.CLOSE)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.Search.Player.UserAction", UserAction.CHANGE_LANGUAGE)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.VoiceSearch.Player.UserAction", - UserAction.WATCH_NEXT_VIDEO)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.Search.Player.UserAction", UserAction.TRY_NOW)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.VoiceSearch.Player.UserAction", - UserAction.BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER)); - } - - @Test - public void testWatchStateHistogramNames() { - VideoTutorialMetrics.recordWatchStateUpdate(FeatureType.CHROME_INTRO, WatchState.STARTED); - VideoTutorialMetrics.recordWatchStateUpdate(FeatureType.CHROME_INTRO, WatchState.COMPLETED); - VideoTutorialMetrics.recordWatchStateUpdate(FeatureType.CHROME_INTRO, WatchState.PAUSED); - VideoTutorialMetrics.recordWatchStateUpdate(FeatureType.CHROME_INTRO, WatchState.RESUMED); - VideoTutorialMetrics.recordWatchStateUpdate(FeatureType.CHROME_INTRO, WatchState.PAUSED); - VideoTutorialMetrics.recordWatchStateUpdate(FeatureType.CHROME_INTRO, WatchState.RESUMED); - VideoTutorialMetrics.recordWatchStateUpdate(FeatureType.CHROME_INTRO, WatchState.WATCHED); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.ChromeIntro.Player.Progress", WatchState.STARTED)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.ChromeIntro.Player.Progress", WatchState.COMPLETED)); - Assert.assertEquals(2, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.ChromeIntro.Player.Progress", WatchState.PAUSED)); - Assert.assertEquals(2, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.ChromeIntro.Player.Progress", WatchState.RESUMED)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "VideoTutorials.ChromeIntro.Player.Progress", WatchState.WATCHED)); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinatorImpl.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinatorImpl.java deleted file mode 100644 index 9dd3d0b..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerCoordinatorImpl.java +++ /dev/null
@@ -1,112 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.player; - -import android.content.Context; -import android.graphics.Color; -import android.util.Pair; -import android.view.View; - -import org.chromium.base.Callback; -import org.chromium.base.supplier.Supplier; -import org.chromium.chrome.browser.video_tutorials.LanguageInfoProvider; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver; -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.chrome.browser.video_tutorials.languages.LanguagePickerCoordinator; -import org.chromium.components.embedder_support.delegate.WebContentsDelegateAndroid; -import org.chromium.components.embedder_support.view.ContentView; -import org.chromium.components.thinwebview.ThinWebView; -import org.chromium.components.thinwebview.ThinWebViewConstraints; -import org.chromium.components.thinwebview.ThinWebViewFactory; -import org.chromium.content_public.browser.MediaSession; -import org.chromium.content_public.browser.WebContents; -import org.chromium.ui.base.IntentRequestTracker; -import org.chromium.ui.modelutil.PropertyModel; -import org.chromium.ui.modelutil.PropertyModelChangeProcessor; - -/** - * The top level coordinator for the video player. - */ -public class VideoPlayerCoordinatorImpl implements VideoPlayerCoordinator { - private final Context mContext; - private final PropertyModel mModel; - private final VideoPlayerView mView; - private final VideoPlayerMediator mMediator; - private final VideoTutorialService mVideoTutorialService; - private final LanguagePickerCoordinator mLanguagePicker; - private WebContents mWebContents; - private WebContentsDelegateAndroid mWebContentsDelegate; - private PlaybackStateObserver mMediaSessionObserver; - - /** - * Constructor. - * @param context The activity context. - * @param videoTutorialService The backend for serving video tutorials. - * @param webContentsFactory A supplier to supply WebContents and ContentView. - * @param tryNowCallback Callback to be invoked when try now button is clicked. - * @param closeCallback Callback to be invoked when this UI is closed. - * @param intentRequestTracker The {@link IntentRequestTracker} of the current activity. - */ - public VideoPlayerCoordinatorImpl(Context context, VideoTutorialService videoTutorialService, - Supplier<Pair<WebContents, ContentView>> webContentsFactory, - LanguageInfoProvider languageInfoProvider, Callback<Tutorial> tryNowCallback, - Runnable closeCallback, IntentRequestTracker intentRequestTracker) { - mContext = context; - mVideoTutorialService = videoTutorialService; - mModel = new PropertyModel(VideoPlayerProperties.ALL_KEYS); - - ThinWebView thinWebView = createThinWebView(webContentsFactory, intentRequestTracker); - mView = new VideoPlayerView(context, mModel, thinWebView); - mLanguagePicker = - new LanguagePickerCoordinator(mView.getView().findViewById(R.id.language_picker), - mVideoTutorialService, languageInfoProvider); - mMediator = new VideoPlayerMediator(mContext, mModel, videoTutorialService, mLanguagePicker, - mWebContents, mMediaSessionObserver, tryNowCallback, closeCallback); - PropertyModelChangeProcessor.create(mModel, mView, new VideoPlayerViewBinder()); - } - - @Override - public void playVideoTutorial(Tutorial tutorial) { - mMediator.playVideoTutorial(tutorial); - } - - @Override - public View getView() { - return mView.getView(); - } - - @Override - public boolean onBackPressed() { - if (mMediator.handleBackPressed()) return true; - return false; - } - - @Override - public void destroy() { - mMediaSessionObserver.stopObserving(); - mView.destroy(); - mWebContents.destroy(); - } - - private ThinWebView createThinWebView( - Supplier<Pair<WebContents, ContentView>> webContentsFactory, - IntentRequestTracker intentRequestTracker) { - Pair<WebContents, ContentView> pair = webContentsFactory.get(); - mWebContents = pair.first; - ContentView webContentView = pair.second; - mWebContentsDelegate = new WebContentsDelegateAndroid(); - mMediaSessionObserver = new PlaybackStateObserver( - MediaSession.fromWebContents(mWebContents), () -> { return mMediator; }); - - ThinWebViewConstraints constraints = new ThinWebViewConstraints(); - constraints.backgroundColor = Color.BLACK; - ThinWebView thinWebView = - ThinWebViewFactory.create(mContext, constraints, intentRequestTracker); - thinWebView.attachWebContents(mWebContents, webContentView, mWebContentsDelegate); - return thinWebView; - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java deleted file mode 100644 index 9117475..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediator.java +++ /dev/null
@@ -1,235 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.player; - -import android.content.Context; -import android.text.TextUtils; - -import org.chromium.base.Callback; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo.State; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialService; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialUtils; -import org.chromium.chrome.browser.video_tutorials.languages.LanguagePickerCoordinator; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.LanguagePickerAction; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.UserAction; -import org.chromium.chrome.browser.video_tutorials.metrics.VideoTutorialMetrics.WatchState; -import org.chromium.content_public.browser.LoadUrlParams; -import org.chromium.content_public.browser.WebContents; -import org.chromium.ui.modelutil.PropertyModel; - -/** - * The mediator for the video player UI, responsible for changing the state of UI based on user - * interaction events, and player state. - */ -class VideoPlayerMediator implements PlaybackStateObserver.Observer { - private static final String VARIATION_ENABLE_SHARE_BUTTON = "enable_share"; - public static Boolean sEnableShareForTesting; - - private final Context mContext; - private final VideoTutorialService mVideoTutorialService; - private final PropertyModel mModel; - private final LanguagePickerCoordinator mLanguagePicker; - private final WebContents mWebContents; - private Tutorial mTutorial; - private final Callback<Tutorial> mTryNowCallback; - private final Runnable mCloseCallback; - private final PlaybackStateObserver mPlaybackStateObserver; - private long mVideoStartTime; - - /** Constructor. */ - public VideoPlayerMediator(Context context, PropertyModel model, - VideoTutorialService videoTutorialService, LanguagePickerCoordinator languagePicker, - WebContents webContents, PlaybackStateObserver playbackStateObserver, - Callback<Tutorial> tryNowCallback, Runnable closeCallback) { - mContext = context; - mModel = model; - mVideoTutorialService = videoTutorialService; - mLanguagePicker = languagePicker; - mWebContents = webContents; - mTryNowCallback = tryNowCallback; - mCloseCallback = closeCallback; - mPlaybackStateObserver = playbackStateObserver; - - mModel.set(VideoPlayerProperties.SHOW_LOADING_SCREEN, false); - mModel.set(VideoPlayerProperties.SHOW_LANGUAGE_PICKER, false); - hideMediaControls(); - mModel.set(VideoPlayerProperties.CALLBACK_WATCH_NEXT, this::onWatchNextClicked); - mModel.set(VideoPlayerProperties.CALLBACK_CHANGE_LANGUAGE, this::changeLanguage); - mModel.set(VideoPlayerProperties.CALLBACK_TRY_NOW, this::tryNow); - mModel.set(VideoPlayerProperties.CALLBACK_SHARE, this::share); - mModel.set(VideoPlayerProperties.CALLBACK_CLOSE, this::close); - mModel.set(VideoPlayerProperties.CALLBACK_PLAY_BUTTON, () -> startVideo(mTutorial)); - } - - /** Called when the player is getting destroyed. */ - public void destroy() { - if (mPlaybackStateObserver.getWatchStateInfo().videoWatched()) { - VideoTutorialMetrics.recordWatchStateUpdate(mTutorial.featureType, WatchState.WATCHED); - } - } - - boolean handleBackPressed() { - // TODO(crbug.com/1406012): Remove these metrics or introduce new metrics in other lifecycle - // hooks because this method never consumes back event. - boolean isShowingLanguagePicker = mModel.get(VideoPlayerProperties.SHOW_LANGUAGE_PICKER); - boolean isShowingLoadingScreen = mModel.get(VideoPlayerProperties.SHOW_LOADING_SCREEN); - boolean isShowingVideoPlayer = !isShowingLanguagePicker && !isShowingLoadingScreen; - - if (isShowingVideoPlayer) { - VideoTutorialMetrics.recordUserAction( - mTutorial.featureType, UserAction.BACK_PRESS_WHEN_SHOWING_VIDEO_PLAYER); - } else if (isShowingLanguagePicker) { - VideoTutorialMetrics.recordLanguagePickerAction(LanguagePickerAction.BACK_PRESS); - } - - return false; - } - - /** - * Entry point for playing a tutorial video. Shows the language picker if it is the very first - * time. - */ - void playVideoTutorial(Tutorial tutorial) { - mTutorial = tutorial; - boolean shouldShowLanguagePicker = - TextUtils.isEmpty(mVideoTutorialService.getPreferredLocale()) - && areMultipleLanguagesAvailable(); - if (shouldShowLanguagePicker) { - mModel.set(VideoPlayerProperties.SHOW_LANGUAGE_PICKER, true); - mLanguagePicker.showLanguagePicker( - mTutorial.featureType, this::onLanguageSelected, mCloseCallback); - } else { - startVideo(tutorial); - } - } - - @Override - public void onPlay() { - VideoTutorialMetrics.recordWatchStateUpdate(mTutorial.featureType, WatchState.RESUMED); - if (mVideoStartTime != 0) { - VideoTutorialMetrics.recordVideoLoadTimeLatency( - System.currentTimeMillis() - mVideoStartTime); - // Set it to zero to ignore subsequent pause/resume events. - mVideoStartTime = 0; - } - - mModel.set(VideoPlayerProperties.SHOW_LOADING_SCREEN, false); - hideMediaControls(); - } - - @Override - public void onPause() { - VideoTutorialMetrics.recordWatchStateUpdate(mTutorial.featureType, WatchState.PAUSED); - mModel.set(VideoPlayerProperties.SHOW_WATCH_NEXT, false); - mModel.set(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE, false); - mModel.set(VideoPlayerProperties.SHOW_TRY_NOW, - VideoTutorialUtils.shouldShowTryNow(mTutorial.featureType)); - mModel.set(VideoPlayerProperties.WATCH_STATE_FOR_TRY_NOW, State.PAUSED); - mModel.set(VideoPlayerProperties.SHOW_SHARE, enableShare()); - mModel.set(VideoPlayerProperties.SHOW_CLOSE, true); - mModel.set(VideoPlayerProperties.SHOW_PLAY_BUTTON, false); - } - - @Override - public void onEnded() { - VideoTutorialMetrics.recordWatchStateUpdate(mTutorial.featureType, WatchState.COMPLETED); - mModel.set(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE, areMultipleLanguagesAvailable()); - maybeShowWatchNextVideoButton(); - mModel.set(VideoPlayerProperties.SHOW_TRY_NOW, - VideoTutorialUtils.shouldShowTryNow(mTutorial.featureType)); - mModel.set(VideoPlayerProperties.WATCH_STATE_FOR_TRY_NOW, State.ENDED); - mModel.set(VideoPlayerProperties.SHOW_SHARE, enableShare()); - mModel.set(VideoPlayerProperties.SHOW_CLOSE, true); - mModel.set(VideoPlayerProperties.SHOW_PLAY_BUTTON, true); - } - - @Override - public void onError() { - // TODO(shaktisahu): Determine UI for error state. - } - - private void changeLanguage() { - mModel.set(VideoPlayerProperties.SHOW_LANGUAGE_PICKER, true); - mLanguagePicker.showLanguagePicker( - mTutorial.featureType, this::onLanguageSelected, this::onLanguagePickerClosed); - VideoTutorialMetrics.recordUserAction(mTutorial.featureType, UserAction.CHANGE_LANGUAGE); - } - - private void onLanguageSelected() { - mModel.set(VideoPlayerProperties.SHOW_LANGUAGE_PICKER, false); - mVideoTutorialService.getTutorial(mTutorial.featureType, this::startVideo); - } - - private void onLanguagePickerClosed() { - mModel.set(VideoPlayerProperties.SHOW_LANGUAGE_PICKER, false); - } - - private void tryNow() { - VideoTutorialMetrics.recordUserAction(mTutorial.featureType, UserAction.TRY_NOW); - mTryNowCallback.onResult(mTutorial); - } - - private void share() { - VideoTutorialMetrics.recordUserAction(mTutorial.featureType, UserAction.SHARE); - VideoTutorialUtils.launchShareIntent(mContext, mTutorial); - } - - private void close() { - VideoTutorialMetrics.recordUserAction(mTutorial.featureType, UserAction.CLOSE); - mCloseCallback.run(); - } - - private void startVideo(Tutorial tutorial) { - mPlaybackStateObserver.reset(); - VideoTutorialMetrics.recordWatchStateUpdate(mTutorial.featureType, WatchState.STARTED); - mVideoStartTime = System.currentTimeMillis(); - mTutorial = tutorial; - LoadUrlParams loadUrlParams = - new LoadUrlParams(VideoPlayerURLBuilder.buildFromTutorial(tutorial)); - loadUrlParams.setHasUserGesture(true); - mWebContents.getNavigationController().loadUrl(loadUrlParams); - mModel.set(VideoPlayerProperties.SHOW_LOADING_SCREEN, false); - hideMediaControls(); - } - - private void maybeShowWatchNextVideoButton() { - VideoTutorialUtils.getNextTutorial(mVideoTutorialService, mTutorial, nextTutorial -> { - mModel.set(VideoPlayerProperties.SHOW_WATCH_NEXT, nextTutorial != null); - }); - } - - private void onWatchNextClicked() { - if (mPlaybackStateObserver.getWatchStateInfo().videoWatched()) { - VideoTutorialMetrics.recordWatchStateUpdate(mTutorial.featureType, WatchState.WATCHED); - } - VideoTutorialMetrics.recordUserAction(mTutorial.featureType, UserAction.WATCH_NEXT_VIDEO); - VideoTutorialUtils.getNextTutorial(mVideoTutorialService, mTutorial, this::startVideo); - } - - private void hideMediaControls() { - mModel.set(VideoPlayerProperties.SHOW_TRY_NOW, false); - mModel.set(VideoPlayerProperties.SHOW_WATCH_NEXT, false); - mModel.set(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE, false); - mModel.set(VideoPlayerProperties.SHOW_SHARE, enableShare()); - mModel.set(VideoPlayerProperties.SHOW_CLOSE, true); - mModel.set(VideoPlayerProperties.SHOW_PLAY_BUTTON, false); - } - - private boolean enableShare() { - return sEnableShareForTesting == null - ? ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( - ChromeFeatureList.VIDEO_TUTORIALS, VARIATION_ENABLE_SHARE_BUTTON, true) - : sEnableShareForTesting; - } - - private boolean areMultipleLanguagesAvailable() { - return mVideoTutorialService.getAvailableLanguagesForTutorial(mTutorial.featureType).size() - > 1; - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediatorUnitTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediatorUnitTest.java deleted file mode 100644 index 31311a5c..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerMediatorUnitTest.java +++ /dev/null
@@ -1,253 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.player; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; - -import android.content.Context; -import android.content.res.Resources; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.Callback; -import org.chromium.base.metrics.UmaRecorderHolder; -import org.chromium.base.test.BaseRobolectricTestRunner; -import org.chromium.chrome.browser.video_tutorials.FeatureType; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo; -import org.chromium.chrome.browser.video_tutorials.Tutorial; -import org.chromium.chrome.browser.video_tutorials.VideoTutorialUtils; -import org.chromium.chrome.browser.video_tutorials.languages.LanguagePickerCoordinator; -import org.chromium.chrome.browser.video_tutorials.test.TestVideoTutorialService; -import org.chromium.content_public.browser.NavigationController; -import org.chromium.content_public.browser.WebContents; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel; -import org.chromium.ui.modelutil.PropertyObservable; - -/** - * Tests for {@link VideoPlayerMediator}. - */ -@RunWith(BaseRobolectricTestRunner.class) -public class VideoPlayerMediatorUnitTest { - private TestVideoTutorialService mTestVideoTutorialService; - private PropertyModel mModel; - private VideoPlayerMediator mMediator; - @Mock - Context mContext; - @Mock - Resources mResources; - @Mock - private LanguagePickerCoordinator mLanguagePicker; - @Mock - WebContents mWebContents; - @Mock - NavigationController mNavigationController; - @Mock - Runnable mCloseCallback; - - @Captor - ArgumentCaptor<Runnable> mLanguagePickerCallback; - @Mock - PropertyObservable.PropertyObserver<PropertyKey> mPropertyObserver; - @Mock - Callback<Tutorial> mTryNowCallback; - @Mock - PlaybackStateObserver mPlaybackStateObserver; - - @Before - public void setUp() { - UmaRecorderHolder.resetForTesting(); - MockitoAnnotations.initMocks(this); - - Mockito.doReturn(mNavigationController).when(mWebContents).getNavigationController(); - Mockito.doReturn(mResources).when(mContext).getResources(); - mModel = new PropertyModel(VideoPlayerProperties.ALL_KEYS); - mModel.addObserver(mPropertyObserver); - - VideoPlayerMediator.sEnableShareForTesting = true; - mTestVideoTutorialService = new TestVideoTutorialService(); - mMediator = new VideoPlayerMediator(mContext, mModel, mTestVideoTutorialService, - mLanguagePicker, mWebContents, mPlaybackStateObserver, mTryNowCallback, - mCloseCallback); - } - - @Test - public void languagePickerShownFirstTime() { - mTestVideoTutorialService.setPreferredLocale(null); - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - mMediator.playVideoTutorial(tutorial); - - assertThat(mModel.get(VideoPlayerProperties.SHOW_LANGUAGE_PICKER), equalTo(true)); - Mockito.verify(mLanguagePicker, Mockito.times(1)) - .showLanguagePicker( - eq(tutorial.featureType), mLanguagePickerCallback.capture(), any()); - ((Runnable) mLanguagePickerCallback.getValue()).run(); - Mockito.verify(mNavigationController).loadUrl(any()); - } - - @Test - public void languagePickerNotShownIfOnlyOneLanguage() { - mTestVideoTutorialService.setPreferredLocale(null); - mTestVideoTutorialService.initializeTestLanguages(new String[] {"hi"}); - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - mMediator.playVideoTutorial(tutorial); - - assertThat(mModel.get(VideoPlayerProperties.SHOW_LANGUAGE_PICKER), equalTo(false)); - Mockito.verify(mLanguagePicker, Mockito.times(0)) - .showLanguagePicker(anyInt(), mLanguagePickerCallback.capture(), any()); - } - - @Test - public void languagePickerNotShownIfPreferredLocaleSetAlready() { - mTestVideoTutorialService.setPreferredLocale("en"); - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - mMediator.playVideoTutorial(tutorial); - - assertThat(mModel.get(VideoPlayerProperties.SHOW_LANGUAGE_PICKER), equalTo(false)); - Mockito.verify(mLanguagePicker, Mockito.never()).showLanguagePicker(anyInt(), any(), any()); - Mockito.verify(mNavigationController).loadUrl(any()); - } - - @Test - public void showLoadingScreenDuringStartup() { - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - mMediator.playVideoTutorial(tutorial); - Mockito.verify(mNavigationController).loadUrl(any()); - assertThat(mModel.get(VideoPlayerProperties.SHOW_LOADING_SCREEN), equalTo(false)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_SHARE), equalTo(true)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_CLOSE), equalTo(true)); - - mMediator.onPlay(); - assertThat(mModel.get(VideoPlayerProperties.SHOW_LOADING_SCREEN), equalTo(false)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_SHARE), equalTo(true)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_CLOSE), equalTo(true)); - } - - @Test - public void verifyControlsAtPauseState() { - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - mMediator.playVideoTutorial(tutorial); - mMediator.onPlay(); - mMediator.onPause(); - assertThat(mModel.get(VideoPlayerProperties.SHOW_SHARE), equalTo(true)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_CLOSE), equalTo(true)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_WATCH_NEXT), equalTo(false)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE), equalTo(false)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_PLAY_BUTTON), equalTo(false)); - } - - @Test - public void verifyControlsAtEndState() { - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - mMediator.playVideoTutorial(tutorial); - mMediator.onPlay(); - assertThat(mModel.get(VideoPlayerProperties.SHOW_WATCH_NEXT), equalTo(false)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE), equalTo(false)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_PLAY_BUTTON), equalTo(false)); - - mMediator.onEnded(); - assertThat(mModel.get(VideoPlayerProperties.SHOW_WATCH_NEXT), equalTo(true)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE), equalTo(true)); - assertThat(mModel.get(VideoPlayerProperties.SHOW_PLAY_BUTTON), equalTo(true)); - } - - @Test - public void testChangeLanguage() { - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - mMediator.playVideoTutorial(tutorial); - mMediator.onPlay(); - mMediator.onEnded(); - - mModel.get(VideoPlayerProperties.CALLBACK_CHANGE_LANGUAGE).run(); - Mockito.verify(mLanguagePicker, Mockito.times(1)) - .showLanguagePicker( - eq(tutorial.featureType), mLanguagePickerCallback.capture(), any()); - mTestVideoTutorialService.setPreferredLocale("en"); - ((Runnable) mLanguagePickerCallback.getValue()).run(); - } - - @Test - public void verifyButtonCallbacks() { - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - mMediator.playVideoTutorial(tutorial); - mMediator.onPlay(); - mMediator.onPause(); - - mModel.get(VideoPlayerProperties.CALLBACK_TRY_NOW).run(); - Mockito.verify(mTryNowCallback).onResult(tutorial); - - mModel.get(VideoPlayerProperties.CALLBACK_CLOSE).run(); - Mockito.verify(mCloseCallback).run(); - - mModel.get(VideoPlayerProperties.CALLBACK_SHARE).run(); - mModel.get(VideoPlayerProperties.CALLBACK_CHANGE_LANGUAGE).run(); - Mockito.verify(mLanguagePicker).showLanguagePicker(eq(tutorial.featureType), any(), any()); - - WatchStateInfo watchStateInfo = new WatchStateInfo(); - watchStateInfo.videoLength = 10; - watchStateInfo.currentPosition = 8; - Mockito.doReturn(watchStateInfo).when(mPlaybackStateObserver).getWatchStateInfo(); - mModel.get(VideoPlayerProperties.CALLBACK_WATCH_NEXT).run(); - mMediator.destroy(); - } - - @Test - public void testHandleBackPressed() { - Tutorial tutorial = mTestVideoTutorialService.getTestTutorials().get(0); - mMediator.playVideoTutorial(tutorial); - mMediator.onPlay(); - Assert.assertFalse(mMediator.handleBackPressed()); - } - - @Test - public void testVideoLengthString() { - assertThat(VideoTutorialUtils.getVideoLengthString(0), equalTo("0:00")); - assertThat(VideoTutorialUtils.getVideoLengthString(5), equalTo("0:05")); - assertThat(VideoTutorialUtils.getVideoLengthString(55), equalTo("0:55")); - assertThat(VideoTutorialUtils.getVideoLengthString(70), equalTo("1:10")); - assertThat(VideoTutorialUtils.getVideoLengthString(1200), equalTo("20:00")); - assertThat(VideoTutorialUtils.getVideoLengthString(3615), equalTo("1:00:15")); - } - - @Test - public void testTryNowEnabledForFeatures() { - Assert.assertFalse(VideoTutorialUtils.shouldShowTryNow(FeatureType.CHROME_INTRO)); - Assert.assertFalse(VideoTutorialUtils.shouldShowTryNow(FeatureType.DOWNLOAD)); - Assert.assertTrue(VideoTutorialUtils.shouldShowTryNow(FeatureType.SEARCH)); - Assert.assertTrue(VideoTutorialUtils.shouldShowTryNow(FeatureType.VOICE_SEARCH)); - Assert.assertFalse(VideoTutorialUtils.shouldShowTryNow(99)); - } - - @Test - public void testVideoPlayerURL() { - String videoUrl = "https://example/video.mp4"; - String posterUrl = "https://example/poster.png"; - String animationUrl = "https://example/anim.gif"; - String thumbnailUrl = "https://example/thumb.png"; - String captionUrl = "https://example/caption.vtt"; - String shareUrl = "https://example/share.mp4"; - Tutorial testTutorial = new Tutorial(FeatureType.CHROME_INTRO, "title", videoUrl, posterUrl, - animationUrl, thumbnailUrl, captionUrl, shareUrl, 25); - - assertThat(VideoPlayerURLBuilder.buildFromTutorial(testTutorial), - equalTo("chrome-untrusted://video-tutorials/" - + "?video_url=https://example/video.mp4" - + "&poster_url=https://example/poster.png" - + "&caption_url=https://example/caption.vtt")); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java deleted file mode 100644 index 04833d1..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerProperties.java +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.player; - -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo.State; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableBooleanPropertyKey; -import org.chromium.ui.modelutil.PropertyModel.WritableObjectPropertyKey; - -/** - * The properties required to build the video player which primarily contains (1) the screen being - * shown on the player, e.g. loading view, language picker, or video player. (2) callbacks - * associated with various buttons. - */ -interface VideoPlayerProperties { - WritableBooleanPropertyKey SHOW_LOADING_SCREEN = new WritableBooleanPropertyKey(); - WritableBooleanPropertyKey SHOW_LANGUAGE_PICKER = new WritableBooleanPropertyKey(); - WritableBooleanPropertyKey SHOW_TRY_NOW = new WritableBooleanPropertyKey(); - WritableBooleanPropertyKey SHOW_SHARE = new WritableBooleanPropertyKey(); - WritableBooleanPropertyKey SHOW_CLOSE = new WritableBooleanPropertyKey(); - WritableBooleanPropertyKey SHOW_WATCH_NEXT = new WritableBooleanPropertyKey(); - WritableBooleanPropertyKey SHOW_CHANGE_LANGUAGE = new WritableBooleanPropertyKey(); - WritableBooleanPropertyKey SHOW_PLAY_BUTTON = new WritableBooleanPropertyKey(); - WritableObjectPropertyKey<Runnable> CALLBACK_PLAY_BUTTON = new WritableObjectPropertyKey(); - WritableObjectPropertyKey<String> CHANGE_LANGUAGE_BUTTON_TEXT = - new WritableObjectPropertyKey<>(); - WritableObjectPropertyKey<Runnable> CALLBACK_WATCH_NEXT = new WritableObjectPropertyKey<>(); - WritableObjectPropertyKey<Runnable> CALLBACK_CHANGE_LANGUAGE = - new WritableObjectPropertyKey<>(); - WritableObjectPropertyKey<Runnable> CALLBACK_TRY_NOW = new WritableObjectPropertyKey<>(); - WritableObjectPropertyKey<Runnable> CALLBACK_SHARE = new WritableObjectPropertyKey<>(); - WritableObjectPropertyKey<Runnable> CALLBACK_CLOSE = new WritableObjectPropertyKey<>(); - WritableObjectPropertyKey<State> WATCH_STATE_FOR_TRY_NOW = new WritableObjectPropertyKey<>(); - - PropertyKey[] ALL_KEYS = new PropertyKey[] {SHOW_LOADING_SCREEN, SHOW_LANGUAGE_PICKER, - SHOW_TRY_NOW, SHOW_SHARE, SHOW_CLOSE, SHOW_WATCH_NEXT, SHOW_CHANGE_LANGUAGE, - SHOW_PLAY_BUTTON, CALLBACK_PLAY_BUTTON, CHANGE_LANGUAGE_BUTTON_TEXT, - CALLBACK_WATCH_NEXT, CALLBACK_CHANGE_LANGUAGE, CALLBACK_TRY_NOW, CALLBACK_SHARE, - CALLBACK_CLOSE, WATCH_STATE_FOR_TRY_NOW}; -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerURLBuilder.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerURLBuilder.java deleted file mode 100644 index fc519e22..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerURLBuilder.java +++ /dev/null
@@ -1,29 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.player; - -import org.chromium.chrome.browser.video_tutorials.Tutorial; - -/** - * Creates the player URL for a video tutorial. - */ -class VideoPlayerURLBuilder { - // TODO(shaktisahu): Move this to UrlConstants. - private static final String VIDEO_PLAYER_URL = "chrome-untrusted://video-tutorials/"; - - /** Constructs the player URL for a given video tutorial. */ - public static String buildFromTutorial(Tutorial tutorial) { - StringBuilder builder = new StringBuilder(); - builder.append(VIDEO_PLAYER_URL); - builder.append("?"); - builder.append("video_url="); - builder.append(tutorial.videoUrl); - builder.append("&poster_url="); - builder.append(tutorial.posterUrl); - builder.append("&caption_url="); - builder.append(tutorial.captionUrl); - return builder.toString(); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerView.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerView.java deleted file mode 100644 index 3accd667b..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerView.java +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.player; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; - -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo.State; -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.components.thinwebview.ThinWebView; -import org.chromium.ui.modelutil.PropertyModel; - -/** - * Represents the view component of the media player. Contains loading screen, language picker, and - * media controls. - */ -class VideoPlayerView { - private final PropertyModel mModel; - private final FrameLayout mFrameLayout; - private final ThinWebView mThinWebView; - private final View mLoadingView; - private final View mControls; - private final View mLanguagePickerView; - - /** Constructor. */ - public VideoPlayerView(Context context, PropertyModel model, ThinWebView thinWebView) { - mModel = model; - mThinWebView = thinWebView; - mFrameLayout = new FrameLayout(context); - mFrameLayout.addView(mThinWebView.getView()); - - mControls = LayoutInflater.from(context).inflate(R.layout.video_player_controls, null); - mLoadingView = LayoutInflater.from(context).inflate(R.layout.video_player_loading, null); - mLanguagePickerView = LayoutInflater.from(context).inflate(R.layout.language_picker, null); - - mFrameLayout.addView(mControls); - mFrameLayout.addView(mLoadingView); - mFrameLayout.addView(mLanguagePickerView); - } - - View getView() { - return mFrameLayout; - } - - void destroy() { - mThinWebView.destroy(); - } - - void showLoadingAnimation(boolean show) { - mLoadingView.setVisibility(show ? View.VISIBLE : View.GONE); - } - - void showLanguagePicker(boolean show) { - mLanguagePickerView.setVisibility(show ? View.VISIBLE : View.GONE); - } - - void setTryNowButtonPosition(WatchStateInfo.State state) { - View topHalf = mControls.findViewById(R.id.top_half); - View bottomHalf = mControls.findViewById(R.id.bottom_half); - LinearLayout.LayoutParams topLayoutParams = (LayoutParams) topHalf.getLayoutParams(); - LinearLayout.LayoutParams bottomLayoutParams = (LayoutParams) bottomHalf.getLayoutParams(); - if (state == State.PAUSED) { - topLayoutParams.weight = 0.5f; - bottomLayoutParams.weight = 0.5f; - } else if (state == State.ENDED) { - topLayoutParams.weight = 0.62f; - bottomLayoutParams.weight = 0.38f; - } else { - assert false : "Unexpected state " + state; - } - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinder.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinder.java deleted file mode 100644 index b6def9b..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinder.java +++ /dev/null
@@ -1,87 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.player; - -import android.view.View; -import android.widget.TextView; - -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.ui.modelutil.PropertyKey; -import org.chromium.ui.modelutil.PropertyModel; -import org.chromium.ui.modelutil.PropertyModelChangeProcessor.ViewBinder; - -/** - * The binder to bind the video player property model with the {@link VideoPlayerView}. - */ -class VideoPlayerViewBinder implements ViewBinder<PropertyModel, VideoPlayerView, PropertyKey> { - @Override - public void bind(PropertyModel model, VideoPlayerView view, PropertyKey propertyKey) { - if (propertyKey == VideoPlayerProperties.SHOW_LOADING_SCREEN) { - view.showLoadingAnimation(model.get(VideoPlayerProperties.SHOW_LOADING_SCREEN)); - } else if (propertyKey == VideoPlayerProperties.SHOW_LANGUAGE_PICKER) { - view.showLanguagePicker(model.get(VideoPlayerProperties.SHOW_LANGUAGE_PICKER)); - } else if (propertyKey == VideoPlayerProperties.SHOW_TRY_NOW) { - view.getView() - .findViewById(R.id.try_now) - .setVisibility(model.get(VideoPlayerProperties.SHOW_TRY_NOW) ? View.VISIBLE - : View.GONE); - } else if (propertyKey == VideoPlayerProperties.SHOW_SHARE) { - view.getView() - .findViewById(R.id.share_button) - .setVisibility( - model.get(VideoPlayerProperties.SHOW_SHARE) ? View.VISIBLE : View.GONE); - } else if (propertyKey == VideoPlayerProperties.SHOW_CLOSE) { - view.getView() - .findViewById(R.id.close_button) - .setVisibility( - model.get(VideoPlayerProperties.SHOW_CLOSE) ? View.VISIBLE : View.GONE); - } else if (propertyKey == VideoPlayerProperties.SHOW_WATCH_NEXT) { - view.getView() - .findViewById(R.id.watch_next) - .setVisibility(model.get(VideoPlayerProperties.SHOW_WATCH_NEXT) ? View.VISIBLE - : View.GONE); - } else if (propertyKey == VideoPlayerProperties.SHOW_CHANGE_LANGUAGE) { - view.getView() - .findViewById(R.id.change_language) - .setVisibility(model.get(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE) - ? View.VISIBLE - : View.GONE); - } else if (propertyKey == VideoPlayerProperties.SHOW_PLAY_BUTTON) { - view.getView() - .findViewById(R.id.play_button) - .setVisibility(model.get(VideoPlayerProperties.SHOW_PLAY_BUTTON) ? View.VISIBLE - : View.GONE); - } else if (propertyKey == VideoPlayerProperties.CHANGE_LANGUAGE_BUTTON_TEXT) { - TextView textView = view.getView().findViewById(R.id.change_language); - textView.setText(model.get(VideoPlayerProperties.CHANGE_LANGUAGE_BUTTON_TEXT)); - } else if (propertyKey == VideoPlayerProperties.CALLBACK_CLOSE) { - view.getView().findViewById(R.id.close_button).setOnClickListener(v -> { - model.get(VideoPlayerProperties.CALLBACK_CLOSE).run(); - }); - } else if (propertyKey == VideoPlayerProperties.CALLBACK_SHARE) { - view.getView().findViewById(R.id.share_button).setOnClickListener(v -> { - model.get(VideoPlayerProperties.CALLBACK_SHARE).run(); - }); - } else if (propertyKey == VideoPlayerProperties.CALLBACK_WATCH_NEXT) { - view.getView().findViewById(R.id.watch_next).setOnClickListener(v -> { - model.get(VideoPlayerProperties.CALLBACK_WATCH_NEXT).run(); - }); - } else if (propertyKey == VideoPlayerProperties.CALLBACK_TRY_NOW) { - view.getView().findViewById(R.id.try_now).setOnClickListener(v -> { - model.get(VideoPlayerProperties.CALLBACK_TRY_NOW).run(); - }); - } else if (propertyKey == VideoPlayerProperties.CALLBACK_CHANGE_LANGUAGE) { - view.getView().findViewById(R.id.change_language).setOnClickListener(v -> { - model.get(VideoPlayerProperties.CALLBACK_CHANGE_LANGUAGE).run(); - }); - } else if (propertyKey == VideoPlayerProperties.CALLBACK_PLAY_BUTTON) { - view.getView().findViewById(R.id.play_button).setOnClickListener(v -> { - model.get(VideoPlayerProperties.CALLBACK_PLAY_BUTTON).run(); - }); - } else if (propertyKey == VideoPlayerProperties.WATCH_STATE_FOR_TRY_NOW) { - view.setTryNowButtonPosition(model.get(VideoPlayerProperties.WATCH_STATE_FOR_TRY_NOW)); - } - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinderTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinderTest.java deleted file mode 100644 index d4cb7be..0000000 --- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/player/VideoPlayerViewBinderTest.java +++ /dev/null
@@ -1,209 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.video_tutorials.player; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import android.app.Activity; -import android.text.TextUtils; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.TextView; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.lifecycle.Stage; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import org.chromium.base.test.BaseActivityTestRule; -import org.chromium.base.test.UiThreadTest; -import org.chromium.base.test.util.ApplicationTestUtils; -import org.chromium.chrome.browser.video_tutorials.PlaybackStateObserver.WatchStateInfo.State; -import org.chromium.chrome.browser.video_tutorials.R; -import org.chromium.chrome.test.ChromeJUnit4ClassRunner; -import org.chromium.components.thinwebview.ThinWebView; -import org.chromium.content_public.browser.test.util.TestThreadUtils; -import org.chromium.ui.modelutil.PropertyModel; -import org.chromium.ui.modelutil.PropertyModelChangeProcessor; -import org.chromium.ui.test.util.BlankUiTestActivity; - -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Tests for {@link VideoPlayerViewBinder}. - */ -@RunWith(ChromeJUnit4ClassRunner.class) -public class VideoPlayerViewBinderTest { - @Rule - public BaseActivityTestRule<BlankUiTestActivity> mActivityTestRule = - new BaseActivityTestRule<>(BlankUiTestActivity.class); - - private Activity mActivity; - private VideoPlayerView mVideoPlayerView; - private View mLoadingView; - private View mLanguagePickerView; - private View mControls; - - private PropertyModel mModel; - private PropertyModelChangeProcessor mMCP; - - @Mock - private ThinWebView mThinWebView; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mActivityTestRule.launchActivity(null); - ApplicationTestUtils.waitForActivityState(mActivityTestRule.getActivity(), Stage.RESUMED); - mActivity = mActivityTestRule.getActivity(); - - TestThreadUtils.runOnUiThreadBlocking(() -> { - mModel = new PropertyModel(VideoPlayerProperties.ALL_KEYS); - - FrameLayout thinWebViewLayout = new FrameLayout(mActivity); - Mockito.when(mThinWebView.getView()).thenReturn(thinWebViewLayout); - - mVideoPlayerView = new VideoPlayerView(mActivity, mModel, mThinWebView); - View mainView = mVideoPlayerView.getView(); - mActivity.setContentView(mainView); - - mLanguagePickerView = mainView.findViewById(R.id.language_picker); - mLoadingView = mainView.findViewById(R.id.loading_root); - mControls = mainView.findViewById(R.id.player_root); - mLanguagePickerView.setVisibility(View.GONE); - mLoadingView.setVisibility(View.GONE); - mControls.setVisibility(View.GONE); - mMCP = PropertyModelChangeProcessor.create( - mModel, mVideoPlayerView, new VideoPlayerViewBinder()); - }); - } - - @After - public void tearDown() throws Exception { - TestThreadUtils.runOnUiThreadBlocking(() -> { - mMCP.destroy(); - mVideoPlayerView.destroy(); - }); - } - - @Test - @UiThreadTest - @SmallTest - public void testLoadingAnimation() { - mModel.set(VideoPlayerProperties.SHOW_LOADING_SCREEN, true); - assertEquals(View.VISIBLE, mLoadingView.getVisibility()); - mModel.set(VideoPlayerProperties.SHOW_LOADING_SCREEN, false); - assertEquals(View.GONE, mLoadingView.getVisibility()); - } - - @Test - @UiThreadTest - @SmallTest - public void testLanguagePickerVisibility() { - mModel.set(VideoPlayerProperties.SHOW_LANGUAGE_PICKER, true); - assertEquals(View.VISIBLE, mLanguagePickerView.getVisibility()); - } - - @Test - @UiThreadTest - @SmallTest - public void testTryNowButton() { - View tryNowButton = mControls.findViewById(R.id.try_now); - mModel.set(VideoPlayerProperties.SHOW_TRY_NOW, false); - assertEquals(View.GONE, tryNowButton.getVisibility()); - mModel.set(VideoPlayerProperties.SHOW_TRY_NOW, true); - assertEquals(View.VISIBLE, tryNowButton.getVisibility()); - - mModel.set(VideoPlayerProperties.WATCH_STATE_FOR_TRY_NOW, State.PAUSED); - mModel.set(VideoPlayerProperties.WATCH_STATE_FOR_TRY_NOW, State.ENDED); - AtomicBoolean buttonClicked = new AtomicBoolean(); - mModel.set(VideoPlayerProperties.CALLBACK_TRY_NOW, () -> buttonClicked.set(true)); - tryNowButton.performClick(); - assertTrue(buttonClicked.get()); - } - - @Test - @UiThreadTest - @SmallTest - public void testWatchNextButton() { - View watchNextButton = mControls.findViewById(R.id.watch_next); - mModel.set(VideoPlayerProperties.SHOW_WATCH_NEXT, false); - assertEquals(View.GONE, watchNextButton.getVisibility()); - mModel.set(VideoPlayerProperties.SHOW_WATCH_NEXT, true); - assertEquals(View.VISIBLE, watchNextButton.getVisibility()); - - AtomicBoolean buttonClicked = new AtomicBoolean(); - mModel.set(VideoPlayerProperties.CALLBACK_WATCH_NEXT, () -> buttonClicked.set(true)); - watchNextButton.performClick(); - assertTrue(buttonClicked.get()); - } - - @Test - @UiThreadTest - @SmallTest - public void testPlayButton() { - View playButton = mControls.findViewById(R.id.play_button); - mModel.set(VideoPlayerProperties.SHOW_PLAY_BUTTON, false); - assertEquals(View.GONE, playButton.getVisibility()); - mModel.set(VideoPlayerProperties.SHOW_PLAY_BUTTON, true); - assertEquals(View.VISIBLE, playButton.getVisibility()); - - AtomicBoolean buttonClicked = new AtomicBoolean(); - mModel.set(VideoPlayerProperties.CALLBACK_PLAY_BUTTON, () -> buttonClicked.set(true)); - playButton.performClick(); - assertTrue(buttonClicked.get()); - } - - @Test - @UiThreadTest - @SmallTest - public void testChangeLanguageButton() { - TextView changeLanguage = mControls.findViewById(R.id.change_language); - String languageName = "XYZ"; - mModel.set(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE, false); - assertEquals(View.GONE, changeLanguage.getVisibility()); - mModel.set(VideoPlayerProperties.SHOW_CHANGE_LANGUAGE, true); - mModel.set(VideoPlayerProperties.CHANGE_LANGUAGE_BUTTON_TEXT, languageName); - assertEquals(View.VISIBLE, changeLanguage.getVisibility()); - assertTrue(TextUtils.equals(languageName, changeLanguage.getText())); - - AtomicBoolean buttonClicked = new AtomicBoolean(); - mModel.set(VideoPlayerProperties.CALLBACK_CHANGE_LANGUAGE, () -> buttonClicked.set(true)); - changeLanguage.performClick(); - assertTrue(buttonClicked.get()); - } - - @Test - @UiThreadTest - @SmallTest - public void testShareButton() { - View shareButton = mControls.findViewById(R.id.share_button); - mModel.set(VideoPlayerProperties.SHOW_SHARE, true); - assertEquals(View.VISIBLE, shareButton.getVisibility()); - AtomicBoolean buttonClicked = new AtomicBoolean(); - mModel.set(VideoPlayerProperties.CALLBACK_SHARE, () -> buttonClicked.set(true)); - shareButton.performClick(); - assertTrue(buttonClicked.get()); - } - - @Test - @UiThreadTest - @SmallTest - public void testCloseButton() { - View closeButton = mControls.findViewById(R.id.close_button); - AtomicBoolean buttonClicked = new AtomicBoolean(); - mModel.set(VideoPlayerProperties.CALLBACK_CLOSE, () -> buttonClicked.set(true)); - closeButton.performClick(); - assertTrue(buttonClicked.get()); - } -}
diff --git a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc b/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc deleted file mode 100644 index 02a7ae9..0000000 --- a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.h" - -#include <memory> -#include <string> - -#include "base/android/jni_string.h" -#include "chrome/browser/video_tutorials/internal/jni_headers/TutorialConversionBridge_jni.h" - -namespace video_tutorials { - -using base::android::ConvertUTF8ToJavaString; - -ScopedJavaLocalRef<jobject> CreateJavaTutorialAndMaybeAddToList( - JNIEnv* env, - ScopedJavaLocalRef<jobject> jlist, - const Tutorial& tutorial) { - return Java_TutorialConversionBridge_createTutorialAndMaybeAddToList( - env, jlist, static_cast<int>(tutorial.feature), - ConvertUTF8ToJavaString(env, tutorial.title), - ConvertUTF8ToJavaString(env, tutorial.video_url.spec()), - ConvertUTF8ToJavaString(env, tutorial.poster_url.spec()), - ConvertUTF8ToJavaString(env, tutorial.animated_gif_url.spec()), - ConvertUTF8ToJavaString(env, tutorial.thumbnail_url.spec()), - ConvertUTF8ToJavaString(env, tutorial.caption_url.spec()), - ConvertUTF8ToJavaString(env, tutorial.share_url.spec()), - tutorial.video_length); -} - -ScopedJavaLocalRef<jobject> TutorialConversionBridge::CreateJavaTutorials( - JNIEnv* env, - const std::vector<Tutorial>& tutorials) { - ScopedJavaLocalRef<jobject> jlist = - Java_TutorialConversionBridge_createTutorialList(env); - - for (const auto& tutorial : tutorials) - CreateJavaTutorialAndMaybeAddToList(env, jlist, tutorial); - - return jlist; -} - -ScopedJavaLocalRef<jobject> TutorialConversionBridge::CreateJavaTutorial( - JNIEnv* env, - absl::optional<Tutorial> tutorial) { - ScopedJavaLocalRef<jobject> jobj; - if (tutorial.has_value()) { - jobj = CreateJavaTutorialAndMaybeAddToList( - env, ScopedJavaLocalRef<jobject>(), tutorial.value()); - } - - return jobj; -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.h b/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.h deleted file mode 100644 index b228ac5..0000000 --- a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.h +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_ANDROID_TUTORIAL_CONVERSION_BRIDGE_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_ANDROID_TUTORIAL_CONVERSION_BRIDGE_H_ - -#include <vector> - -#include "base/android/jni_android.h" -#include "chrome/browser/video_tutorials/tutorial.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -using base::android::ScopedJavaLocalRef; - -namespace video_tutorials { - -// Helper class providing video tutorial conversion utility methods between C++ -// and Java. -class TutorialConversionBridge { - public: - static ScopedJavaLocalRef<jobject> CreateJavaTutorials( - JNIEnv* env, - const std::vector<Tutorial>& tutorials); - - static ScopedJavaLocalRef<jobject> CreateJavaTutorial( - JNIEnv* env, - absl::optional<Tutorial> tutorial); -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_ANDROID_TUTORIAL_CONVERSION_BRIDGE_H_
diff --git a/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.cc b/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.cc deleted file mode 100644 index 7d3301f1..0000000 --- a/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.cc +++ /dev/null
@@ -1,129 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.h" - -#include <memory> -#include <vector> - -#include "base/android/callback_android.h" -#include "base/android/jni_array.h" -#include "base/android/jni_string.h" -#include "base/functional/bind.h" -#include "chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.h" -#include "chrome/browser/video_tutorials/internal/jni_headers/VideoTutorialServiceBridge_jni.h" -#include "chrome/browser/video_tutorials/tutorial.h" - -using base::android::AttachCurrentThread; - -namespace video_tutorials { -namespace { - -const char kVideoTutorialServiceBridgeKey[] = "video_tutorial_service_bridge"; - -void RunGetMultipleTutorialsCallback(const JavaRef<jobject>& j_callback, - std::vector<Tutorial> tutorials) { - JNIEnv* env = AttachCurrentThread(); - RunObjectCallbackAndroid( - j_callback, - TutorialConversionBridge::CreateJavaTutorials(env, std::move(tutorials))); -} - -void RunGetSingleTutorialCallback(const JavaRef<jobject>& j_callback, - absl::optional<Tutorial> tutorial) { - JNIEnv* env = AttachCurrentThread(); - RunObjectCallbackAndroid( - j_callback, TutorialConversionBridge::CreateJavaTutorial(env, tutorial)); -} - -} // namespace - -// static -ScopedJavaLocalRef<jobject> -VideoTutorialServiceBridge::GetBridgeForVideoTutorialService( - VideoTutorialService* video_tutorial_service) { - if (!video_tutorial_service->GetUserData(kVideoTutorialServiceBridgeKey)) { - video_tutorial_service->SetUserData( - kVideoTutorialServiceBridgeKey, - std::make_unique<VideoTutorialServiceBridge>(video_tutorial_service)); - } - - VideoTutorialServiceBridge* bridge = static_cast<VideoTutorialServiceBridge*>( - video_tutorial_service->GetUserData(kVideoTutorialServiceBridgeKey)); - - return ScopedJavaLocalRef<jobject>(bridge->java_obj_); -} - -VideoTutorialServiceBridge::VideoTutorialServiceBridge( - VideoTutorialService* video_tutorial_service) - : video_tutorial_service_(video_tutorial_service) { - DCHECK(video_tutorial_service_); - JNIEnv* env = base::android::AttachCurrentThread(); - java_obj_.Reset(env, Java_VideoTutorialServiceBridge_create( - env, reinterpret_cast<int64_t>(this)) - .obj()); -} - -VideoTutorialServiceBridge::~VideoTutorialServiceBridge() { - JNIEnv* env = base::android::AttachCurrentThread(); - Java_VideoTutorialServiceBridge_clearNativePtr(env, java_obj_); -} - -void VideoTutorialServiceBridge::GetTutorials( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - const JavaParamRef<jobject>& jcallback) { - video_tutorial_service_->GetTutorials( - base::BindOnce(&RunGetMultipleTutorialsCallback, - ScopedJavaGlobalRef<jobject>(jcallback))); -} - -void VideoTutorialServiceBridge::GetTutorial( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - jint j_feature, - const JavaParamRef<jobject>& jcallback) { - video_tutorial_service_->GetTutorial( - static_cast<FeatureType>(j_feature), - base::BindOnce(&RunGetSingleTutorialCallback, - ScopedJavaGlobalRef<jobject>(jcallback))); -} - -ScopedJavaLocalRef<jobjectArray> -VideoTutorialServiceBridge::GetSupportedLanguages( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller) { - return base::android::ToJavaArrayOfStrings( - env, video_tutorial_service_->GetSupportedLanguages()); -} - -ScopedJavaLocalRef<jobjectArray> -VideoTutorialServiceBridge::GetAvailableLanguagesForTutorial( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - jint j_feature) { - return base::android::ToJavaArrayOfStrings( - env, video_tutorial_service_->GetAvailableLanguagesForTutorial( - static_cast<FeatureType>(j_feature))); -} - -ScopedJavaLocalRef<jstring> VideoTutorialServiceBridge::GetPreferredLocale( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller) { - absl::optional<std::string> locale = - video_tutorial_service_->GetPreferredLocale(); - return locale.has_value() - ? base::android::ConvertUTF8ToJavaString(env, locale.value()) - : ScopedJavaLocalRef<jstring>(); -} - -void VideoTutorialServiceBridge::SetPreferredLocale( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - jstring j_locale) { - std::string locale = base::android::ConvertJavaStringToUTF8(env, j_locale); - video_tutorial_service_->SetPreferredLocale(locale); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.h b/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.h deleted file mode 100644 index 2307e79a..0000000 --- a/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.h +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_ANDROID_VIDEO_TUTORIAL_SERVICE_BRIDGE_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_ANDROID_VIDEO_TUTORIAL_SERVICE_BRIDGE_H_ - -#include "base/android/jni_android.h" -#include "base/memory/raw_ptr.h" -#include "base/supports_user_data.h" -#include "chrome/browser/video_tutorials/video_tutorial_service.h" - -using base::android::JavaParamRef; -using base::android::JavaRef; -using base::android::ScopedJavaGlobalRef; -using base::android::ScopedJavaLocalRef; - -namespace video_tutorials { - -// Helper class responsible for bridging the VideoTutorialService between C++ -// and Java. -class VideoTutorialServiceBridge : public base::SupportsUserData::Data { - public: - // Returns a Java VideoTutorialServiceBridge for |video_tutorial_service|. - // There will be only one bridge per VideoTutorialServiceBridge. - static ScopedJavaLocalRef<jobject> GetBridgeForVideoTutorialService( - VideoTutorialService* video_tutorial_service); - - explicit VideoTutorialServiceBridge( - VideoTutorialService* video_tutorial_service); - - VideoTutorialServiceBridge(const VideoTutorialServiceBridge&) = delete; - VideoTutorialServiceBridge& operator=(const VideoTutorialServiceBridge&) = - delete; - - ~VideoTutorialServiceBridge() override; - - // Methods called from Java via JNI. - void GetTutorials(JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - const JavaParamRef<jobject>& jcallback); - void GetTutorial(JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - jint j_feature, - const JavaParamRef<jobject>& jcallback); - ScopedJavaLocalRef<jobjectArray> GetSupportedLanguages( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller); - ScopedJavaLocalRef<jobjectArray> GetAvailableLanguagesForTutorial( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - jint j_feature); - ScopedJavaLocalRef<jstring> GetPreferredLocale( - JNIEnv* env, - const JavaParamRef<jobject>& jcaller); - void SetPreferredLocale(JNIEnv* env, - const JavaParamRef<jobject>& jcaller, - jstring j_locale); - - private: - // A reference to the Java counterpart of this class. See - // VideoTutorialServiceBridge.java. - ScopedJavaGlobalRef<jobject> java_obj_; - - // Not owned. - raw_ptr<VideoTutorialService> video_tutorial_service_; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_ANDROID_VIDEO_TUTORIAL_SERVICE_BRIDGE_H_
diff --git a/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge_factory.cc b/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge_factory.cc deleted file mode 100644 index f548350..0000000 --- a/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge_factory.cc +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/android/jni_android.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_android.h" -#include "chrome/browser/profiles/profile_key.h" -#include "chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.h" -#include "chrome/browser/video_tutorials/internal/jni_headers/VideoTutorialServiceFactory_jni.h" -#include "chrome/browser/video_tutorials/video_tutorial_service_factory.h" - -// Takes a Java Profile and returns a Java VideoTutorialService. -static base::android::ScopedJavaLocalRef<jobject> -JNI_VideoTutorialServiceFactory_GetForProfile( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& j_profile) { - Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile); - ProfileKey* profile_key = profile->GetProfileKey(); - - // Return null if there is no reasonable context for the provided Java - // profile. - if (profile_key == nullptr) - return base::android::ScopedJavaLocalRef<jobject>(); - - video_tutorials::VideoTutorialService* tutorial_service = - video_tutorials::VideoTutorialServiceFactory::GetInstance()->GetForKey( - profile_key); - return video_tutorials::VideoTutorialServiceBridge:: - GetBridgeForVideoTutorialService(tutorial_service); -}
diff --git a/chrome/browser/video_tutorials/internal/config.cc b/chrome/browser/video_tutorials/internal/config.cc deleted file mode 100644 index 3136d68..0000000 --- a/chrome/browser/video_tutorials/internal/config.cc +++ /dev/null
@@ -1,75 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/config.h" - -#include "base/command_line.h" -#include "base/metrics/field_trial_params.h" -#include "chrome/browser/video_tutorials/switches.h" - -namespace video_tutorials { -// Default URL string for GetTutorials RPC. -constexpr char kDefaultGetTutorialsPath[] = "/v1/videotutorials"; - -// The default locale. -constexpr char kDefaultPreferredLocale[] = "en"; - -// Finch parameter key for base server URL to retrieve the tutorials. -constexpr char kBaseURLKey[] = "base_url"; - -constexpr char kPreferredLocaleConfigKey[] = "default_locale"; - -constexpr char kFetchFrequencyKey[] = "fetch_frequency"; - -constexpr char kExperimentTagKey[] = "experiment_tag"; - -// Default frequency in days for fetching tutorial metatada from server. -constexpr int kDefaultFetchFrequencyDays = 15; - -namespace { -const GURL BuildGetTutorialsEndpoint(const GURL& base_url, const char* path) { - GURL::Replacements replacements; - replacements.SetPathStr(path); - return base_url.ReplaceComponents(replacements); -} - -} // namespace - -// static -GURL Config::GetTutorialsServerURL(const std::string& default_server_url) { - std::string base_url_from_finch = base::GetFieldTrialParamValueByFeature( - features::kVideoTutorials, kBaseURLKey); - if (!base_url_from_finch.empty()) - return BuildGetTutorialsEndpoint(GURL(base_url_from_finch), - kDefaultGetTutorialsPath); - return default_server_url.empty() - ? GURL() - : BuildGetTutorialsEndpoint(GURL(default_server_url), - kDefaultGetTutorialsPath); -} - -// static -std::string Config::GetDefaultPreferredLocale() { - std::string default_locale_from_finch = - base::GetFieldTrialParamValueByFeature(features::kVideoTutorials, - kPreferredLocaleConfigKey); - return default_locale_from_finch.empty() ? kDefaultPreferredLocale - : default_locale_from_finch; -} - -// static -base::TimeDelta Config::GetFetchFrequency() { - int frequency_in_days = base::GetFieldTrialParamByFeatureAsInt( - features::kVideoTutorials, kFetchFrequencyKey, - kDefaultFetchFrequencyDays); - return base::Days(frequency_in_days); -} - -// static -std::string Config::GetExperimentTag() { - return base::GetFieldTrialParamValueByFeature(features::kVideoTutorials, - kExperimentTagKey); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/config.h b/chrome/browser/video_tutorials/internal/config.h deleted file mode 100644 index 50a3a79..0000000 --- a/chrome/browser/video_tutorials/internal/config.h +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_CONFIG_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_CONFIG_H_ - -#include <memory> -#include <string> - -#include "base/time/time.h" -#include "url/gurl.h" - -namespace video_tutorials { - -// Default URL string for GetVideoTutorials RPC. -extern const char kDefaultGetTutorialsPath[]; - -// Finch parameter key for base server URL to retrieve the tutorials. -extern const char kBaseURLKey[]; - -// Finch parameter key for the default preferred locale. -extern const char kPreferredLocaleConfigKey[]; - -// Default preferred locale setting before user picks the language. -// This will be used as the language for the video tutorial promo cards. -extern const char kDefaultPreferredLocale[]; - -// Finch parameter key for the fetch frequency to retrieve the tutorials. -extern const char kFetchFrequencyKey[]; - -class Config { - public: - // Get video tutorials metadata server URL. - static GURL GetTutorialsServerURL(const std::string& default_server_url); - - // Get the default locale before users choice. - static std::string GetDefaultPreferredLocale(); - - // Get the default fetch frequency. - static base::TimeDelta GetFetchFrequency(); - - // Gets the experiment tag to be passed to server. - static std::string GetExperimentTag(); -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_CONFIG_H_
diff --git a/chrome/browser/video_tutorials/internal/config_unittest.cc b/chrome/browser/video_tutorials/internal/config_unittest.cc deleted file mode 100644 index 3c78bc2..0000000 --- a/chrome/browser/video_tutorials/internal/config_unittest.cc +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/config.h" - -#include <map> -#include <string> - -#include "base/test/scoped_feature_list.h" -#include "chrome/browser/video_tutorials/switches.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace video_tutorials { - -TEST(VideoTutorialsConfigTest, FinchConfigEnabled) { - base::test::ScopedFeatureList feature_list; - std::map<std::string, std::string> params = { - {kBaseURLKey, "https://test.com"}, - {kPreferredLocaleConfigKey, "en"}, - {"fetch_frequency", "10"}, - {"experiment_tag", "{some_param:some_value}"}}; - feature_list.InitAndEnableFeatureWithParameters(features::kVideoTutorials, - params); - - EXPECT_EQ(Config::GetTutorialsServerURL("").spec(), - "https://test.com/v1/videotutorials"); - EXPECT_EQ(Config::GetTutorialsServerURL("https://abc.com").spec(), - "https://test.com/v1/videotutorials"); - EXPECT_EQ(Config::GetDefaultPreferredLocale(), "en"); - EXPECT_EQ(Config::GetFetchFrequency(), base::Days(10)); - EXPECT_EQ(Config::GetExperimentTag(), "{some_param:some_value}"); -} - -TEST(VideoTutorialsConfigTest, ConfigDefaultParams) { - base::test::ScopedFeatureList feature_list; - feature_list.InitAndEnableFeature(features::kVideoTutorials); - EXPECT_EQ(Config::GetTutorialsServerURL("https://testing.com").spec(), - "https://testing.com/v1/videotutorials"); - EXPECT_EQ(Config::GetTutorialsServerURL(""), GURL()); - EXPECT_EQ(Config::GetDefaultPreferredLocale(), "en"); - EXPECT_EQ(Config::GetFetchFrequency(), base::Days(15)); - EXPECT_EQ(Config::GetExperimentTag(), ""); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/proto_conversions.cc b/chrome/browser/video_tutorials/internal/proto_conversions.cc deleted file mode 100644 index 01785d7..0000000 --- a/chrome/browser/video_tutorials/internal/proto_conversions.cc +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/proto_conversions.h" - -#include "base/notreached.h" - -namespace video_tutorials { - -FeatureType ToFeatureType(proto::FeatureType type) { - switch (type) { - case proto::FeatureType::INVALID: - return FeatureType::kInvalid; - case proto::FeatureType::SUMMARY: - return FeatureType::kSummary; - case proto::FeatureType::CHROME_INTRO: - return FeatureType::kChromeIntro; - case proto::FeatureType::DOWNLOAD: - return FeatureType::kDownload; - case proto::FeatureType::SEARCH: - return FeatureType::kSearch; - case proto::FeatureType::VOICE_SEARCH: - return FeatureType::kVoiceSearch; - case proto::FeatureType::TEST: - return FeatureType::kTest; - default: - return static_cast<FeatureType>(type); - } -} - -proto::FeatureType FromFeatureType(FeatureType type) { - switch (type) { - case FeatureType::kInvalid: - return proto::FeatureType::INVALID; - case FeatureType::kSummary: - return proto::FeatureType::SUMMARY; - case FeatureType::kChromeIntro: - return proto::FeatureType::CHROME_INTRO; - case FeatureType::kDownload: - return proto::FeatureType::DOWNLOAD; - case FeatureType::kSearch: - return proto::FeatureType::SEARCH; - case FeatureType::kVoiceSearch: - return proto::FeatureType::VOICE_SEARCH; - case FeatureType::kTest: - return proto::FeatureType::TEST; - default: - return static_cast<proto::FeatureType>(type); - } -} - -void TutorialFromProto(const proto::VideoTutorial* proto, Tutorial* tutorial) { - DCHECK(tutorial); - DCHECK(proto); - tutorial->feature = ToFeatureType(proto->feature()); - tutorial->title = proto->title(); - tutorial->video_url = GURL(proto->video_url()); - tutorial->share_url = GURL(proto->share_url()); - tutorial->poster_url = GURL(proto->poster_url()); - tutorial->animated_gif_url = GURL(proto->animated_gif_url()); - tutorial->thumbnail_url = GURL(proto->thumbnail_url()); - tutorial->caption_url = GURL(proto->caption_url()); - tutorial->video_length = proto->video_length(); -} - -std::vector<Tutorial> TutorialsFromProto( - const proto::VideoTutorialGroup* proto) { - std::vector<Tutorial> tutorials; - DCHECK(proto); - for (const auto& tutorial_proto : proto->tutorials()) { - Tutorial tutorial; - TutorialFromProto(&tutorial_proto, &tutorial); - tutorials.emplace_back(std::move(tutorial)); - } - return tutorials; -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/proto_conversions.h b/chrome/browser/video_tutorials/internal/proto_conversions.h deleted file mode 100644 index b1bcc05b..0000000 --- a/chrome/browser/video_tutorials/internal/proto_conversions.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_PROTO_CONVERSIONS_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_PROTO_CONVERSIONS_H_ - -#include "chrome/browser/video_tutorials/internal/tutorial_group.h" -#include "chrome/browser/video_tutorials/proto/video_tutorials.pb.h" - -namespace video_tutorials { - -FeatureType ToFeatureType(proto::FeatureType type); -proto::FeatureType FromFeatureType(FeatureType type); - -void TutorialFromProto(const proto::VideoTutorial* proto, Tutorial* tutorial); - -// Convert proto::VideoTutorialGroup to in-memory std::vector<Tutorial>. -std::vector<Tutorial> TutorialsFromProto( - const proto::VideoTutorialGroup* proto); - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_PROTO_CONVERSIONS_H_
diff --git a/chrome/browser/video_tutorials/internal/proto_conversions_unittest.cc b/chrome/browser/video_tutorials/internal/proto_conversions_unittest.cc deleted file mode 100644 index 5a8ecb3..0000000 --- a/chrome/browser/video_tutorials/internal/proto_conversions_unittest.cc +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/proto_conversions.h" -#include "chrome/browser/video_tutorials/test/test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace video_tutorials { -namespace { - -// Verify round-way conversion of feature enum type. -TEST(VideoTutorialsProtoConversionsTest, FeatureConversion) { - EXPECT_EQ(FeatureType::kTest, - ToFeatureType(FromFeatureType(FeatureType::kTest))); - EXPECT_EQ(FeatureType::kChromeIntro, - ToFeatureType(FromFeatureType(FeatureType::kChromeIntro))); - EXPECT_EQ(FeatureType::kDownload, - ToFeatureType(FromFeatureType(FeatureType::kDownload))); - EXPECT_EQ(FeatureType::kSearch, - ToFeatureType(FromFeatureType(FeatureType::kSearch))); - EXPECT_EQ(FeatureType::kVoiceSearch, - ToFeatureType(FromFeatureType(FeatureType::kVoiceSearch))); - EXPECT_EQ(FeatureType::kSummary, - ToFeatureType(FromFeatureType(FeatureType::kSummary))); -} - -TEST(VideoTutorialsProtoConversionsTest, TutorialFromProto) { - std::string title = "some_title"; - std::string video_url = "https://some_video_url.com/"; - std::string share_url = "https://some_share_url.com/"; - std::string poster_url = "https://some_poster_url.com/"; - std::string animated_gif_url = "https://some_animated_gif_url.com/"; - std::string thumbnail_url = "https://some_thumbnail_url.com/"; - std::string caption_url = "https://caption_url.com/"; - int video_length = 10; - - proto::VideoTutorial proto; - proto.set_feature(FromFeatureType(FeatureType::kDownload)); - proto.set_title(title); - proto.set_video_url(video_url); - proto.set_share_url(share_url); - proto.set_poster_url(poster_url); - proto.set_animated_gif_url(animated_gif_url); - proto.set_thumbnail_url(thumbnail_url); - proto.set_caption_url(caption_url); - proto.set_video_length(video_length); - Tutorial tutorial; - - TutorialFromProto(&proto, &tutorial); - EXPECT_EQ(title, tutorial.title); - EXPECT_EQ(video_url, tutorial.video_url); - EXPECT_EQ(share_url, tutorial.share_url); - EXPECT_EQ(poster_url, tutorial.poster_url); - EXPECT_EQ(animated_gif_url, tutorial.animated_gif_url); - EXPECT_EQ(thumbnail_url, tutorial.thumbnail_url); - EXPECT_EQ(caption_url, tutorial.caption_url); - EXPECT_EQ(video_length, tutorial.video_length); - - proto::VideoTutorialGroup group; - group.add_tutorials()->set_title(title); - std::vector<Tutorial> tutorials = TutorialsFromProto(&group); - EXPECT_EQ(1u, tutorials.size()); - EXPECT_EQ(title, tutorials[0].title); -} - -} // namespace -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/store.h b/chrome/browser/video_tutorials/internal/store.h deleted file mode 100644 index d318cb1..0000000 --- a/chrome/browser/video_tutorials/internal/store.h +++ /dev/null
@@ -1,42 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_STORE_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_STORE_H_ - -#include <map> -#include <memory> -#include <string> -#include <vector> - -#include "base/functional/callback.h" - -namespace video_tutorials { - -// Interface of video tutorials metadata store. -template <typename T> -class Store { - public: - using Entries = std::unique_ptr<std::vector<T>>; - using LoadCallback = base::OnceCallback<void(bool, std::unique_ptr<T>)>; - using UpdateCallback = base::OnceCallback<void(bool)>; - - // Initializes and loads the one and only database entry into memory. If - // invoked for the second time, it will skip initialization and proceeds with - // the load step. - virtual void InitAndLoad(LoadCallback callback) = 0; - - // Updates the one and only database entry. - virtual void Update(const T& entry, UpdateCallback callback) = 0; - - Store() = default; - virtual ~Store() = default; - - Store(const Store& other) = delete; - Store& operator=(const Store& other) = delete; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_STORE_H_
diff --git a/chrome/browser/video_tutorials/internal/tutorial_fetcher.cc b/chrome/browser/video_tutorials/internal/tutorial_fetcher.cc deleted file mode 100644 index ddcedf70..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_fetcher.cc +++ /dev/null
@@ -1,168 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/tutorial_fetcher.h" - -#include <utility> - -#include "base/lazy_instance.h" -#include "net/base/url_util.h" -#include "net/http/http_request_headers.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" -#include "services/network/public/mojom/url_response_head.mojom.h" - -namespace video_tutorials { -namespace { - -// An override server URL for testing. -base::LazyInstance<GURL>::Leaky g_override_url_for_testing; - -const char kRequestContentType[] = "application/x-protobuf"; - -constexpr net::NetworkTrafficAnnotationTag - kVideoTutorialFetcherTrafficAnnotation = - net::DefineNetworkTrafficAnnotation("video_tutorial_fetcher", R"( - semantics { - sender: "Video Tutorial Fetcher" - description: - "Fetches metadata for showing video tutorials on Android." - trigger: - "Chrome startup. Only triggered if the cache is older " - "than two weeks." - data: "No user data." - destination: GOOGLE_OWNED_SERVICE - } - policy { - cookies_allowed: NO - setting: - "No user setting to disable this feature. The " - "feature is only enabled in certain countries." - policy_exception_justification: - "Not implemented. The fetch frequency is really low." - } - )"); - -class TutorialFetcherImpl : public TutorialFetcher { - public: - TutorialFetcherImpl( - const GURL& url, - const std::string& country_code, - const std::string& accept_languages, - const std::string& api_key, - const std::string& experiment_tag, - const std::string& client_version, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) - : url_loader_factory_(url_loader_factory), - url_(url), - country_code_(country_code), - accept_languages_(accept_languages), - api_key_(api_key), - experiment_tag_(experiment_tag), - client_version_(client_version) {} - - private: - // TutorialFetcher implementation. - void StartFetchForTutorials(FinishedCallback callback) override { - auto resource_request = BuildGetRequest(); - if (!resource_request) - return; - url_loader_ = network::SimpleURLLoader::Create( - std::move(resource_request), kVideoTutorialFetcherTrafficAnnotation); - url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie( - url_loader_factory_.get(), - base::BindOnce(&TutorialFetcherImpl::OnDownloadComplete, - weak_ptr_factory_.GetWeakPtr(), std::move(callback))); - } - - void OnAcceptLanguagesChanged(const std::string& accept_languages) override { - accept_languages_ = accept_languages; - } - - // Build the request to get tutorial info. - std::unique_ptr<network::ResourceRequest> BuildGetRequest() { - if (url_.is_empty() && g_override_url_for_testing.Get().is_empty()) - return nullptr; - auto request = std::make_unique<network::ResourceRequest>(); - request->method = net::HttpRequestHeaders::kGetMethod; - request->headers.SetHeader("x-goog-api-key", api_key_); - request->headers.SetHeader("X-Client-Version", client_version_); - request->headers.SetHeader(net::HttpRequestHeaders::kContentType, - kRequestContentType); - request->url = - net::AppendOrReplaceQueryParameter(url_, "country_code", country_code_); - if (!experiment_tag_.empty()) { - request->url = net::AppendOrReplaceQueryParameter( - request->url, "experiment_tag", experiment_tag_); - } - if (!accept_languages_.empty()) { - request->headers.SetHeader(net::HttpRequestHeaders::kAcceptLanguage, - accept_languages_); - } - - if (!g_override_url_for_testing.Get().is_empty()) - request->url = g_override_url_for_testing.Get(); - - return request; - } - - // Called after receiving HTTP response. Processes the response code and net - // error. - void OnDownloadComplete(FinishedCallback callback, - std::unique_ptr<std::string> response_body) { - int response_code = -1; - if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) - response_code = url_loader_->ResponseInfo()->headers->response_code(); - - bool success = - (response_code >= 200 && response_code < 300 && response_body); - // TODO(shaktisahu): Collect metrics on response code. - std::move(callback).Run(success, std::move(response_body)); - url_loader_.reset(); - } - - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; - - // Simple URL loader to fetch proto from network. - std::unique_ptr<network::SimpleURLLoader> url_loader_; - - // Params of resource request. - GURL url_; - std::string country_code_; - std::string accept_languages_; - std::string api_key_; - std::string experiment_tag_; - std::string client_version_; - - base::WeakPtrFactory<TutorialFetcherImpl> weak_ptr_factory_{this}; -}; - -} // namespace - -// static -std::unique_ptr<TutorialFetcher> TutorialFetcher::Create( - const GURL& url, - const std::string& country_code, - const std::string& accept_languages, - const std::string& api_key, - const std::string& experiment_tag, - const std::string& client_version, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { - return std::make_unique<TutorialFetcherImpl>( - url, country_code, accept_languages, api_key, experiment_tag, - client_version, url_loader_factory); -} - -// static -void TutorialFetcher::SetOverrideURLForTesting(const GURL& url) { - g_override_url_for_testing.Get() = url; -} - -TutorialFetcher::TutorialFetcher() = default; -TutorialFetcher::~TutorialFetcher() = default; - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/tutorial_fetcher.h b/chrome/browser/video_tutorials/internal/tutorial_fetcher.h deleted file mode 100644 index 295e6f7..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_fetcher.h +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_FETCHER_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_FETCHER_H_ - -#include <memory> -#include <string> - -#include "base/functional/callback.h" -#include "url/gurl.h" - -namespace network { -class SharedURLLoaderFactory; -} // namespace network - -namespace video_tutorials { - -class TutorialFetcher { - public: - // Called after the fetch task is done, |status| and serialized response - // |data| will be returned. Invoked with |nullptr| if status is not success. - using FinishedCallback = - base::OnceCallback<void(bool success, - std::unique_ptr<std::string> response_body)>; - - // Method to create a TutorialFetcher. - static std::unique_ptr<TutorialFetcher> Create( - const GURL& url, - const std::string& country_code, - const std::string& accept_languages, - const std::string& api_key, - const std::string& experiment_tag, - const std::string& client_version, - const scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); - - // For testing only. - static void SetOverrideURLForTesting(const GURL& url); - - // Start the fetch to download tutorials. - virtual void StartFetchForTutorials(FinishedCallback callback) = 0; - - // Called when accept languages are changed. - virtual void OnAcceptLanguagesChanged( - const std::string& accept_languages) = 0; - - virtual ~TutorialFetcher(); - - TutorialFetcher(const TutorialFetcher& other) = delete; - TutorialFetcher& operator=(const TutorialFetcher& other) = delete; - - protected: - TutorialFetcher(); -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_FETCHER_H_
diff --git a/chrome/browser/video_tutorials/internal/tutorial_fetcher_unittest.cc b/chrome/browser/video_tutorials/internal/tutorial_fetcher_unittest.cc deleted file mode 100644 index f9cba09..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_fetcher_unittest.cc +++ /dev/null
@@ -1,197 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/tutorial_fetcher.h" - -#include "base/test/bind.h" -#include "base/test/task_environment.h" -#include "net/http/http_status_code.h" -#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" -#include "services/network/public/mojom/url_response_head.mojom.h" -#include "services/network/test/test_url_loader_factory.h" -#include "services/network/test/test_utils.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "url/gurl.h" - -namespace { -const char kServerURL[] = "https://www.test.com"; -const char kGoogleApiKey[] = "api-key"; -const char kVideoTutorialsMessage[] = R"pb( - tutorial_groups { - locale: "en" - tutorial { - feature: "1" - title: "feature1" - video_url: "https://some_url.com/video.mp4" - poster_url: "https://some_url.com/poster.jpg" - caption_url: "https://some_url.com/caption.vtt" - } - })pb"; -} // namespace - -namespace video_tutorials { -class TutorialFetcherTest : public testing::Test { - public: - TutorialFetcherTest(); - ~TutorialFetcherTest() override = default; - - TutorialFetcherTest(const TutorialFetcherTest& other) = delete; - TutorialFetcherTest& operator=(const TutorialFetcherTest& other) = delete; - - void SetUp() override; - - std::unique_ptr<TutorialFetcher> CreateFetcher(); - - bool RunFetcherWithNetError(net::Error net_error); - bool RunFetcherWithHttpError(net::HttpStatusCode http_error); - bool RunFetcherWithData(const std::string& response_data, - std::string* data_received); - - void RespondWithNetError(int net_error); - void RespondWithHttpError(net::HttpStatusCode http_error); - void RespondWithData(const std::string& data); - - network::ResourceRequest last_resource_request() const { - return last_resource_request_; - } - - private: - TutorialFetcher::FinishedCallback StoreResult(); - bool RunFetcher(base::OnceCallback<void(void)> respond_callback, - std::string* data_received); - - network::TestURLLoaderFactory test_url_loader_factory_; - scoped_refptr<network::SharedURLLoaderFactory> - test_shared_url_loader_factory_; - - std::unique_ptr<std::string> last_data_; - bool last_status_ = false; - network::ResourceRequest last_resource_request_; - - base::test::SingleThreadTaskEnvironment task_environment_{ - base::test::SingleThreadTaskEnvironment::MainThreadType::IO, - base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME}; -}; - -TutorialFetcherTest::TutorialFetcherTest() - : test_shared_url_loader_factory_( - base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( - &test_url_loader_factory_)) {} - -void TutorialFetcherTest::SetUp() { - test_url_loader_factory_.SetInterceptor( - base::BindLambdaForTesting([&](const network::ResourceRequest& request) { - EXPECT_TRUE(request.url.is_valid() && !request.url.is_empty()); - last_resource_request_ = request; - })); -} - -TutorialFetcher::FinishedCallback TutorialFetcherTest::StoreResult() { - return base::BindLambdaForTesting( - [&](bool success, std::unique_ptr<std::string> data) { - last_status_ = success; - last_data_ = std::move(data); - }); -} - -std::unique_ptr<TutorialFetcher> TutorialFetcherTest::CreateFetcher() { - std::unique_ptr<TutorialFetcher> fetcher = - TutorialFetcher::Create(GURL(kServerURL), "", "", kGoogleApiKey, "", "", - test_shared_url_loader_factory_); - return fetcher; -} - -bool TutorialFetcherTest::RunFetcherWithNetError(net::Error net_error) { - std::string data_received; - bool status = - RunFetcher(base::BindOnce(&TutorialFetcherTest::RespondWithNetError, - base::Unretained(this), net_error), - &data_received); - EXPECT_TRUE(data_received.empty()); - return status; -} - -bool TutorialFetcherTest::RunFetcherWithHttpError( - net::HttpStatusCode http_error) { - std::string data_received; - bool status = - RunFetcher(base::BindOnce(&TutorialFetcherTest::RespondWithHttpError, - base::Unretained(this), http_error), - &data_received); - EXPECT_TRUE(data_received.empty()); - - return status; -} - -bool TutorialFetcherTest::RunFetcherWithData(const std::string& response_data, - std::string* data_received) { - bool success = - RunFetcher(base::BindOnce(&TutorialFetcherTest::RespondWithData, - base::Unretained(this), response_data), - data_received); - return success; -} - -void TutorialFetcherTest::RespondWithNetError(int net_error) { - network::URLLoaderCompletionStatus completion_status(net_error); - test_url_loader_factory_.SimulateResponseForPendingRequest( - last_resource_request_.url, completion_status, - network::mojom::URLResponseHead::New(), std::string(), - network::TestURLLoaderFactory::kMostRecentMatch); -} - -void TutorialFetcherTest::RespondWithHttpError(net::HttpStatusCode http_error) { - auto url_response_head = network::CreateURLResponseHead(http_error); - test_url_loader_factory_.SimulateResponseForPendingRequest( - last_resource_request_.url, network::URLLoaderCompletionStatus(net::OK), - std::move(url_response_head), std::string(), - network::TestURLLoaderFactory::kMostRecentMatch); -} - -void TutorialFetcherTest::RespondWithData(const std::string& data) { - test_url_loader_factory_.SimulateResponseForPendingRequest( - last_resource_request_.url.spec(), data, net::HTTP_OK, - network::TestURLLoaderFactory::kMostRecentMatch); -} - -bool TutorialFetcherTest::RunFetcher( - base::OnceCallback<void(void)> respond_callback, - std::string* data_received) { - auto fetcher = CreateFetcher(); - fetcher->StartFetchForTutorials(StoreResult()); - std::move(respond_callback).Run(); - task_environment_.RunUntilIdle(); - if (last_data_) - *data_received = *last_data_; - return last_status_; -} - -// Tests that net errors will result in failed status. -TEST_F(TutorialFetcherTest, NetErrors) { - EXPECT_EQ(false, RunFetcherWithNetError(net::ERR_BLOCKED_BY_ADMINISTRATOR)); -} - -// Tests that http errors will result in failed status. -TEST_F(TutorialFetcherTest, HttpErrors) { - EXPECT_EQ(false, RunFetcherWithHttpError(net::HTTP_NOT_FOUND)); -} - -// Tests that empty responses are handled properly. -TEST_F(TutorialFetcherTest, EmptyResponse) { - std::string data; - EXPECT_EQ(true, RunFetcherWithData("", &data)); - EXPECT_TRUE(data.empty()); -} - -// Tests that a susscess response is received properly. -TEST_F(TutorialFetcherTest, Success) { - std::string data; - EXPECT_EQ(true, RunFetcherWithData(kVideoTutorialsMessage, &data)); - EXPECT_EQ(kVideoTutorialsMessage, data); - - EXPECT_EQ(last_resource_request().url.spec(), - "https://www.test.com/?country_code="); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/tutorial_group.cc b/chrome/browser/video_tutorials/internal/tutorial_group.cc deleted file mode 100644 index ce08b887..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_group.cc +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/tutorial_group.h" - -namespace video_tutorials { - -TutorialGroup::TutorialGroup() = default; - -TutorialGroup::TutorialGroup(const std::string& language) - : language(language) {} - -bool TutorialGroup::operator==(const TutorialGroup& other) const { - return language == other.language && tutorials == other.tutorials; -} - -bool TutorialGroup::operator!=(const TutorialGroup& other) const { - return !(*this == other); -} - -TutorialGroup::~TutorialGroup() = default; - -TutorialGroup::TutorialGroup(const TutorialGroup& other) = default; - -TutorialGroup& TutorialGroup::operator=(const TutorialGroup& other) = default; - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/tutorial_group.h b/chrome/browser/video_tutorials/internal/tutorial_group.h deleted file mode 100644 index 6210a3b..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_group.h +++ /dev/null
@@ -1,36 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_GROUP_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_GROUP_H_ - -#include <string> -#include <vector> - -#include "chrome/browser/video_tutorials/tutorial.h" - -namespace video_tutorials { - -// In memory struct of a group of video tutorials with same language . -struct TutorialGroup { - TutorialGroup(); - explicit TutorialGroup(const std::string& language); - ~TutorialGroup(); - - bool operator==(const TutorialGroup& other) const; - bool operator!=(const TutorialGroup& other) const; - - TutorialGroup(const TutorialGroup& other); - TutorialGroup& operator=(const TutorialGroup& other); - - // Language of this group. - std::string language; - - // A list of tutorials. - std::vector<Tutorial> tutorials; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_GROUP_H_
diff --git a/chrome/browser/video_tutorials/internal/tutorial_group_unittest.cc b/chrome/browser/video_tutorials/internal/tutorial_group_unittest.cc deleted file mode 100644 index 016f17b..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_group_unittest.cc +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/tutorial_group.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace video_tutorials { -namespace { - -void ResetTutorialGroup(TutorialGroup* group) { - *group = TutorialGroup("en"); - group->tutorials.resize(3, Tutorial()); - group->tutorials.front().feature = FeatureType::kDownload; - group->tutorials.back().feature = FeatureType::kSearch; -} - -// Verify the copy/assign and compare operators for TutorialGroup struct. -TEST(VideoTutorialGroupTest, CopyAndCompareOperators) { - TutorialGroup lhs, rhs; - ResetTutorialGroup(&lhs); - ResetTutorialGroup(&rhs); - - EXPECT_EQ(lhs, rhs); - - rhs.language = "jp"; - EXPECT_NE(lhs, rhs); - ResetTutorialGroup(&rhs); - - std::reverse(rhs.tutorials.begin(), rhs.tutorials.end()); - EXPECT_NE(lhs, rhs); - ResetTutorialGroup(&rhs); - - rhs.tutorials.pop_back(); - EXPECT_NE(lhs, rhs); - ResetTutorialGroup(&rhs); -} - -} // namespace -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager.h b/chrome/browser/video_tutorials/internal/tutorial_manager.h deleted file mode 100644 index 4828f9a9..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_manager.h +++ /dev/null
@@ -1,78 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_MANAGER_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_MANAGER_H_ - -#include "base/functional/callback.h" -#include "chrome/browser/video_tutorials/internal/tutorial_group.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -namespace video_tutorials { -namespace proto { -class VideoTutorialGroups; -} // namespace proto - -// Responsible for serving video tutorials and coordinating access with the -// network fetcher and the storage layer. -class TutorialManager { - public: - using SuccessCallback = base::OnceCallback<void(bool)>; - using MultipleItemCallback = base::OnceCallback<void(std::vector<Tutorial>)>; - using SingleItemCallback = base::OnceCallback<void(absl::optional<Tutorial>)>; - - // Called to initialize the DB. Any other method calls to this class will be - // cached and invoked after the initialization is completed. - virtual void Initialize(SuccessCallback callback) = 0; - - // Returns whether the initialization is complete. - virtual bool IsInitialized() = 0; - - // Called to return the list of video tutorials in the user's preferred - // language. Must be invoked after preferred language is changed. If preferred - // language is not set, it returns the tutorials in the first available - // language. - // This method also loads the data from DB for the first time. Hence every - // other method must be invoked after a call to this one. - virtual void GetTutorials(MultipleItemCallback callback) = 0; - - // Called to retrieve the tutorial associated with |feature_type|. - virtual void GetTutorial(FeatureType feature_type, - SingleItemCallback callback) = 0; - - // Returns a list of languages for which video tutorials are available. - virtual std::vector<std::string> GetSupportedLanguages() = 0; - - // Returns a list of languages in which a given tutorial is available. - virtual const std::vector<std::string>& GetAvailableLanguagesForTutorial( - FeatureType feature_type) = 0; - - // Returns the preferred locale for watching the video tutorials. - virtual absl::optional<std::string> GetPreferredLocale() = 0; - - // Sets the user preferred locale for watching the video tutorials. This - // doesn't update the cached tutorials. GetTutorials must be called for the - // new data to be reflected. - virtual void SetPreferredLocale(const std::string& locale) = 0; - - // Returns the locale used for showing the video card title text. - virtual std::string GetTextLocale() = 0; - - // Saves a fresh set of video tutorials into database. Called after a network - // fetch. - virtual void SaveGroups( - std::unique_ptr<proto::VideoTutorialGroups> groups) = 0; - - virtual ~TutorialManager() = default; - - TutorialManager(TutorialManager& other) = delete; - TutorialManager& operator=(TutorialManager& other) = delete; - - protected: - TutorialManager() = default; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_MANAGER_H_
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc b/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc deleted file mode 100644 index b6f9a89..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc +++ /dev/null
@@ -1,193 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/tutorial_manager_impl.h" - -#include <string> -#include <vector> - -#include "base/functional/bind.h" -#include "components/prefs/pref_service.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -namespace video_tutorials { -namespace { - -void FilterOutSummaryCard(std::vector<Tutorial>& tutorials) { - for (auto it = tutorials.begin(); it != tutorials.end();) { - if (it->feature == FeatureType::kSummary) { - it = tutorials.erase(it); - } else { - ++it; - } - } -} - -bool FindTutorialGroupInLanguage(const proto::VideoTutorialGroups& groups, - const std::string& language, - proto::VideoTutorialGroup& out_group) { - for (const proto::VideoTutorialGroup& group : groups.tutorial_groups()) { - if (group.language() == language) { - out_group = group; - return true; - } - } - return false; -} - -void FindTutorialGroupInPreferredLanguageOrDefault( - const proto::VideoTutorialGroups& groups, - const std::string& language, - proto::VideoTutorialGroup& out_group) { - bool found = FindTutorialGroupInLanguage(groups, language, out_group); - if (!found && groups.tutorial_groups_size() > 0) - out_group = groups.tutorial_groups(0); -} - -} // namespace - -TutorialManagerImpl::TutorialManagerImpl(std::unique_ptr<TutorialStore> store, - PrefService* prefs) - : store_(std::move(store)) {} - -TutorialManagerImpl::~TutorialManagerImpl() = default; - -void TutorialManagerImpl::Initialize(SuccessCallback callback) { - DCHECK(!initialized_); - - // The data doesn't exist in the cache. Load it from the DB. - store_->InitAndLoad(base::BindOnce(&TutorialManagerImpl::OnDataLoaded, - weak_ptr_factory_.GetWeakPtr(), - std::move(callback))); -} - -bool TutorialManagerImpl::IsInitialized() { - return initialized_; -} - -void TutorialManagerImpl::GetTutorials(MultipleItemCallback callback) { - DCHECK(initialized_); - if (!tutorial_groups_) { - std::move(callback).Run(std::vector<Tutorial>()); - return; - } - - auto preferred_locale = tutorial_groups_->preferred_locale(); - proto::VideoTutorialGroup active_group; - FindTutorialGroupInPreferredLanguageOrDefault(*tutorial_groups_, - preferred_locale, active_group); - auto tutorials = TutorialsFromProto(&active_group); - - FilterOutSummaryCard(tutorials); - std::move(callback).Run(tutorials); -} - -void TutorialManagerImpl::GetTutorial(FeatureType feature_type, - SingleItemCallback callback) { - DCHECK(initialized_); - if (!tutorial_groups_) { - std::move(callback).Run(absl::nullopt); - return; - } - - auto preferred_locale = tutorial_groups_->preferred_locale(); - proto::VideoTutorialGroup active_group; - FindTutorialGroupInPreferredLanguageOrDefault(*tutorial_groups_, - preferred_locale, active_group); - auto tutorials = TutorialsFromProto(&active_group); - for (const Tutorial& tutorial : tutorials) { - if (tutorial.feature == feature_type) { - std::move(callback).Run(tutorial); - return; - } - } - - std::move(callback).Run(absl::nullopt); -} - -std::vector<std::string> TutorialManagerImpl::GetSupportedLanguages() { - DCHECK(initialized_); - - std::vector<std::string> supported_languages; - if (!tutorial_groups_) - return supported_languages; - - for (const proto::VideoTutorialGroup& group : - tutorial_groups_->tutorial_groups()) { - supported_languages.emplace_back(group.language()); - } - - return supported_languages; -} - -const std::vector<std::string>& -TutorialManagerImpl::GetAvailableLanguagesForTutorial( - FeatureType feature_type) { - DCHECK(initialized_); - return languages_for_tutorials_[feature_type]; -} - -absl::optional<std::string> TutorialManagerImpl::GetPreferredLocale() { - DCHECK(initialized_); - std::string preferred_locale; - if (tutorial_groups_) - preferred_locale = tutorial_groups_->preferred_locale(); - return preferred_locale.empty() ? absl::nullopt - : absl::make_optional(preferred_locale); -} - -void TutorialManagerImpl::SetPreferredLocale(const std::string& locale) { - DCHECK(initialized_); - if (!tutorial_groups_) - return; - - tutorial_groups_->set_preferred_locale(locale); - store_->Update(*tutorial_groups_, - base::BindOnce(&TutorialManagerImpl::OnGroupsSaved, - weak_ptr_factory_.GetWeakPtr())); -} - -std::string TutorialManagerImpl::GetTextLocale() { - DCHECK(initialized_); - return tutorial_groups_ ? tutorial_groups_->text_locale() : std::string(); -} - -void TutorialManagerImpl::OnDataLoaded( - SuccessCallback callback, - bool success, - std::unique_ptr<proto::VideoTutorialGroups> loaded_data) { - tutorial_groups_ = std::move(loaded_data); - - if (tutorial_groups_) { - languages_for_tutorials_.clear(); - for (const auto& group : tutorial_groups_->tutorial_groups()) { - for (const auto& tutorial : group.tutorials()) { - auto feature = ToFeatureType(tutorial.feature()); - languages_for_tutorials_[feature].emplace_back(group.language()); - } - } - } - - initialized_ = true; - std::move(callback).Run(success); -} - -void TutorialManagerImpl::SaveGroups( - std::unique_ptr<proto::VideoTutorialGroups> groups) { - DCHECK(initialized_); - if (!groups) { - OnGroupsSaved(true); - return; - } - - if (tutorial_groups_) - groups->set_preferred_locale(tutorial_groups_->preferred_locale()); - - store_->Update(*groups, base::BindOnce(&TutorialManagerImpl::OnGroupsSaved, - weak_ptr_factory_.GetWeakPtr())); -} - -void TutorialManagerImpl::OnGroupsSaved(bool success) {} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.h b/chrome/browser/video_tutorials/internal/tutorial_manager_impl.h deleted file mode 100644 index 69097906a..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.h +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_MANAGER_IMPL_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_MANAGER_IMPL_H_ - -#include "chrome/browser/video_tutorials/internal/tutorial_manager.h" - -#include <deque> -#include <map> -#include <memory> -#include <string> -#include <vector> - -#include "base/memory/weak_ptr.h" -#include "chrome/browser/video_tutorials/internal/proto_conversions.h" -#include "chrome/browser/video_tutorials/internal/store.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -class PrefService; - -namespace video_tutorials { - -class TutorialManagerImpl : public TutorialManager { - public: - using TutorialStore = Store<proto::VideoTutorialGroups>; - TutorialManagerImpl(std::unique_ptr<TutorialStore> store, PrefService* prefs); - ~TutorialManagerImpl() override; - - private: - // TutorialManager implementation. - void Initialize(SuccessCallback callback) override; - bool IsInitialized() override; - void GetTutorials(MultipleItemCallback callback) override; - void GetTutorial(FeatureType feature_type, - SingleItemCallback callback) override; - std::vector<std::string> GetSupportedLanguages() override; - const std::vector<std::string>& GetAvailableLanguagesForTutorial( - FeatureType feature_type) override; - absl::optional<std::string> GetPreferredLocale() override; - void SetPreferredLocale(const std::string& locale) override; - std::string GetTextLocale() override; - void SaveGroups(std::unique_ptr<proto::VideoTutorialGroups> groups) override; - - void OnDataLoaded(SuccessCallback callback, - bool success, - std::unique_ptr<proto::VideoTutorialGroups> loaded_groups); - void OnGroupsSaved(bool success); - - // The underlying persistence store. - std::unique_ptr<TutorialStore> store_; - - // List of supported languages per tutorial. - std::map<FeatureType, std::vector<std::string>> languages_for_tutorials_; - - // Cached copy of the DB. Loaded on the first call to GetTutorials. - std::unique_ptr<proto::VideoTutorialGroups> tutorial_groups_; - - // The initialization status of the database. - bool initialized_{false}; - - base::WeakPtrFactory<TutorialManagerImpl> weak_ptr_factory_{this}; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_MANAGER_IMPL_H_
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc b/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc deleted file mode 100644 index 4803193..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc +++ /dev/null
@@ -1,232 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/tutorial_manager_impl.h" - -#include <map> -#include <utility> - -#include "base/functional/bind.h" -#include "base/memory/raw_ptr.h" -#include "base/run_loop.h" -#include "base/test/task_environment.h" -#include "chrome/browser/video_tutorials/internal/tutorial_store.h" -#include "chrome/browser/video_tutorials/prefs.h" -#include "components/prefs/testing_pref_service.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; -using ::testing::StrictMock; - -namespace video_tutorials { -namespace { - -proto::VideoTutorialGroups CreateSampleGroups( - const std::vector<std::string>& locales, - const std::vector<FeatureType>& features) { - proto::VideoTutorialGroups groups; - for (const auto& locale : locales) { - proto::VideoTutorialGroup* group = groups.add_tutorial_groups(); - group->set_language(locale); - for (FeatureType feature : features) { - proto::VideoTutorial* tutorial = group->add_tutorials(); - tutorial->set_feature(FromFeatureType(feature)); - } - } - - return groups; -} - -class TestStore : public TutorialStore { - public: - TestStore() : TutorialStore(nullptr) {} - ~TestStore() override = default; - - void InitAndLoad(LoadCallback callback) override { - std::move(callback).Run( - true, std::make_unique<proto::VideoTutorialGroups>(groups_)); - } - - void Update(const proto::VideoTutorialGroups& entry, - UpdateCallback callback) override { - groups_ = entry; - std::move(callback).Run(true); - } - - void Update(const proto::VideoTutorialGroups groups) { - Update(groups, base::BindOnce([](bool success) { EXPECT_TRUE(success); })); - base::RunLoop().RunUntilIdle(); - } - - private: - proto::VideoTutorialGroups groups_; -}; - -class TutorialManagerTest : public testing::Test { - public: - TutorialManagerTest() = default; - ~TutorialManagerTest() override = default; - - TutorialManagerTest(const TutorialManagerTest& other) = delete; - TutorialManagerTest& operator=(const TutorialManagerTest& other) = delete; - - void SetUp() override { video_tutorials::RegisterPrefs(prefs_.registry()); } - - void CreateTutorialManager(std::unique_ptr<TestStore> tutorial_store) { - tutorial_store_ = tutorial_store.get(); - manager_ = std::make_unique<TutorialManagerImpl>(std::move(tutorial_store), - &prefs_); - } - - // Run Initialize call from manager_ and waits for callback completion. - void Initialize() { - base::RunLoop loop; - manager()->Initialize(base::BindOnce(&TutorialManagerTest::OnInitialize, - base::Unretained(this), - loop.QuitClosure())); - loop.Run(); - } - - void OnInitialize(base::RepeatingClosure closure, bool success) { - std::move(closure).Run(); - } - - // Run GetTutorials call from manager_ and caches the results in - // last_results_. - void GetTutorials() { - base::RunLoop loop; - last_results_.clear(); - manager()->GetTutorials(base::BindOnce(&TutorialManagerTest::OnGetTutorials, - base::Unretained(this), - loop.QuitClosure())); - loop.Run(); - } - - void OnGetTutorials(base::RepeatingClosure closure, - std::vector<Tutorial> tutorials) { - last_results_ = tutorials; - std::move(closure).Run(); - } - - void GetTutorial(FeatureType feature_type) { - base::RunLoop loop; - last_get_tutorial_result_ = absl::nullopt; - manager()->GetTutorial( - feature_type, - base::BindOnce(&TutorialManagerTest::OnGetTutorial, - base::Unretained(this), loop.QuitClosure())); - loop.Run(); - } - - void OnGetTutorial(base::RepeatingClosure closure, - absl::optional<Tutorial> tutorial) { - last_get_tutorial_result_ = tutorial; - std::move(closure).Run(); - } - - void SaveGroups(std::unique_ptr<proto::VideoTutorialGroups> groups) { - manager()->SaveGroups(std::move(groups)); - base::RunLoop().RunUntilIdle(); - } - - protected: - TutorialManager* manager() { return manager_.get(); } - TestStore* tutorial_store() { return tutorial_store_; } - std::vector<Tutorial> last_results() { return last_results_; } - absl::optional<Tutorial> last_get_tutorial_result() { - return last_get_tutorial_result_; - } - - private: - base::test::TaskEnvironment task_environment_; - TestingPrefServiceSimple prefs_; - std::unique_ptr<TutorialManager> manager_; - raw_ptr<TestStore> tutorial_store_; - std::vector<Tutorial> last_results_; - absl::optional<Tutorial> last_get_tutorial_result_; -}; - -TEST_F(TutorialManagerTest, InitAndGetTutorials) { - std::vector<FeatureType> features( - {FeatureType::kDownload, FeatureType::kSearch}); - auto groups = CreateSampleGroups({"hi", "kn"}, features); - auto* tutorial = groups.mutable_tutorial_groups(1)->add_tutorials(); - tutorial->set_feature(FromFeatureType(FeatureType::kVoiceSearch)); - - auto tutorial_store = std::make_unique<StrictMock<TestStore>>(); - tutorial_store->Update(groups); - CreateTutorialManager(std::move(tutorial_store)); - Initialize(); - - auto languages = manager()->GetSupportedLanguages(); - EXPECT_EQ(languages.size(), 2u); - manager()->SetPreferredLocale("hi"); - GetTutorials(); - EXPECT_EQ(last_results().size(), 2u); - - GetTutorial(FeatureType::kSearch); - EXPECT_EQ(FeatureType::kSearch, last_get_tutorial_result()->feature); - - languages = manager()->GetAvailableLanguagesForTutorial(FeatureType::kSearch); - EXPECT_EQ(languages.size(), 2u); - languages = - manager()->GetAvailableLanguagesForTutorial(FeatureType::kChromeIntro); - EXPECT_EQ(languages.size(), 0u); - languages = - manager()->GetAvailableLanguagesForTutorial(FeatureType::kVoiceSearch); - EXPECT_EQ(languages.size(), 1u); -} - -TEST_F(TutorialManagerTest, InitAndGetTutorialsWithSummary) { - std::vector<FeatureType> features( - {FeatureType::kDownload, FeatureType::kSearch, FeatureType::kSummary}); - auto groups = CreateSampleGroups({"hi", "kn"}, features); - auto tutorial_store = std::make_unique<StrictMock<TestStore>>(); - tutorial_store->Update(groups); - CreateTutorialManager(std::move(tutorial_store)); - Initialize(); - - auto languages = manager()->GetSupportedLanguages(); - EXPECT_EQ(languages.size(), 2u); - manager()->SetPreferredLocale("hi"); - GetTutorials(); - EXPECT_EQ(last_results().size(), 2u); -} - -TEST_F(TutorialManagerTest, SaveNewData) { - std::vector<FeatureType> features( - {FeatureType::kDownload, FeatureType::kSearch, FeatureType::kSummary}); - auto groups = CreateSampleGroups({"hi", "kn"}, features); - auto tutorial_store = std::make_unique<StrictMock<TestStore>>(); - tutorial_store->Update(groups); - CreateTutorialManager(std::move(tutorial_store)); - Initialize(); - - manager()->SetPreferredLocale("hi"); - auto languages = manager()->GetSupportedLanguages(); - EXPECT_EQ(languages.size(), 2u); - GetTutorials(); - EXPECT_EQ(last_results().size(), 2u); - languages = - manager()->GetAvailableLanguagesForTutorial(FeatureType::kDownload); - EXPECT_EQ(languages.size(), 2u); - - // New fetch data. - features = std::vector<FeatureType>( - {FeatureType::kChromeIntro, FeatureType::kDownload, FeatureType::kSearch, - FeatureType::kVoiceSearch}); - auto new_groups = CreateSampleGroups({"hi", "tl", "ar"}, features); - SaveGroups(std::make_unique<proto::VideoTutorialGroups>(new_groups)); - - languages = manager()->GetSupportedLanguages(); - EXPECT_EQ(languages.size(), 2u); - - GetTutorials(); - EXPECT_EQ(last_results().size(), 2u); -} - -} // namespace - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/tutorial_service_impl.cc b/chrome/browser/video_tutorials/internal/tutorial_service_impl.cc deleted file mode 100644 index a3358ed..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_service_impl.cc +++ /dev/null
@@ -1,144 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/tutorial_service_impl.h" - -#include <utility> - -#include "base/functional/bind.h" -#include "base/functional/callback_helpers.h" -#include "base/strings/string_util.h" -#include "base/task/single_thread_task_runner.h" -#include "chrome/browser/video_tutorials/internal/config.h" -#include "chrome/browser/video_tutorials/internal/proto_conversions.h" -#include "chrome/browser/video_tutorials/prefs.h" -#include "components/language/core/browser/pref_names.h" - -namespace video_tutorials { - -TutorialServiceImpl::TutorialServiceImpl( - std::unique_ptr<TutorialManager> tutorial_manager, - std::unique_ptr<TutorialFetcher> tutorial_fetcher, - PrefService* pref_service) - : tutorial_manager_(std::move(tutorial_manager)), - tutorial_fetcher_(std::move(tutorial_fetcher)), - pref_service_(pref_service) { - tutorial_manager_->Initialize( - base::BindOnce(&TutorialServiceImpl::OnManagerInitialized, - weak_ptr_factory_.GetWeakPtr())); - pref_change_registrar_.Init(pref_service); - pref_change_registrar_.Add( - language::prefs::kAcceptLanguages, - base::BindRepeating(&TutorialServiceImpl::OnAcceptLanguagesChanged, - weak_ptr_factory_.GetWeakPtr())); -} - -TutorialServiceImpl::~TutorialServiceImpl() = default; - -void TutorialServiceImpl::GetTutorials(MultipleItemCallback callback) { - if (!tutorial_manager_->IsInitialized()) { - MaybeCacheApiCall(base::BindOnce(&TutorialServiceImpl::GetTutorials, - weak_ptr_factory_.GetWeakPtr(), - std::move(callback))); - return; - } - - tutorial_manager_->GetTutorials(std::move(callback)); -} - -void TutorialServiceImpl::GetTutorial(FeatureType feature_type, - SingleItemCallback callback) { - if (!tutorial_manager_->IsInitialized()) { - MaybeCacheApiCall(base::BindOnce(&TutorialServiceImpl::GetTutorial, - weak_ptr_factory_.GetWeakPtr(), - feature_type, std::move(callback))); - return; - } - - tutorial_manager_->GetTutorial(feature_type, std::move(callback)); -} - -void TutorialServiceImpl::StartFetchIfNecessary() { - base::Time last_update_time = pref_service_->GetTime(kLastUpdatedTimeKey); - bool ttl_expired = - ((base::Time::Now() - last_update_time) > Config::GetFetchFrequency()); - std::string accept_languages = - pref_service_->GetString(language::prefs::kAcceptLanguages); - std::string text_locale = tutorial_manager_->GetTextLocale(); - bool locale_match = base::StartsWith(accept_languages, text_locale, - base::CompareCase::INSENSITIVE_ASCII); - bool needs_update = ttl_expired || !locale_match || text_locale.empty(); - if (needs_update) { - tutorial_fetcher_->StartFetchForTutorials(base::BindOnce( - &TutorialServiceImpl::OnFetchFinished, weak_ptr_factory_.GetWeakPtr())); - } -} - -void TutorialServiceImpl::OnManagerInitialized(bool success) { - StartFetchIfNecessary(); - FlushCachedApiCalls(); -} - -void TutorialServiceImpl::OnFetchFinished( - bool success, - std::unique_ptr<std::string> response_body) { - pref_service_->SetTime(kLastUpdatedTimeKey, base::Time::Now()); - - if (!success || !response_body) - return; - - proto::VideoTutorialGroups response_proto; - bool parse_success = response_proto.ParseFromString(*response_body.get()); - if (!parse_success) - return; - - tutorial_manager_->SaveGroups( - std::make_unique<proto::VideoTutorialGroups>(std::move(response_proto))); -} - -void TutorialServiceImpl::OnAcceptLanguagesChanged() { - if (!tutorial_manager_->IsInitialized()) - return; - - std::string accept_languages = - pref_service_->GetString(language::prefs::kAcceptLanguages); - tutorial_fetcher_->OnAcceptLanguagesChanged(accept_languages); - StartFetchIfNecessary(); -} - -void TutorialServiceImpl::MaybeCacheApiCall(base::OnceClosure api_call) { - DCHECK(!tutorial_manager_->IsInitialized()) - << "Only cache API calls before initialization."; - cached_api_calls_.emplace_back(std::move(api_call)); -} - -void TutorialServiceImpl::FlushCachedApiCalls() { - // Flush all cached calls in FIFO sequence. - while (!cached_api_calls_.empty()) { - auto api_call = std::move(cached_api_calls_.front()); - cached_api_calls_.pop_front(); - base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( - FROM_HERE, std::move(api_call)); - } -} - -std::vector<std::string> TutorialServiceImpl::GetSupportedLanguages() { - return tutorial_manager_->GetSupportedLanguages(); -} - -const std::vector<std::string>& -TutorialServiceImpl::GetAvailableLanguagesForTutorial( - FeatureType feature_type) { - return tutorial_manager_->GetAvailableLanguagesForTutorial(feature_type); -} - -absl::optional<std::string> TutorialServiceImpl::GetPreferredLocale() { - return tutorial_manager_->GetPreferredLocale(); -} - -void TutorialServiceImpl::SetPreferredLocale(const std::string& locale) { - tutorial_manager_->SetPreferredLocale(locale); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/tutorial_service_impl.h b/chrome/browser/video_tutorials/internal/tutorial_service_impl.h deleted file mode 100644 index 7ae4ba3..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_service_impl.h +++ /dev/null
@@ -1,68 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_SERVICE_IMPL_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_SERVICE_IMPL_H_ - -#include <deque> - -#include "base/memory/raw_ptr.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/video_tutorials/internal/tutorial_fetcher.h" -#include "chrome/browser/video_tutorials/internal/tutorial_manager.h" -#include "chrome/browser/video_tutorials/video_tutorial_service.h" -#include "components/prefs/pref_change_registrar.h" -#include "components/prefs/pref_service.h" - -namespace video_tutorials { - -class TutorialServiceImpl : public VideoTutorialService { - public: - TutorialServiceImpl(std::unique_ptr<TutorialManager> tutorial_manager, - std::unique_ptr<TutorialFetcher> tutorial_fetcher, - PrefService* pref_service); - ~TutorialServiceImpl() override; - - // TutorialService implementation. - void GetTutorials(MultipleItemCallback callback) override; - void GetTutorial(FeatureType feature_type, - SingleItemCallback callback) override; - std::vector<std::string> GetSupportedLanguages() override; - const std::vector<std::string>& GetAvailableLanguagesForTutorial( - FeatureType feature_type) override; - absl::optional<std::string> GetPreferredLocale() override; - void SetPreferredLocale(const std::string& locale) override; - - private: - // Called at service startup to determine if a network fetch is necessary - // based on the last fetch timestamp. - void StartFetchIfNecessary(); - void OnFetchFinished(bool success, - std::unique_ptr<std::string> response_body); - void OnManagerInitialized(bool success); - void OnAcceptLanguagesChanged(); - void MaybeCacheApiCall(base::OnceClosure api_call); - void FlushCachedApiCalls(); - - // Manages in memory tutorial metadata and coordinates with TutorialStore. - std::unique_ptr<TutorialManager> tutorial_manager_; - - // Fetcher to execute download jobs from Google server. - std::unique_ptr<TutorialFetcher> tutorial_fetcher_; - - // PrefService. - raw_ptr<PrefService> pref_service_; - - // Listens to accept languages changes. - PrefChangeRegistrar pref_change_registrar_; - - // Cached API calls before initialization. - std::deque<base::OnceClosure> cached_api_calls_; - - base::WeakPtrFactory<TutorialServiceImpl> weak_ptr_factory_{this}; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_SERVICE_IMPL_H_
diff --git a/chrome/browser/video_tutorials/internal/tutorial_store.cc b/chrome/browser/video_tutorials/internal/tutorial_store.cc deleted file mode 100644 index 01643e4..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_store.cc +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/tutorial_store.h" - -#include <string> -#include <utility> -#include <vector> - -#include "base/functional/bind.h" -#include "components/leveldb_proto/public/proto_database.h" - -namespace video_tutorials { -namespace { -// The key for the only database entry in the video tutorials database. -constexpr char kDatabaseEntryKey[] = ""; - -} // namespace - -TutorialStore::TutorialStore(TutorialProtoDb db) : db_(std::move(db)) {} - -TutorialStore::~TutorialStore() = default; - -void TutorialStore::InitAndLoad(LoadCallback callback) { - bool initialized = init_success_.has_value() && init_success_.value(); - if (initialized) { - db_->GetEntry(kDatabaseEntryKey, std::move(callback)); - return; - } - - db_->Init(base::BindOnce(&TutorialStore::OnDbInitialized, - weak_ptr_factory_.GetWeakPtr(), - std::move(callback))); -} - -void TutorialStore::Update(const proto::VideoTutorialGroups& entry, - UpdateCallback callback) { - using KeyEntryVector = - std::vector<std::pair<std::string, proto::VideoTutorialGroups>>; - auto entries_to_save = std::make_unique<KeyEntryVector>(); - entries_to_save->emplace_back(kDatabaseEntryKey, entry); - - auto keys_to_remove = std::make_unique<std::vector<std::string>>(); - db_->UpdateEntries(std::move(entries_to_save), std::move(keys_to_remove), - std::move(callback)); -} - -void TutorialStore::OnDbInitialized(LoadCallback callback, - leveldb_proto::Enums::InitStatus status) { - init_success_ = status == leveldb_proto::Enums::InitStatus::kOK; - if (!init_success_) { - std::move(callback).Run(false, nullptr); - return; - } - - db_->GetEntry(kDatabaseEntryKey, std::move(callback)); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/internal/tutorial_store.h b/chrome/browser/video_tutorials/internal/tutorial_store.h deleted file mode 100644 index 48cad13a..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_store.h +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_STORE_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_STORE_H_ - -#include <memory> -#include <utility> - -#include "base/functional/callback.h" -#include "base/memory/weak_ptr.h" -#include "chrome/browser/video_tutorials/internal/proto_conversions.h" -#include "chrome/browser/video_tutorials/internal/store.h" -#include "components/leveldb_proto/public/proto_database.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -namespace video_tutorials { -// Persistence layer for storing the video tutorial metadata. -class TutorialStore : public Store<proto::VideoTutorialGroups> { - public: - using TutorialProtoDb = std::unique_ptr<leveldb_proto::ProtoDatabase< - video_tutorials::proto::VideoTutorialGroups>>; - explicit TutorialStore(TutorialProtoDb db); - ~TutorialStore() override; - - TutorialStore(const TutorialStore& other) = delete; - TutorialStore& operator=(const TutorialStore& other) = delete; - - // Store implementation. - void InitAndLoad(LoadCallback callback) override; - void Update(const proto::VideoTutorialGroups& entry, - UpdateCallback callback) override; - - private: - // Called when the db is initialized. - void OnDbInitialized(LoadCallback callback, - leveldb_proto::Enums::InitStatus status); - - // The underlying database. - TutorialProtoDb db_; - - // The database initialization status. - absl::optional<bool> init_success_; - - base::WeakPtrFactory<TutorialStore> weak_ptr_factory_{this}; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_INTERNAL_TUTORIAL_STORE_H_
diff --git a/chrome/browser/video_tutorials/internal/tutorial_store_unittest.cc b/chrome/browser/video_tutorials/internal/tutorial_store_unittest.cc deleted file mode 100644 index 16bd4a54..0000000 --- a/chrome/browser/video_tutorials/internal/tutorial_store_unittest.cc +++ /dev/null
@@ -1,133 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/internal/tutorial_store.h" - -#include <map> -#include <memory> -#include <string> -#include <utility> - -#include "base/memory/raw_ptr.h" -#include "base/run_loop.h" -#include "base/test/task_environment.h" -#include "components/leveldb_proto/public/proto_database.h" -#include "components/leveldb_proto/testing/fake_db.h" -#include "testing/gtest/include/gtest/gtest.h" - -using leveldb_proto::test::FakeDB; -using InitStatus = leveldb_proto::Enums::InitStatus; - -namespace video_tutorials { -namespace { -constexpr char kDatabaseEntryKey[] = ""; -} // namespace - -class TutorialStoreTest : public testing::Test { - public: - using KeysAndEntries = std::map<std::string, proto::VideoTutorialGroups>; - - TutorialStoreTest() { - auto db = - std::make_unique<FakeDB<proto::VideoTutorialGroups>>(&db_entries_); - db_ = db.get(); - store_ = std::make_unique<TutorialStore>(std::move(db)); - } - ~TutorialStoreTest() override = default; - - TutorialStoreTest(const TutorialStoreTest& other) = delete; - TutorialStoreTest& operator=(const TutorialStoreTest& other) = delete; - - protected: - void LoadEntriesAndVerify(bool load_only, bool expected_success) { - store_->InitAndLoad(base::BindOnce(&TutorialStoreTest::OnEntriesLoaded, - base::Unretained(this), - expected_success)); - if (!load_only) - db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK); - db_->GetCallback(true); - } - - void OnEntriesLoaded( - bool expected_success, - bool success, - std::unique_ptr<proto::VideoTutorialGroups> loaded_data) { - EXPECT_EQ(expected_success, success); - EXPECT_TRUE(loaded_data); - last_load_result_ = std::move(loaded_data); - } - - FakeDB<proto::VideoTutorialGroups>* db() { return db_; } - TutorialStore* store() { return store_.get(); } - - proto::VideoTutorialGroups* last_load_result() { - return last_load_result_.get(); - } - - base::test::TaskEnvironment task_environment_; - std::map<std::string, proto::VideoTutorialGroups> db_entries_; - std::unique_ptr<proto::VideoTutorialGroups> last_load_result_; - raw_ptr<FakeDB<proto::VideoTutorialGroups>> db_{nullptr}; - std::unique_ptr<TutorialStore> store_; -}; - -TEST_F(TutorialStoreTest, InitAndLoad) { - // Initialize database and call InitAndLoad(). - proto::VideoTutorialGroups test_data; - test_data.set_preferred_locale("hi"); - test_data.add_tutorial_groups()->add_tutorials()->set_feature( - proto::FeatureType::DOWNLOAD); - test_data.add_tutorial_groups()->add_tutorials()->set_feature( - proto::FeatureType::SEARCH); - - db_entries_[kDatabaseEntryKey] = test_data; - LoadEntriesAndVerify(false, true); - EXPECT_TRUE(last_load_result()); - EXPECT_EQ(2, last_load_result()->tutorial_groups_size()); - EXPECT_EQ(proto::FeatureType::DOWNLOAD, - last_load_result()->tutorial_groups(0).tutorials(0).feature()); - - // Modify the database, and call Load(). - test_data.add_tutorial_groups()->add_tutorials()->set_feature( - proto::FeatureType::VOICE_SEARCH); - db_entries_[kDatabaseEntryKey] = test_data; - LoadEntriesAndVerify(true, true); - EXPECT_TRUE(last_load_result()); - EXPECT_EQ(3, last_load_result()->tutorial_groups_size()); - EXPECT_EQ(proto::FeatureType::VOICE_SEARCH, - last_load_result()->tutorial_groups(2).tutorials(0).feature()); -} - -TEST_F(TutorialStoreTest, Update) { - // Initialize database with no data. - proto::VideoTutorialGroups test_data; - db_entries_[kDatabaseEntryKey] = test_data; - LoadEntriesAndVerify(false, true); - EXPECT_TRUE(last_load_result()); - EXPECT_EQ(0, last_load_result()->tutorial_groups_size()); - - // Add a tutorial group and update. - test_data.add_tutorial_groups()->add_tutorials()->set_feature( - proto::FeatureType::SEARCH); - store()->Update(test_data, - base::BindOnce([](bool success) { EXPECT_TRUE(success); })); - db()->UpdateCallback(true); - - LoadEntriesAndVerify(true, true); - EXPECT_TRUE(last_load_result()); - EXPECT_EQ(1, last_load_result()->tutorial_groups_size()); - EXPECT_EQ(proto::FeatureType::SEARCH, - last_load_result()->tutorial_groups(0).tutorials(0).feature()); - - // Clear data and update. - store()->Update(proto::VideoTutorialGroups(), - base::BindOnce([](bool success) { EXPECT_TRUE(success); })); - db()->UpdateCallback(true); - - LoadEntriesAndVerify(true, true); - EXPECT_TRUE(last_load_result()); - EXPECT_EQ(0, last_load_result()->tutorial_groups_size()); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/prefs.cc b/chrome/browser/video_tutorials/prefs.cc deleted file mode 100644 index 5ee762c..0000000 --- a/chrome/browser/video_tutorials/prefs.cc +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/prefs.h" - -#include "components/prefs/pref_registry_simple.h" -#include "components/prefs/pref_service.h" - -namespace video_tutorials { - -constexpr char kPreferredLocaleKey[] = "video_tutorials.perferred_locale"; - -constexpr char kLastUpdatedTimeKey[] = "video_tutorials.last_updated_time"; - -void RegisterPrefs(PrefRegistrySimple* registry) { - registry->RegisterStringPref(kPreferredLocaleKey, std::string()); - registry->RegisterTimePref(kLastUpdatedTimeKey, base::Time()); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/prefs.h b/chrome/browser/video_tutorials/prefs.h deleted file mode 100644 index 1c2814b..0000000 --- a/chrome/browser/video_tutorials/prefs.h +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_PREFS_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_PREFS_H_ - - -class PrefRegistrySimple; - -namespace video_tutorials { - -// Key for the locale that user picked in video tutorials service. -extern const char kPreferredLocaleKey[]; - -// Key to record a timestamp when the last update of video tutorials metadata -// happened. -extern const char kLastUpdatedTimeKey[]; - -// Register to prefs service. -void RegisterPrefs(PrefRegistrySimple* registry); - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_PREFS_H_
diff --git a/chrome/browser/video_tutorials/proto/BUILD.gn b/chrome/browser/video_tutorials/proto/BUILD.gn deleted file mode 100644 index 4a1d740..0000000 --- a/chrome/browser/video_tutorials/proto/BUILD.gn +++ /dev/null
@@ -1,9 +0,0 @@ -# Copyright 2020 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import("//third_party/protobuf/proto_library.gni") - -proto_library("proto") { - sources = [ "video_tutorials.proto" ] -}
diff --git a/chrome/browser/video_tutorials/proto/video_tutorials.proto b/chrome/browser/video_tutorials/proto/video_tutorials.proto deleted file mode 100644 index c72b19c6..0000000 --- a/chrome/browser/video_tutorials/proto/video_tutorials.proto +++ /dev/null
@@ -1,76 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -syntax = "proto3"; - -option optimize_for = LITE_RUNTIME; - -package video_tutorials.proto; - -// Represents the feature where the video tutorial targeted to. -enum FeatureType { - INVALID = 0; - SUMMARY = 1; - CHROME_INTRO = 2; - DOWNLOAD = 3; - SEARCH = 4; - VOICE_SEARCH = 5; - // For test only. - TEST = 9999999; -} - -// A group of video tutorials with same language. -message VideoTutorialGroup { - // Language of the video. Only used for the video. Not used for the title - // text. - string language = 1; - - // A list of video tutorials metadata. - repeated VideoTutorial tutorials = 2; -} - -// Metadata of a video tutorial. -message VideoTutorial { - // Type of feature where this video tutorial targeted. - FeatureType feature = 1; - - // The user visible description of this video tutorial. - // This string will be in the system language set by the user. - string title = 2; - - // The complete URL for the video. - string video_url = 3; - - // The URL of the video for sharing. - string share_url = 4; - - // The URL of the video poster. Shown while the video is loading in the - // player. - string poster_url = 5; - - // The URL of this video's caption. - string caption_url = 6; - - // Duration of the video in seconds. - int64 video_length = 7; - - // The URL of the animated thumbnail. Shown in the IPH cards. - string animated_gif_url = 8; - - // The URL of the thumbnail image. Shown in the video list. - string thumbnail_url = 9; -} - -// Response from the server containing tutorial groups for all languages. -message VideoTutorialGroups { - // Tutorials in all available languages. - repeated VideoTutorialGroup tutorial_groups = 1; - - // The locale used to show the title text. - string text_locale = 2; - - // The preferred locale for watching the video. This is not obtained from - // the server, and is saved on client side based on the user selection. - string preferred_locale = 3; -} \ No newline at end of file
diff --git a/chrome/browser/video_tutorials/switches.cc b/chrome/browser/video_tutorials/switches.cc deleted file mode 100644 index 24882cedb..0000000 --- a/chrome/browser/video_tutorials/switches.cc +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/switches.h" - -namespace video_tutorials { -namespace features { - -BASE_FEATURE(kVideoTutorials, - "VideoTutorials", - base::FEATURE_DISABLED_BY_DEFAULT); - -} // namespace features -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/switches.h b/chrome/browser/video_tutorials/switches.h deleted file mode 100644 index 0111045..0000000 --- a/chrome/browser/video_tutorials/switches.h +++ /dev/null
@@ -1,19 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_SWITCHES_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_SWITCHES_H_ - -#include "base/feature_list.h" - -namespace video_tutorials { -namespace features { - -// Main feature flag for the video tutorials feature. -BASE_DECLARE_FEATURE(kVideoTutorials); - -} // namespace features -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_SWITCHES_H_
diff --git a/chrome/browser/video_tutorials/test/BUILD.gn b/chrome/browser/video_tutorials/test/BUILD.gn deleted file mode 100644 index fe11865..0000000 --- a/chrome/browser/video_tutorials/test/BUILD.gn +++ /dev/null
@@ -1,23 +0,0 @@ -# Copyright 2020 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -source_set("test_lib") { - testonly = true - - visibility = [ - "//chrome/browser/video_tutorials/internal:unit_tests", - "//chrome/browser/video_tutorials:video_tutorials_unit_tests", - ] - - sources = [ - "test_utils.cc", - "test_utils.h", - ] - - deps = [ - "//chrome/browser/video_tutorials/internal", - "//testing/gmock", - "//testing/gtest", - ] -}
diff --git a/chrome/browser/video_tutorials/test/test_utils.cc b/chrome/browser/video_tutorials/test/test_utils.cc deleted file mode 100644 index fb943b8..0000000 --- a/chrome/browser/video_tutorials/test/test_utils.cc +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/test/test_utils.h" - -namespace video_tutorials { -namespace test { - -const char kTestTitle[] = "Test Title"; - -void BuildTestEntry(Tutorial* entry) { - *entry = Tutorial( - FeatureType::kTest, kTestTitle, "https://www.example.com/video_url", - "https://www.example.com/share_url", "https://www.example.com/poster_url", - "https://www.example.com/animated_gif_url", - "https://www.example.com/thumbnail_url", - "https://www.example.com/caption_url", 60); -} - -void BuildTestGroup(TutorialGroup* group) { - *group = TutorialGroup("en"); - group->tutorials.clear(); - Tutorial entry1; - BuildTestEntry(&entry1); - group->tutorials.emplace_back(entry1); - group->tutorials.emplace_back(entry1); -} - -} // namespace test -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/test/test_utils.h b/chrome/browser/video_tutorials/test/test_utils.h deleted file mode 100644 index 6801e64..0000000 --- a/chrome/browser/video_tutorials/test/test_utils.h +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_TEST_TEST_UTILS_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_TEST_TEST_UTILS_H_ - -#include "chrome/browser/video_tutorials/internal/tutorial_group.h" - -namespace video_tutorials { -namespace test { - -// Build a TutorialGroup filled with fake data for test purpose. -void BuildTestGroup(TutorialGroup* group); - -// Build a Tutorial entry filled with fake data for test purpose. -void BuildTestEntry(Tutorial* entry); - -} // namespace test -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_TEST_TEST_UTILS_H_
diff --git a/chrome/browser/video_tutorials/tutorial.cc b/chrome/browser/video_tutorials/tutorial.cc deleted file mode 100644 index 0bc499d..0000000 --- a/chrome/browser/video_tutorials/tutorial.cc +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/tutorial.h" - -namespace video_tutorials { - -Tutorial::Tutorial() : feature(FeatureType::kInvalid), video_length(0) {} - -Tutorial::Tutorial(FeatureType feature, - const std::string& title, - const std::string& video_url, - const std::string& share_url, - const std::string& poster_url, - const std::string& animated_gif_url, - const std::string& thumbnail_url, - const std::string& caption_url, - int video_length) - : feature(feature), - title(title), - video_url(video_url), - share_url(share_url), - poster_url(poster_url), - animated_gif_url(animated_gif_url), - thumbnail_url(thumbnail_url), - caption_url(caption_url), - video_length(video_length) {} - -bool Tutorial::operator==(const Tutorial& other) const { - return feature == other.feature && title == other.title && - video_url == other.video_url && share_url == other.share_url && - poster_url == other.poster_url && - animated_gif_url == other.animated_gif_url && - thumbnail_url == other.thumbnail_url && - caption_url == other.caption_url && video_length == other.video_length; -} - -bool Tutorial::operator!=(const Tutorial& other) const { - return !(*this == other); -} - -Tutorial::~Tutorial() = default; - -Tutorial::Tutorial(const Tutorial& other) = default; - -Tutorial& Tutorial::operator=(const Tutorial& other) = default; - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/tutorial.h b/chrome/browser/video_tutorials/tutorial.h deleted file mode 100644 index d5159ee86..0000000 --- a/chrome/browser/video_tutorials/tutorial.h +++ /dev/null
@@ -1,83 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_TUTORIAL_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_TUTORIAL_H_ - -#include <string> -#include "base/logging.h" -#include "url/gurl.h" - -namespace video_tutorials { - -// Please align this enum with -// chrome/browser/video_tutorials/proto/video_tutorials.proto and variants -// Feature in -// tools/metrics/histograms/metadata/video_tutorials/histograms.xml. -// A Java counterpart will be generated for this enum. -// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.video_tutorials -enum class FeatureType { - kTest = -1, - kInvalid = 0, - kSummary = 1, - kChromeIntro = 2, - kDownload = 3, - kSearch = 4, - kVoiceSearch = 5, - kMaxValue = kVoiceSearch, -}; - -// In memory struct of a video tutorial entry. -// Represents the metadata required to play a video tutorial. -struct Tutorial { - Tutorial(); - Tutorial(FeatureType feature, - const std::string& title, - const std::string& video_url, - const std::string& share_url, - const std::string& poster_url, - const std::string& animated_gif_url, - const std::string& thumbnail_url, - const std::string& caption_url, - int video_length); - ~Tutorial(); - - bool operator==(const Tutorial& other) const; - bool operator!=(const Tutorial& other) const; - - Tutorial(const Tutorial& other); - Tutorial& operator=(const Tutorial& other); - - // Type of feature where this video tutorial targeted. - FeatureType feature; - - // The title of the video. - std::string title; - - // The URL of the video. - GURL video_url; - - // The share URL for the video. - GURL share_url; - - // The URL of the poster image. Shown while the video is loading in the - // player. - GURL poster_url; - - // The URL of the animated gif image. - GURL animated_gif_url; - - // The URL of the video thumbnail. - GURL thumbnail_url; - - // The URL of the subtitles. - GURL caption_url; - - // The length of the video in seconds. - int video_length; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_TUTORIAL_H_
diff --git a/chrome/browser/video_tutorials/tutorial_factory_helper.cc b/chrome/browser/video_tutorials/tutorial_factory_helper.cc deleted file mode 100644 index b8432d3..0000000 --- a/chrome/browser/video_tutorials/tutorial_factory_helper.cc +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/tutorial_factory_helper.h" - -#include <utility> - -#include "base/task/sequenced_task_runner.h" -#include "base/task/thread_pool.h" -#include "chrome/browser/video_tutorials/internal/config.h" -#include "chrome/browser/video_tutorials/internal/tutorial_fetcher.h" -#include "chrome/browser/video_tutorials/internal/tutorial_manager_impl.h" -#include "chrome/browser/video_tutorials/internal/tutorial_service_impl.h" -#include "chrome/browser/video_tutorials/internal/tutorial_store.h" -#include "components/leveldb_proto/public/proto_database_provider.h" -#include "components/leveldb_proto/public/shared_proto_database_client_list.h" -#include "components/prefs/pref_service.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" - -namespace video_tutorials { -namespace { -const base::FilePath::CharType kVideoTutorialsDbName[] = - FILE_PATH_LITERAL("VideoTutorialsDatabase"); -} // namespace - -std::unique_ptr<VideoTutorialService> CreateVideoTutorialService( - leveldb_proto::ProtoDatabaseProvider* db_provider, - const base::FilePath& storage_dir, - const std::string& accepted_language, - const std::string& country_code, - const std::string& api_key, - const std::string& client_version, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - const std::string& default_server_url, - PrefService* pref_service) { - // Create tutorial store and manager. - auto task_runner = base::ThreadPool::CreateSequencedTaskRunner( - {base::MayBlock(), base::TaskPriority::USER_VISIBLE}); - base::FilePath database_dir = storage_dir.Append(kVideoTutorialsDbName); - auto tutorial_db = - db_provider->GetDB<video_tutorials::proto::VideoTutorialGroups>( - leveldb_proto::ProtoDbType::VIDEO_TUTORIALS_V2_DATABASE, database_dir, - task_runner); - auto tutorial_store = std::make_unique<TutorialStore>(std::move(tutorial_db)); - auto tutorial_manager = std::make_unique<TutorialManagerImpl>( - std::move(tutorial_store), pref_service); - - // Create fetcher. - auto fetcher = TutorialFetcher::Create( - Config::GetTutorialsServerURL(default_server_url), country_code, - accepted_language, api_key, Config::GetExperimentTag(), client_version, - url_loader_factory); - - auto tutorial_service_impl = std::make_unique<TutorialServiceImpl>( - std::move(tutorial_manager), std::move(fetcher), pref_service); - return std::move(tutorial_service_impl); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/tutorial_factory_helper.h b/chrome/browser/video_tutorials/tutorial_factory_helper.h deleted file mode 100644 index f34728a..0000000 --- a/chrome/browser/video_tutorials/tutorial_factory_helper.h +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_TUTORIAL_FACTORY_HELPER_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_TUTORIAL_FACTORY_HELPER_H_ - -#include <memory> -#include <string> - -#include "base/files/file_path.h" -#include "base/memory/scoped_refptr.h" - -namespace leveldb_proto { -class ProtoDatabaseProvider; -} // namespace leveldb_proto - -namespace network { -class SharedURLLoaderFactory; -} // namespace network - -class PrefService; - -namespace video_tutorials { - -class VideoTutorialService; - -std::unique_ptr<VideoTutorialService> CreateVideoTutorialService( - leveldb_proto::ProtoDatabaseProvider* db_provider, - const base::FilePath& storage_dir, - const std::string& accepted_language, - const std::string& country_code, - const std::string& api_key, - const std::string& client_version, - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - const std::string& default_server_url, - PrefService* pref_service); - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_TUTORIAL_FACTORY_HELPER_H_
diff --git a/chrome/browser/video_tutorials/tutorial_unittest.cc b/chrome/browser/video_tutorials/tutorial_unittest.cc deleted file mode 100644 index abfe0fe..0000000 --- a/chrome/browser/video_tutorials/tutorial_unittest.cc +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/tutorial.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace video_tutorials { -namespace { - -const char kTestTitle[] = "Test Title"; -const char kTestURL[] = "https://www.example.com"; - -void ResetTutorialEntry(Tutorial* entry) { - *entry = Tutorial(FeatureType::kTest, kTestTitle, kTestURL, kTestURL, - kTestURL, kTestURL, kTestURL, kTestURL, 60); -} - -// Verify the copy/assign and compare operators for Tutorial struct. -TEST(VideoTutorialsTest, CopyAndCompareOperators) { - Tutorial lhs, rhs; - ResetTutorialEntry(&lhs); - ResetTutorialEntry(&rhs); - EXPECT_EQ(lhs, rhs); - - rhs.title = "changed"; - EXPECT_NE(lhs, rhs); - ResetTutorialEntry(&rhs); - - rhs.feature = FeatureType::kDownload; - EXPECT_NE(lhs, rhs); - ResetTutorialEntry(&rhs); - - rhs.video_url = GURL("changed"); - EXPECT_NE(lhs, rhs); - ResetTutorialEntry(&rhs); - - rhs.share_url = GURL("changed"); - EXPECT_NE(lhs, rhs); - ResetTutorialEntry(&rhs); - - rhs.poster_url = GURL("changed"); - EXPECT_NE(lhs, rhs); - ResetTutorialEntry(&rhs); - - rhs.caption_url = GURL("changed"); - EXPECT_NE(lhs, rhs); - ResetTutorialEntry(&rhs); - - rhs.video_length++; - EXPECT_NE(lhs, rhs); -} - -} // namespace -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/video_tutorial_service.h b/chrome/browser/video_tutorials/video_tutorial_service.h deleted file mode 100644 index bd2510a1..0000000 --- a/chrome/browser/video_tutorials/video_tutorial_service.h +++ /dev/null
@@ -1,57 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_VIDEO_TUTORIAL_SERVICE_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_VIDEO_TUTORIAL_SERVICE_H_ - -#include <string> -#include <vector> - -#include "base/functional/callback.h" -#include "base/supports_user_data.h" -#include "chrome/browser/video_tutorials/tutorial.h" -#include "components/keyed_service/core/keyed_service.h" -#include "third_party/abseil-cpp/absl/types/optional.h" - -namespace video_tutorials { - -using TutorialList = std::vector<Tutorial>; -using MultipleItemCallback = base::OnceCallback<void(std::vector<Tutorial>)>; -using SingleItemCallback = base::OnceCallback<void(absl::optional<Tutorial>)>; - -// The central class on chrome client responsible for managing, storing, and -// serving video tutorials in chrome. -class VideoTutorialService : public KeyedService, - public base::SupportsUserData { - public: - // Called to retrieve all the tutorials. - virtual void GetTutorials(MultipleItemCallback callback) = 0; - - // Called to retrieve the tutorial associated with |feature_type|. - virtual void GetTutorial(FeatureType feature_type, - SingleItemCallback callback) = 0; - - // Called to retrieve all the supported locales. - virtual std::vector<std::string> GetSupportedLanguages() = 0; - - // Returns a list of languages in which a given tutorial is available. - virtual const std::vector<std::string>& GetAvailableLanguagesForTutorial( - FeatureType feature_type) = 0; - - // Called to retrieve the preferred locale, if it is set by the user. - virtual absl::optional<std::string> GetPreferredLocale() = 0; - - // Called to set the preferred locale. - virtual void SetPreferredLocale(const std::string& locale) = 0; - - VideoTutorialService() = default; - ~VideoTutorialService() override = default; - - VideoTutorialService(const VideoTutorialService&) = delete; - VideoTutorialService& operator=(const VideoTutorialService&) = delete; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_VIDEO_TUTORIAL_SERVICE_H_
diff --git a/chrome/browser/video_tutorials/video_tutorial_service_factory.cc b/chrome/browser/video_tutorials/video_tutorial_service_factory.cc deleted file mode 100644 index 1883ecab..0000000 --- a/chrome/browser/video_tutorials/video_tutorial_service_factory.cc +++ /dev/null
@@ -1,122 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/video_tutorial_service_factory.h" - -#include "base/memory/singleton.h" -#include "base/strings/stringprintf.h" -#include "build/build_config.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/image_fetcher/image_fetcher_service_factory.h" -#include "chrome/browser/net/system_network_context_manager.h" -#include "chrome/browser/profiles/profile_key.h" -#include "chrome/browser/video_tutorials/tutorial_factory_helper.h" -#include "chrome/common/channel_info.h" -#include "chrome/common/chrome_constants.h" -#include "components/background_task_scheduler/background_task_scheduler_factory.h" -#include "components/keyed_service/core/simple_dependency_manager.h" -#include "components/language/core/browser/locale_util.h" -#include "components/language/core/browser/pref_names.h" -#include "components/prefs/pref_service.h" -#include "components/variations/service/variations_service.h" -#include "components/version_info/version_info.h" -#include "google_apis/google_api_keys.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" - -#if BUILDFLAG(IS_ANDROID) -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "base/android/scoped_java_ref.h" -#include "chrome/android/chrome_jni_headers/VideoTutorialsServiceUtils_jni.h" -#endif - -namespace video_tutorials { -namespace { - -std::string GetCountryCode() { - std::string country_code; - auto* variations_service = g_browser_process->variations_service(); - if (variations_service) { - country_code = variations_service->GetStoredPermanentCountry(); - if (!country_code.empty()) - return country_code; - country_code = variations_service->GetLatestCountry(); - } - return country_code; -} - -std::string GetGoogleAPIKey() { - bool is_stable_channel = - chrome::GetChannel() == version_info::Channel::STABLE; - return is_stable_channel ? google_apis::GetAPIKey() - : google_apis::GetNonStableAPIKey(); -} - -std::string GetDefaultServerUrl() { - std::string default_server_url; -#if BUILDFLAG(IS_ANDROID) - JNIEnv* env = base::android::AttachCurrentThread(); - base::android::ScopedJavaLocalRef<jstring> j_server_url = - Java_VideoTutorialsServiceUtils_getDefaultServerUrl(env); - default_server_url = - base::android::ConvertJavaStringToUTF8(env, j_server_url); -#endif - return default_server_url; -} - -} // namespace - -// static -VideoTutorialServiceFactory* VideoTutorialServiceFactory::GetInstance() { - return base::Singleton<VideoTutorialServiceFactory>::get(); -} - -// static -VideoTutorialService* VideoTutorialServiceFactory::GetForKey( - SimpleFactoryKey* key) { - return static_cast<VideoTutorialService*>( - GetInstance()->GetServiceForKey(key, /*create=*/true)); -} - -VideoTutorialServiceFactory::VideoTutorialServiceFactory() - : SimpleKeyedServiceFactory("VideoTutorialService", - SimpleDependencyManager::GetInstance()) { - DependsOn(ImageFetcherServiceFactory::GetInstance()); - DependsOn(background_task::BackgroundTaskSchedulerFactory::GetInstance()); -} - -std::unique_ptr<KeyedService> -VideoTutorialServiceFactory::BuildServiceInstanceFor( - SimpleFactoryKey* key) const { - auto* db_provider = - ProfileKey::FromSimpleFactoryKey(key)->GetProtoDatabaseProvider(); - // |storage_dir| is not actually used since we are using the shared leveldb. - base::FilePath storage_dir = - ProfileKey::FromSimpleFactoryKey(key)->GetPath().Append( - chrome::kVideoTutorialsStorageDirname); - - std::string accept_languanges = - ProfileKey::FromSimpleFactoryKey(key)->GetPrefs()->GetString( - language::prefs::kAcceptLanguages); - - auto url_loader_factory = - SystemNetworkContextManager::GetInstance()->GetSharedURLLoaderFactory(); - - base::Version version = version_info::GetVersion(); - std::string channel_name = - chrome::GetChannelName(chrome::WithExtendedStable(true)); - std::string client_version = - base::StringPrintf("%d.%d.%d.%s.chrome", - version.components()[0], // Major - version.components()[2], // Build - version.components()[3], // Patch - channel_name.c_str()); - - return CreateVideoTutorialService( - db_provider, storage_dir, accept_languanges, GetCountryCode(), - GetGoogleAPIKey(), client_version, url_loader_factory, - GetDefaultServerUrl(), ProfileKey::FromSimpleFactoryKey(key)->GetPrefs()); -} - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/video_tutorial_service_factory.h b/chrome/browser/video_tutorials/video_tutorial_service_factory.h deleted file mode 100644 index ad0d00c..0000000 --- a/chrome/browser/video_tutorials/video_tutorial_service_factory.h +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_VIDEO_TUTORIAL_SERVICE_FACTORY_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_VIDEO_TUTORIAL_SERVICE_FACTORY_H_ - -#include <memory> - -#include "chrome/browser/video_tutorials/video_tutorial_service.h" -#include "components/keyed_service/core/simple_keyed_service_factory.h" - -namespace base { -template <typename T> -struct DefaultSingletonTraits; -} // namespace base - -namespace video_tutorials { - -class VideoTutorialService; - -// A factory to create one unique VideoTutorialService. -class VideoTutorialServiceFactory : public SimpleKeyedServiceFactory { - public: - static VideoTutorialServiceFactory* GetInstance(); - static VideoTutorialService* GetForKey(SimpleFactoryKey* key); - - private: - friend struct base::DefaultSingletonTraits<VideoTutorialServiceFactory>; - - VideoTutorialServiceFactory(); - ~VideoTutorialServiceFactory() override = default; - - std::unique_ptr<KeyedService> BuildServiceInstanceFor( - SimpleFactoryKey* key) const override; -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_VIDEO_TUTORIAL_SERVICE_FACTORY_H_
diff --git a/chrome/browser/video_tutorials/video_tutorial_tab_helper.cc b/chrome/browser/video_tutorials/video_tutorial_tab_helper.cc deleted file mode 100644 index 09b22eb..0000000 --- a/chrome/browser/video_tutorials/video_tutorial_tab_helper.cc +++ /dev/null
@@ -1,49 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/video_tutorials/video_tutorial_tab_helper.h" - -#include "build/build_config.h" -#include "content/public/browser/navigation_handle.h" -#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h" -#include "third_party/blink/public/mojom/autoplay/autoplay.mojom.h" - -namespace video_tutorials { -namespace { - -// Returns whether the URL of the navigation matches the video player URL. -bool IsVideoPlayerURL(GURL url) { -#if BUILDFLAG(IS_ANDROID) - std::string url_string = url.possibly_invalid_spec(); - if (url_string.find(chrome::kChromeUIUntrustedVideoPlayerUrl) == 0) - return true; -#endif - return false; -} - -} // namespace - -VideoTutorialTabHelper::VideoTutorialTabHelper( - content::WebContents* web_contents) - : content::WebContentsObserver(web_contents), - content::WebContentsUserData<VideoTutorialTabHelper>(*web_contents) {} - -VideoTutorialTabHelper::~VideoTutorialTabHelper() = default; - -void VideoTutorialTabHelper::ReadyToCommitNavigation( - content::NavigationHandle* handle) { - std::string url = handle->GetURL().possibly_invalid_spec(); - if (!IsVideoPlayerURL(handle->GetURL())) - return; - - mojo::AssociatedRemote<blink::mojom::AutoplayConfigurationClient> client; - handle->GetRenderFrameHost()->GetRemoteAssociatedInterfaces()->GetInterface( - &client); - client->AddAutoplayFlags(url::Origin::Create(handle->GetURL()), - blink::mojom::kAutoplayFlagUserException); -} - -WEB_CONTENTS_USER_DATA_KEY_IMPL(VideoTutorialTabHelper); - -} // namespace video_tutorials
diff --git a/chrome/browser/video_tutorials/video_tutorial_tab_helper.h b/chrome/browser/video_tutorials/video_tutorial_tab_helper.h deleted file mode 100644 index ffb37e8..0000000 --- a/chrome/browser/video_tutorials/video_tutorial_tab_helper.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright 2020 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_VIDEO_TUTORIALS_VIDEO_TUTORIAL_TAB_HELPER_H_ -#define CHROME_BROWSER_VIDEO_TUTORIALS_VIDEO_TUTORIAL_TAB_HELPER_H_ - -#include "chrome/common/webui_url_constants.h" -#include "content/public/browser/web_contents_observer.h" -#include "content/public/browser/web_contents_user_data.h" - -namespace video_tutorials { - -class VideoTutorialTabHelper - : public content::WebContentsObserver, - public content::WebContentsUserData<VideoTutorialTabHelper> { - public: - ~VideoTutorialTabHelper() override; - VideoTutorialTabHelper(const VideoTutorialTabHelper&) = delete; - VideoTutorialTabHelper& operator=(const VideoTutorialTabHelper&) = delete; - - // content::WebContentsObserver overrides. - void ReadyToCommitNavigation(content::NavigationHandle* handle) override; - - private: - friend class content::WebContentsUserData<VideoTutorialTabHelper>; - - explicit VideoTutorialTabHelper(content::WebContents* web_contents); - - WEB_CONTENTS_USER_DATA_KEY_DECL(); -}; - -} // namespace video_tutorials - -#endif // CHROME_BROWSER_VIDEO_TUTORIALS_VIDEO_TUTORIAL_TAB_HELPER_H_
diff --git a/chrome/browser/vr/test/webxr_vr_browser_test.cc b/chrome/browser/vr/test/webxr_vr_browser_test.cc index 39f3d7b..ed8aacd 100644 --- a/chrome/browser/vr/test/webxr_vr_browser_test.cc +++ b/chrome/browser/vr/test/webxr_vr_browser_test.cc
@@ -33,7 +33,7 @@ GetPermissionRequestManager()->set_auto_response_for_test( permission_auto_response_); - // ExecuteScript runs with a user gesture, so we can just directly call + // ExecJs runs with a user gesture, so we can just directly call // requestSession instead of having to do the hacky workaround the // instrumentation tests use of actually sending a click event to the canvas. RunJavaScriptOrFail("onRequestSession()", web_contents);
diff --git a/chrome/browser/vr/test/xr_browser_test.cc b/chrome/browser/vr/test/xr_browser_test.cc index 3f5d11b..8ffa605 100644 --- a/chrome/browser/vr/test/xr_browser_test.cc +++ b/chrome/browser/vr/test/xr_browser_test.cc
@@ -206,7 +206,7 @@ return; } - ASSERT_TRUE(content::ExecuteScript(web_contents, js_expression)) + ASSERT_TRUE(content::ExecJs(web_contents, js_expression)) << "Failed to run given JavaScript: " << js_expression; }
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn index 7808e21..7951201a 100644 --- a/chrome/browser/web_applications/BUILD.gn +++ b/chrome/browser/web_applications/BUILD.gn
@@ -69,6 +69,8 @@ "file_utils_wrapper.h", "install_bounce_metric.cc", "install_bounce_metric.h", + "isolated_web_apps/error/uma_logging.cc", + "isolated_web_apps/error/uma_logging.h", "isolated_web_apps/get_isolated_web_app_browsing_data_command.cc", "isolated_web_apps/get_isolated_web_app_browsing_data_command.h", "isolated_web_apps/install_isolated_web_app_command.cc", @@ -616,6 +618,7 @@ "external_install_options_unittest.cc", "externally_managed_app_manager_impl_unittest.cc", "externally_managed_app_manager_unittest.cc", + "isolated_web_apps/error/uma_logging_unittest.cc", "isolated_web_apps/install_isolated_web_app_command_unittest.cc", "isolated_web_apps/install_isolated_web_app_from_command_line_unittest.cc", "isolated_web_apps/isolated_web_app_dev_mode_unittest.cc",
diff --git a/chrome/browser/web_applications/isolated_web_apps/error/uma_logging.cc b/chrome/browser/web_applications/isolated_web_apps/error/uma_logging.cc new file mode 100644 index 0000000..da07a80 --- /dev/null +++ b/chrome/browser/web_applications/isolated_web_apps/error/uma_logging.cc
@@ -0,0 +1,20 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h" + +namespace web_app { +namespace { +const char kUmaSuccessSuffix[] = "Success"; +const char kUmaErrorSuffix[] = "Error"; +} // namespace + +std::string ToSuccessHistogramName(base::StringPiece base_name) { + return base::StrCat({base_name, kUmaSuccessSuffix}); +} + +std::string ToErrorHistogramName(base::StringPiece base_name) { + return base::StrCat({base_name, kUmaErrorSuffix}); +} +} // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h b/chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h new file mode 100644 index 0000000..a37d1e5b --- /dev/null +++ b/chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h
@@ -0,0 +1,48 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_ERROR_UMA_LOGGING_H_ +#define CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_ERROR_UMA_LOGGING_H_ + +#include "base/metrics/histogram_functions.h" +#include "base/strings/strcat.h" +#include "base/strings/string_piece.h" +#include "base/types/expected.h" + +namespace web_app { + +// Every error type that is logged by the UmaLogExpectedStatus function should +// be converted to a UMA-friendly enumeration. This function is an +// implementation for the case when the error type is enumeration. +template <class E> +E ToErrorEnum(E e) { + static_assert(std::is_enum<E>::value, "E is not an enum."); + return e; +} + +// These functions return the names of the histograms where the +// wrapped in base::expected<> error are logged. +std::string ToSuccessHistogramName(base::StringPiece base_name); +std::string ToErrorHistogramName(base::StringPiece base_name); + +// UMA-logs an error wrapped in base::expected<void, ErrorType>. It creates +// 2 histograms by appending corresponding suffixes to `base_name`. +// One histogram logs the success/failure rate. The other histogram logs +// the error type if any. +// Any custom error type should provide a specialized template function that +// converts the custom error type to error enum. +template <class E> +void UmaLogExpectedStatus(base::StringPiece base_name, + const base::expected<void, E>& status) { + base::UmaHistogramBoolean(ToSuccessHistogramName(base_name), + status.has_value()); + + if (!status.has_value()) { + base::UmaHistogramEnumeration(ToErrorHistogramName(base_name), + ToErrorEnum(status.error())); + } +} + +} // namespace web_app +#endif // CHROME_BROWSER_WEB_APPLICATIONS_ISOLATED_WEB_APPS_ERROR_UMA_LOGGING_H_
diff --git a/chrome/browser/web_applications/isolated_web_apps/error/uma_logging_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/error/uma_logging_unittest.cc new file mode 100644 index 0000000..0bea5ca2 --- /dev/null +++ b/chrome/browser/web_applications/isolated_web_apps/error/uma_logging_unittest.cc
@@ -0,0 +1,112 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h" +#include <string> + +#include "base/metrics/histogram_functions.h" +#include "base/strings/strcat.h" +#include "base/strings/string_piece.h" +#include "base/test/metrics/histogram_tester.h" +#include "base/types/expected.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace web_app { + +namespace { +enum class TestingErrorEnum { kFirst = 0, kSecond = 1, kMaxValue = kSecond }; + +struct CustomErrorType { + std::string message; + TestingErrorEnum error_enum; +}; + +TestingErrorEnum ToErrorEnum(CustomErrorType custom_error) { + return custom_error.error_enum; +} +} // namespace + +// Testing wrapped in base::expected enumeration. +TEST(IsolatedWebAppUmaExpectedLog, Enumeration) { + const std::string histogram_base_name("Testing.UMA.ExpectedEnumeration"); + const std::string error_histogram = ToErrorHistogramName(histogram_base_name); + const std::string success_histogram = + ToSuccessHistogramName(histogram_base_name); + const base::HistogramTester tester; + + // Log an error. + const base::expected<void, TestingErrorEnum> status_error_1 = + base::unexpected(TestingErrorEnum::kFirst); + UmaLogExpectedStatus(histogram_base_name, status_error_1); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kFirst), 1); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kSecond), 0); + tester.ExpectBucketCount(success_histogram, 0, 1); + tester.ExpectBucketCount(success_histogram, 1, 0); + + // Log the same error one more time. + UmaLogExpectedStatus(histogram_base_name, status_error_1); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kFirst), 2); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kSecond), 0); + tester.ExpectBucketCount(success_histogram, 0, 2); + tester.ExpectBucketCount(success_histogram, 1, 0); + + // Log another error. + const base::expected<void, TestingErrorEnum> status_error_2 = + base::unexpected(TestingErrorEnum::kSecond); + UmaLogExpectedStatus(histogram_base_name, status_error_2); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kFirst), 2); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kSecond), 1); + tester.ExpectBucketCount(success_histogram, 0, 3); + tester.ExpectBucketCount(success_histogram, 1, 0); + + // Log no error status. + const base::expected<void, TestingErrorEnum> status_ok = base::ok(); + UmaLogExpectedStatus(histogram_base_name, status_ok); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kFirst), 2); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kSecond), 1); + tester.ExpectBucketCount(success_histogram, 0, 3); + tester.ExpectBucketCount(success_histogram, 1, 1); + + tester.ExpectTotalCount(error_histogram, 3); + tester.ExpectTotalCount(success_histogram, 4); +} + +// Tests of a custom error type wrapped in base::expected. +TEST(IsolatedWebAppUmaExpectedLog, CustomType) { + const std::string histogram_base_name("Testing.UMA.ExpectedCustomType"); + const std::string error_histogram = ToErrorHistogramName(histogram_base_name); + const std::string success_histogram = + ToSuccessHistogramName(histogram_base_name); + const base::HistogramTester tester; + + const base::expected<void, CustomErrorType> status_error_1 = + base::unexpected(CustomErrorType{.message = "msg1", + .error_enum = TestingErrorEnum::kFirst}); + UmaLogExpectedStatus(histogram_base_name, status_error_1); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kFirst), 1); + tester.ExpectBucketCount(success_histogram, 0, 1); + + const base::expected<void, CustomErrorType> status_ok = base::ok(); + UmaLogExpectedStatus(histogram_base_name, status_ok); + tester.ExpectBucketCount(error_histogram, + static_cast<int>(TestingErrorEnum::kFirst), 1); + tester.ExpectBucketCount(success_histogram, 0, 1); + tester.ExpectBucketCount(success_histogram, 1, 1); +} + +TEST(IsolatedWebAppUmaExpectedLog, HistogramNaming) { + EXPECT_EQ(ToErrorHistogramName("Hist.Base.Name"), "Hist.Base.NameError"); + EXPECT_EQ(ToSuccessHistogramName("Hist.Base.Name"), "Hist.Base.NameSuccess"); +} + +} // namespace web_app
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc index 5e4e90f..e5d1be1 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.cc
@@ -15,6 +15,8 @@ #include "base/strings/strcat.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" +#include "base/types/expected.h" +#include "chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h" #include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h" @@ -44,6 +46,29 @@ // respect `kCleanupInterval`, but this feels like unnecessary overhead. base::TimeDelta kCleanupInterval = base::Minutes(10); +base::expected<void, IsolatedWebAppReaderRegistry::ReadResponseHeadError> +ToReadResponseHeadError( + const base::expected<IsolatedWebAppResponseReader::Response, + IsolatedWebAppResponseReader::Error>& response) { + if (response.has_value()) { + return base::ok(); + } + switch (response.error().type) { + case IsolatedWebAppResponseReader::Error::Type::kParserInternalError: + return base::unexpected( + IsolatedWebAppReaderRegistry::ReadResponseHeadError:: + kResponseHeadParserInternalError); + case IsolatedWebAppResponseReader::Error::Type::kFormatError: + return base::unexpected( + IsolatedWebAppReaderRegistry::ReadResponseHeadError:: + kResponseHeadParserFormatError); + case IsolatedWebAppResponseReader::Error::Type::kResponseNotFound: + return base::unexpected( + IsolatedWebAppReaderRegistry::ReadResponseHeadError:: + kResponseNotFoundError); + } +} + } // namespace IsolatedWebAppReaderRegistry::IsolatedWebAppReaderRegistry( @@ -197,10 +222,9 @@ ReadResponseCallback callback, base::expected<IsolatedWebAppResponseReader::Response, IsolatedWebAppResponseReader::Error> response) { - base::UmaHistogramEnumeration("WebApp.Isolated.ReadResponseHeadStatus", - response.has_value() - ? ReadResponseHeadStatus::kSuccess - : GetStatusFromError(response.error())); + base::expected<void, IsolatedWebAppReaderRegistry::ReadResponseHeadError> + response_status = ToReadResponseHeadError(response); + UmaLogExpectedStatus("WebApp.Isolated.ReadResponseHead", response_status); std::move(callback).Run(std::move(response).transform_error( static_cast<ReadResponseError (*)( @@ -208,19 +232,6 @@ &ReadResponseError::ForError))); } -IsolatedWebAppReaderRegistry::ReadResponseHeadStatus -IsolatedWebAppReaderRegistry::GetStatusFromError( - const IsolatedWebAppResponseReader::Error& error) { - switch (error.type) { - case IsolatedWebAppResponseReader::Error::Type::kParserInternalError: - return ReadResponseHeadStatus::kResponseHeadParserInternalError; - case IsolatedWebAppResponseReader::Error::Type::kFormatError: - return ReadResponseHeadStatus::kResponseHeadParserFormatError; - case IsolatedWebAppResponseReader::Error::Type::kResponseNotFound: - return ReadResponseHeadStatus::kResponseNotFoundError; - } -} - // static IsolatedWebAppReaderRegistry::ReadResponseError IsolatedWebAppReaderRegistry::ReadResponseError::ForError(
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h index 4fccb64..6979171 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry.h
@@ -95,8 +95,7 @@ // // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. - enum class ReadResponseHeadStatus { - kSuccess = 0, + enum class ReadResponseHeadError { kResponseHeadParserInternalError = 1, kResponseHeadParserFormatError = 2, kResponseNotFoundError = 3, @@ -122,9 +121,6 @@ base::expected<IsolatedWebAppResponseReader::Response, IsolatedWebAppResponseReader::Error> response); - ReadResponseHeadStatus GetStatusFromError( - const IsolatedWebAppResponseReader::Error& error); - enum class ReaderCacheState; // A thin wrapper around `base::flat_map<base::FilePath, Cache::Entry>` that
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc index 72ed5649..a36f7906 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_reader_registry_unittest.cc
@@ -22,6 +22,7 @@ #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "base/types/expected.h" +#include "chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_trust_checker.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h" @@ -230,10 +231,8 @@ EXPECT_EQ(expected_parser_base_url, on_create_parser_future_.Take()); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppResponseReaderFactory::ReadIntegrityBlockAndMetadataStatus:: - kSuccess, - 1); + ToSuccessHistogramName("WebApp.Isolated.SwbnFileUsability"), + /*success*/ 1, 1); std::string response_body = ReadAndFulfillResponseBody( result->head()->payload_length, @@ -320,8 +319,8 @@ "aaaaaaacaibaaaaaaaaaaaaaaiaaeaaaaaaaaaaaaabaeaqaaaaaaaic/foo"); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadResponseHeadStatus", - IsolatedWebAppReaderRegistry::ReadResponseHeadStatus:: + ToErrorHistogramName("WebApp.Isolated.ReadResponseHead"), + IsolatedWebAppReaderRegistry::ReadResponseHeadError:: kResponseNotFoundError, 1); } @@ -446,10 +445,9 @@ class IsolatedWebAppReaderRegistryIntegrityBlockParserErrorTest : public IsolatedWebAppReaderRegistryTest, - public ::testing::WithParamInterface< - std::pair<web_package::mojom::BundleParseErrorType, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus>> {}; + public ::testing::WithParamInterface<std::pair< + web_package::mojom::BundleParseErrorType, + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError>> {}; TEST_P(IsolatedWebAppReaderRegistryIntegrityBlockParserErrorTest, TestIntegrityBlockParserError) { @@ -474,8 +472,8 @@ "Failed to parse integrity block: test error"); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", GetParam().second, - 1); + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + GetParam().second, 1); } INSTANTIATE_TEST_SUITE_P( @@ -484,17 +482,16 @@ ::testing::Values( std::make_pair( web_package::mojom::BundleParseErrorType::kParserInternalError, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kIntegrityBlockParserInternalError), - std::make_pair(web_package::mojom::BundleParseErrorType::kVersionError, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kIntegrityBlockParserVersionError), - std::make_pair(web_package::mojom::BundleParseErrorType::kFormatError, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kIntegrityBlockParserFormatError))); + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kIntegrityBlockParserInternalError), + std::make_pair( + web_package::mojom::BundleParseErrorType::kVersionError, + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kIntegrityBlockParserVersionError), + std::make_pair( + web_package::mojom::BundleParseErrorType::kFormatError, + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kIntegrityBlockParserFormatError))); TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidIntegrityBlockContents) { base::HistogramTester histogram_tester; @@ -523,8 +520,8 @@ "Failed to validate integrity block: test error"); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppResponseReaderFactory::ReadIntegrityBlockAndMetadataStatus:: + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: kIntegrityBlockValidationError, 1); } @@ -563,10 +560,8 @@ ASSERT_TRUE(read_response_future.Take().has_value()); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppResponseReaderFactory::ReadIntegrityBlockAndMetadataStatus:: - kSuccess, - 1); + ToSuccessHistogramName("WebApp.Isolated.SwbnFileUsability"), + /*success*/ 1, 1); #else ReadResult result = read_response_future.Take(); ASSERT_FALSE(result.has_value()); @@ -576,8 +571,8 @@ GetParam().message.c_str())); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppResponseReaderFactory::ReadIntegrityBlockAndMetadataStatus:: + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: kSignatureVerificationError, 1); #endif // BUILDFLAG(IS_CHROMEOS) @@ -591,10 +586,9 @@ class IsolatedWebAppReaderRegistryMetadataParserErrorTest : public IsolatedWebAppReaderRegistryTest, - public ::testing::WithParamInterface< - std::pair<web_package::mojom::BundleParseErrorType, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus>> {}; + public ::testing::WithParamInterface<std::pair< + web_package::mojom::BundleParseErrorType, + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError>> {}; TEST_P(IsolatedWebAppReaderRegistryMetadataParserErrorTest, TestMetadataParserError) { @@ -620,8 +614,8 @@ EXPECT_EQ(result.error().message, "Failed to parse metadata: test error"); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", GetParam().second, - 1); + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + GetParam().second, 1); } INSTANTIATE_TEST_SUITE_P( @@ -630,17 +624,14 @@ ::testing::Values( std::make_pair( web_package::mojom::BundleParseErrorType::kParserInternalError, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kMetadataParserInternalError), + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kMetadataParserInternalError), std::make_pair(web_package::mojom::BundleParseErrorType::kVersionError, IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kMetadataParserVersionError), + UnusableSwbnFileError::kMetadataParserVersionError), std::make_pair(web_package::mojom::BundleParseErrorType::kFormatError, IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kMetadataParserFormatError))); + UnusableSwbnFileError::kMetadataParserFormatError))); TEST_F(IsolatedWebAppReaderRegistryTest, TestInvalidMetadataPrimaryUrl) { base::HistogramTester histogram_tester; @@ -667,8 +658,8 @@ kUrl.spec().c_str())); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppResponseReaderFactory::ReadIntegrityBlockAndMetadataStatus:: + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: kMetadataValidationError, 1); } @@ -703,7 +694,7 @@ : public IsolatedWebAppReaderRegistryTest, public ::testing::WithParamInterface< std::pair<web_package::mojom::BundleParseErrorType, - IsolatedWebAppReaderRegistry::ReadResponseHeadStatus>> {}; + IsolatedWebAppReaderRegistry::ReadResponseHeadError>> {}; TEST_P(IsolatedWebAppReaderRegistryResponseHeadParserErrorTest, TestResponseHeadParserError) { @@ -733,8 +724,9 @@ EXPECT_EQ(result.error().message, "Failed to parse response head: test error"); - histogram_tester.ExpectBucketCount("WebApp.Isolated.ReadResponseHeadStatus", - GetParam().second, 1); + histogram_tester.ExpectBucketCount( + ToErrorHistogramName("WebApp.Isolated.ReadResponseHead"), + GetParam().second, 1); } INSTANTIATE_TEST_SUITE_P( @@ -743,10 +735,10 @@ ::testing::Values( std::make_pair( web_package::mojom::BundleParseErrorType::kParserInternalError, - IsolatedWebAppReaderRegistry::ReadResponseHeadStatus:: + IsolatedWebAppReaderRegistry::ReadResponseHeadError:: kResponseHeadParserInternalError), std::make_pair(web_package::mojom::BundleParseErrorType::kFormatError, - IsolatedWebAppReaderRegistry::ReadResponseHeadStatus:: + IsolatedWebAppReaderRegistry::ReadResponseHeadError:: kResponseHeadParserFormatError))); TEST_F(IsolatedWebAppReaderRegistryTest, TestConcurrentRequests) {
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc index ad94af61..d4f89ac 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.cc
@@ -11,6 +11,7 @@ #include "base/metrics/histogram_functions.h" #include "base/strings/strcat.h" #include "base/strings/stringprintf.h" +#include "chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h" #include "chrome/browser/web_applications/isolated_web_apps/signed_web_bundle_reader.h" #include "chrome/common/url_constants.h" @@ -145,8 +146,7 @@ read_integrity_block_and_metadata_error) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - absl::optional<std::pair<Error, ReadIntegrityBlockAndMetadataStatus>> - error_and_status; + absl::optional<std::pair<Error, UnusableSwbnFileError>> two_errors; if (read_integrity_block_and_metadata_error.has_value()) { Error error = absl::visit( base::Overloaded{ @@ -161,38 +161,38 @@ -> Error { return error->Clone(); }, }, *read_integrity_block_and_metadata_error); - error_and_status = std::make_pair( + two_errors = std::make_pair( std::move(error), - GetStatusFromError(*read_integrity_block_and_metadata_error)); + ToUnusableSwbnFileError(*read_integrity_block_and_metadata_error)); } - if (!error_and_status.has_value()) { + if (!two_errors.has_value()) { if (auto error_message = validator_->ValidateMetadata( web_bundle_id, reader->GetPrimaryURL(), reader->GetEntries()); !error_message.has_value()) { - error_and_status = std::make_pair( - MetadataError(error_message.error()), - ReadIntegrityBlockAndMetadataStatus::kMetadataValidationError); + two_errors = + std::make_pair(MetadataError(error_message.error()), + UnusableSwbnFileError::kMetadataValidationError); } } - base::UmaHistogramEnumeration( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - error_and_status.has_value() - ? error_and_status->second - : ReadIntegrityBlockAndMetadataStatus::kSuccess); + const base::expected<void, UnusableSwbnFileError> usability_status = + two_errors.has_value() + ? base::expected<void, UnusableSwbnFileError>( + base::unexpected(two_errors->second)) + : base::expected<void, UnusableSwbnFileError>(base::ok()); + UmaLogExpectedStatus("WebApp.Isolated.SwbnFileUsability", usability_status); - if (error_and_status.has_value()) { - std::move(callback).Run( - base::unexpected(std::move(error_and_status->first))); + if (two_errors.has_value()) { + std::move(callback).Run(base::unexpected(std::move(two_errors->first))); return; } std::move(callback).Run( std::make_unique<IsolatedWebAppResponseReader>(std::move(reader))); } -IsolatedWebAppResponseReaderFactory::ReadIntegrityBlockAndMetadataStatus -IsolatedWebAppResponseReaderFactory::GetStatusFromError( +IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError +IsolatedWebAppResponseReaderFactory::ToUnusableSwbnFileError( const SignedWebBundleReader::ReadIntegrityBlockAndMetadataError& error) { return absl::visit( base::Overloaded{ @@ -201,37 +201,30 @@ switch (error->type) { case web_package::mojom::BundleParseErrorType:: kParserInternalError: - return ReadIntegrityBlockAndMetadataStatus:: + return UnusableSwbnFileError:: kIntegrityBlockParserInternalError; case web_package::mojom::BundleParseErrorType::kFormatError: - return ReadIntegrityBlockAndMetadataStatus:: - kIntegrityBlockParserFormatError; + return UnusableSwbnFileError::kIntegrityBlockParserFormatError; case web_package::mojom::BundleParseErrorType::kVersionError: - return ReadIntegrityBlockAndMetadataStatus:: - kIntegrityBlockParserVersionError; + return UnusableSwbnFileError::kIntegrityBlockParserVersionError; } }, [](const SignedWebBundleReader::AbortedByCaller& error) { - return ReadIntegrityBlockAndMetadataStatus:: - kIntegrityBlockValidationError; + return UnusableSwbnFileError::kIntegrityBlockValidationError; }, [](const web_package::SignedWebBundleSignatureVerifier::Error& error) { - return ReadIntegrityBlockAndMetadataStatus:: - kSignatureVerificationError; + return UnusableSwbnFileError::kSignatureVerificationError; }, [](const web_package::mojom::BundleMetadataParseErrorPtr& error) { switch (error->type) { case web_package::mojom::BundleParseErrorType:: kParserInternalError: - return ReadIntegrityBlockAndMetadataStatus:: - kMetadataParserInternalError; + return UnusableSwbnFileError::kMetadataParserInternalError; case web_package::mojom::BundleParseErrorType::kFormatError: - return ReadIntegrityBlockAndMetadataStatus:: - kMetadataParserFormatError; + return UnusableSwbnFileError::kMetadataParserFormatError; case web_package::mojom::BundleParseErrorType::kVersionError: - return ReadIntegrityBlockAndMetadataStatus:: - kMetadataParserVersionError; + return UnusableSwbnFileError::kMetadataParserVersionError; } }}, error);
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h index 77d9747..576a0f9 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory.h
@@ -95,11 +95,11 @@ // This enum represents every error type that can occur during integrity block // and metadata parsing, before responses are read from Signed Web Bundles. + // Any of these errors means that the .swbn file is unusable. // // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. - enum class ReadIntegrityBlockAndMetadataStatus { - kSuccess = 0, + enum class UnusableSwbnFileError { // Integrity Block-related errors kIntegrityBlockParserInternalError = 1, kIntegrityBlockParserFormatError = 2, @@ -141,7 +141,7 @@ absl::optional<SignedWebBundleReader::ReadIntegrityBlockAndMetadataError> read_integrity_block_and_metadata_error); - ReadIntegrityBlockAndMetadataStatus GetStatusFromError( + UnusableSwbnFileError ToUnusableSwbnFileError( const SignedWebBundleReader::ReadIntegrityBlockAndMetadataError& error); std::unique_ptr<IsolatedWebAppValidator> validator_;
diff --git a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory_unittest.cc b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory_unittest.cc index 12d3e6b2..357b946 100644 --- a/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory_unittest.cc +++ b/chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader_factory_unittest.cc
@@ -19,6 +19,7 @@ #include "base/test/task_environment.h" #include "base/test/test_future.h" #include "base/types/expected.h" +#include "chrome/browser/web_applications/isolated_web_apps/error/uma_logging.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_response_reader.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_trust_checker.h" #include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_validator.h" @@ -206,10 +207,9 @@ class IsolatedWebAppResponseReaderFactoryIntegrityBlockParserErrorTest : public IsolatedWebAppResponseReaderFactoryTest, - public ::testing::WithParamInterface< - std::pair<web_package::mojom::BundleParseErrorType, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus>> {}; + public ::testing::WithParamInterface<std::pair< + web_package::mojom::BundleParseErrorType, + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError>> {}; TEST_P(IsolatedWebAppResponseReaderFactoryIntegrityBlockParserErrorTest, TestIntegrityBlockParserError) { @@ -235,8 +235,8 @@ EXPECT_THAT((*actual_error)->message, Eq(error->message)); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", GetParam().second, - 1); + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + GetParam().second, 1); } INSTANTIATE_TEST_SUITE_P( @@ -245,17 +245,16 @@ ::testing::Values( std::make_pair( web_package::mojom::BundleParseErrorType::kParserInternalError, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kIntegrityBlockParserInternalError), - std::make_pair(web_package::mojom::BundleParseErrorType::kVersionError, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kIntegrityBlockParserVersionError), - std::make_pair(web_package::mojom::BundleParseErrorType::kFormatError, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kIntegrityBlockParserFormatError))); + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kIntegrityBlockParserInternalError), + std::make_pair( + web_package::mojom::BundleParseErrorType::kVersionError, + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kIntegrityBlockParserVersionError), + std::make_pair( + web_package::mojom::BundleParseErrorType::kFormatError, + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kIntegrityBlockParserFormatError))); TEST_F(IsolatedWebAppResponseReaderFactoryTest, TestInvalidIntegrityBlockContents) { @@ -283,8 +282,8 @@ EXPECT_THAT(actual_error->message, Eq("test error")); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppResponseReaderFactory::ReadIntegrityBlockAndMetadataStatus:: + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: kIntegrityBlockValidationError, 1); } @@ -332,9 +331,9 @@ EXPECT_TRUE(reader_future.Take().has_value()); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus::kSignatureVerificationError, + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kSignatureVerificationError, 0); } else { ReaderResult result = reader_future.Take(); @@ -346,9 +345,9 @@ EXPECT_THAT(actual_error->message, Eq(error_.message)); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus::kSignatureVerificationError, + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kSignatureVerificationError, 1); } } @@ -365,10 +364,9 @@ class IsolatedWebAppResponseReaderFactoryMetadataParserErrorTest : public IsolatedWebAppResponseReaderFactoryTest, - public ::testing::WithParamInterface< - std::pair<web_package::mojom::BundleParseErrorType, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus>> {}; + public ::testing::WithParamInterface<std::pair< + web_package::mojom::BundleParseErrorType, + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError>> {}; TEST_P(IsolatedWebAppResponseReaderFactoryMetadataParserErrorTest, TestMetadataParserError) { @@ -396,8 +394,8 @@ EXPECT_THAT((*actual_error)->message, Eq(error->message)); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", GetParam().second, - 1); + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + GetParam().second, 1); } INSTANTIATE_TEST_SUITE_P( @@ -406,17 +404,14 @@ ::testing::Values( std::make_pair( web_package::mojom::BundleParseErrorType::kParserInternalError, - IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kMetadataParserInternalError), + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: + kMetadataParserInternalError), std::make_pair(web_package::mojom::BundleParseErrorType::kVersionError, IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kMetadataParserVersionError), + UnusableSwbnFileError::kMetadataParserVersionError), std::make_pair(web_package::mojom::BundleParseErrorType::kFormatError, IsolatedWebAppResponseReaderFactory:: - ReadIntegrityBlockAndMetadataStatus:: - kMetadataParserFormatError))); + UnusableSwbnFileError::kMetadataParserFormatError))); TEST_F(IsolatedWebAppResponseReaderFactoryTest, TestInvalidMetadataPrimaryUrl) { base::HistogramTester histogram_tester; @@ -440,8 +435,8 @@ StartsWith("Primary URL must not be present")); histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppResponseReaderFactory::ReadIntegrityBlockAndMetadataStatus:: + ToErrorHistogramName("WebApp.Isolated.SwbnFileUsability"), + IsolatedWebAppResponseReaderFactory::UnusableSwbnFileError:: kMetadataValidationError, 1); }
diff --git a/chrome/browser/webauthn/passkey_model_factory.cc b/chrome/browser/webauthn/passkey_model_factory.cc index d752b1d6..705cd01 100644 --- a/chrome/browser/webauthn/passkey_model_factory.cc +++ b/chrome/browser/webauthn/passkey_model_factory.cc
@@ -27,7 +27,12 @@ PasskeyModelFactory::PasskeyModelFactory() : ProfileKeyedServiceFactory( "PasskeyModel", - ProfileSelections::BuildRedirectedToOriginal()) { + ProfileSelections::Builder() + .WithRegular(ProfileSelection::kRedirectedToOriginal) + // TODO(crbug.com/1418376): Check if this service is needed in + // Guest mode. + .WithGuest(ProfileSelection::kRedirectedToOriginal) + .Build()) { DependsOn(ModelTypeStoreServiceFactory::GetInstance()); }
diff --git a/chrome/build/lacros64.pgo.txt b/chrome/build/lacros64.pgo.txt index dc76d33..dbbb88b 100644 --- a/chrome/build/lacros64.pgo.txt +++ b/chrome/build/lacros64.pgo.txt
@@ -1 +1 @@ -chrome-chromeos-amd64-generic-main-1683705582-f0fd4a67ea09b45afb5cedeb9b28224c1bd66714.profdata +chrome-chromeos-amd64-generic-main-1683734405-031d4bee674c6cad9058aadeff2409b585f24a9b.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 139d6c5..4df39930 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1683719935-268373f4bced8f6cad2c84a9f1f28054d29ab150.profdata +chrome-mac-arm-main-1683734405-148978d5ad2b145e716104e0f8875becbd83382d.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 5335a88..117c2f5d 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1683707573-36a3a937b1b1f3e52396f9d1812955b1a4aafab1.profdata +chrome-win32-main-1683730120-f26e13d08f2ce32718a6b2c82bae54f809e841c7.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 7470e5b..52eb1c3d 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1683707573-21cb7c61e240d36241a2ec301747587c3a057541.profdata +chrome-win64-main-1683730120-d2b57f29577502d057c3d42f853de23dc94de8b0.profdata
diff --git a/chrome/chrome_elf/third_party_dlls/hook.cc b/chrome/chrome_elf/third_party_dlls/hook.cc index a7657dc9..a94d714a 100644 --- a/chrome/chrome_elf/third_party_dlls/hook.cc +++ b/chrome/chrome_elf/third_party_dlls/hook.cc
@@ -209,6 +209,9 @@ } // Lowercase |image_name|. + const auto tolower = [](auto c) { + return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c; + }; for (size_t i = 0; i < image_name->size(); i++) (*image_name)[i] = tolower((*image_name)[i]); @@ -235,7 +238,7 @@ // Lowercase |section_basename|. for (size_t i = 0; i < temp_section_basename.size(); i++) - temp_section_basename[i] = towlower(temp_section_basename[i]); + temp_section_basename[i] = tolower(temp_section_basename[i]); // Convert section strings from UTF-16 to UTF-8. return UTF16ToUTF8(temp_section_path, section_path) &&
diff --git a/chrome/common/extensions/api/autofill_private.idl b/chrome/common/extensions/api/autofill_private.idl index 4960fe9..bdb5eb7 100644 --- a/chrome/common/extensions/api/autofill_private.idl +++ b/chrome/common/extensions/api/autofill_private.idl
@@ -348,6 +348,10 @@ // it refers to the legacy server id of credit cards, not the instrument // ids. static void removeVirtualCard(DOMString cardId); + + // Authenticates the user via device authentication and if successful, it + // will then flip the mandatory auth toggle. + static void authenticateUserAndFlipMandatoryAuthToggle(); }; interface Events {
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc index 2569cbd2..bb2a2a6 100644 --- a/chrome/common/webui_url_constants.cc +++ b/chrome/common/webui_url_constants.cc
@@ -243,9 +243,6 @@ const char kChromeUINativeNewTabURL[] = "chrome-native://newtab/"; const char kChromeUIOfflineInternalsHost[] = "offline-internals"; const char kChromeUISnippetsInternalsHost[] = "snippets-internals"; -const char kChromeUIUntrustedVideoTutorialsHost[] = "video-tutorials"; -const char kChromeUIUntrustedVideoPlayerUrl[] = - "chrome-untrusted://video-tutorials/"; const char kChromeUIWebApksHost[] = "webapks"; #else const char kChromeUIAppServiceInternalsHost[] = "app-service-internals";
diff --git a/chrome/installer/mac/sign_chrome.py b/chrome/installer/mac/sign_chrome.py index 7b8172ed..ba29722 100755 --- a/chrome/installer/mac/sign_chrome.py +++ b/chrome/installer/mac/sign_chrome.py
@@ -20,7 +20,8 @@ specific certificate hashes. Args: - config_args: List of args to expand to the config class's constructor. + config_args: Dict of args to expand as kwargs to the config class's + constructor. development: Boolean indicating whether or not to modify the chosen config for development testing. @@ -38,6 +39,10 @@ return '' @property + def codesign_requirements_outer_app(self): + return '' + + @property def provisioning_profile_basename(self): return None @@ -137,6 +142,7 @@ choices=model.NotarizeAndStapleLevel.valid_strings(), const='staple', default='none', + type=model.NotarizeAndStapleLevel.from_string, help='Specifies the requested notarization actions to be taken. ' '`none` causes no notarization tasks to be performed. ' '`nowait` submits the signed application and packaging to Apple for ' @@ -154,12 +160,6 @@ args = parser.parse_args() - notarization = model.NotarizeAndStapleLevel.from_string(args.notarize) - if notarization.should_notarize(): - if not args.notary_user or not args.notary_password: - parser.error('The `--notary-user` and `--notary-password` ' - 'arguments are required if notarizing.') - config = create_config( model.pick(args, ( 'identity', @@ -169,8 +169,14 @@ 'notary_asc_provider', 'notary_team_id', 'notarization_tool', + 'notarize', )), args.development) + if config.notarize.should_notarize(): + if not args.notary_user or not args.notary_password: + parser.error('The `--notary-user` and `--notary-password` ' + 'arguments are required if notarizing.') + if config.notarization_tool == model.NotarizationTool.NOTARYTOOL: # Let the config override notary_team_id, including a potentially # unspecified argument. @@ -189,7 +195,6 @@ paths, config, disable_packaging=args.disable_packaging, - notarization=notarization, skip_brands=args.skip_brands, channels=args.channels)
diff --git a/chrome/installer/mac/signing/config.py b/chrome/installer/mac/signing/config.py index 3e8acfec..e232884 100644 --- a/chrome/installer/mac/signing/config.py +++ b/chrome/installer/mac/signing/config.py
@@ -4,7 +4,7 @@ import os.path -from .model import Distribution, NotarizationTool +from .model import Distribution, NotarizeAndStapleLevel, NotarizationTool class ConfigError(Exception): @@ -37,7 +37,8 @@ notary_asc_provider=None, notary_team_id=None, codesign_requirements_basic='', - notarization_tool=None): + notarization_tool=None, + notarize=NotarizeAndStapleLevel.STAPLE): """Creates a CodeSignConfig that will sign the product using the static properties on the class, using the code signing identity passed to the constructor. @@ -68,6 +69,7 @@ otherwise. notarization_tool: The tool to use to communicate with the Apple notary service. If None, the config will choose a default. + notarize: The |model.NotarizeAndStapleLevel|. """ assert identity is not None assert type(identity) is str @@ -79,6 +81,7 @@ self._codesign_requirements_basic = codesign_requirements_basic self._notary_team_id = notary_team_id self._notarization_tool = notarization_tool + self._notarize = notarize @staticmethod def is_chrome_branded(): @@ -154,6 +157,13 @@ return None @property + def notarize(self): + """Returns the |model.NotarizeAndStapleLevel| that controls how, if + at all, notarization and stapling of CodeSignedProducts should occur. + """ + return self._notarize + + @property def app_product(self): """Returns the product name that is used for the outer .app bundle. This is displayed to the user in Finder.
diff --git a/chrome/installer/mac/signing/model.py b/chrome/installer/mac/signing/model.py index 760ff42..72991f6 100644 --- a/chrome/installer/mac/signing/model.py +++ b/chrome/installer/mac/signing/model.py
@@ -222,7 +222,10 @@ @classmethod def from_string(cls, str): - return cls[str.upper().replace('-', '_')] + try: + return cls[str.upper().replace('-', '_')] + except KeyError: + raise ValueError(f'Invalid NotarizeAndStapleLevel: {str}') class NotarizationTool(enum.Enum):
diff --git a/chrome/installer/mac/signing/pipeline.py b/chrome/installer/mac/signing/pipeline.py index 89b2139..2b5c558 100644 --- a/chrome/installer/mac/signing/pipeline.py +++ b/chrome/installer/mac/signing/pipeline.py
@@ -645,7 +645,6 @@ def sign_all(orig_paths, config, disable_packaging=False, - notarization=model.NotarizeAndStapleLevel.STAPLE, skip_brands=[], channels=[]): """For each distribution in |config|, performs customization, signing, and @@ -659,9 +658,6 @@ unpackaged signed app bundle will be copied to |paths.output|. If False, the packaging specified in the distribution will be performed. - notarization: The level of notarization to be performed. If - |disable_packaging| is False, the packages (dmg/pkg) will undergo - the same notarization. skip_brands: A list of brand code strings. If a distribution has a brand code in this list, or if a distribution has a brand code and |skip_brands| contains *, that distribution will be skipped. @@ -687,7 +683,7 @@ # If not packaging and not notarizing, then simply drop the # signed bundle in the output directory when done signing. - if not do_packaging and not notarization.should_notarize(): + if not do_packaging and not config.notarize.should_notarize(): dest_dir = paths.output else: dest_dir = notary_paths.work @@ -708,7 +704,7 @@ # If the build products are to be notarized, ZIP the app bundle # and submit it for notarization. - if notarization.should_notarize(): + if config.notarize.should_notarize(): zip_file = os.path.join( notary_paths.work, dist_config.packaging_basename + '.zip') @@ -722,10 +718,10 @@ # If needed, wait for app notarization results to come back, and staple # if required. - if notarization.should_wait(): + if config.notarize.should_wait(): for result in notarize.wait_for_results(uuids_to_config.keys(), config): - if notarization.should_staple(): + if config.notarize.should_staple(): dist_config = uuids_to_config[result] dest_dir = os.path.join( notary_paths.work, @@ -754,23 +750,23 @@ if dist.package_as_dmg: dmg_path = _package_and_sign_dmg(paths, dist_config) - if notarization.should_notarize(): + if config.notarize.should_notarize(): uuid = notarize.submit(dmg_path, dist_config) uuids_to_package_path[uuid] = dmg_path if dist.package_as_pkg: pkg_path = _package_and_sign_pkg(paths, dist_config) - if notarization.should_notarize(): + if config.notarize.should_notarize(): uuid = notarize.submit(pkg_path, dist_config) uuids_to_package_path[uuid] = pkg_path # If needed, wait for package notarization results to come back, and # staple if required. - if notarization.should_wait(): + if config.notarize.should_wait(): for result in notarize.wait_for_results( uuids_to_package_path.keys(), config): - if notarization.should_staple(): + if config.notarize.should_staple(): package_path = uuids_to_package_path[result] notarize.staple(package_path)
diff --git a/chrome/installer/mac/signing/pipeline_test.py b/chrome/installer/mac/signing/pipeline_test.py index 5065f1d..1122e63 100644 --- a/chrome/installer/mac/signing/pipeline_test.py +++ b/chrome/installer/mac/signing/pipeline_test.py
@@ -1319,11 +1319,9 @@ kwargs[ '_package_and_sign_dmg'].return_value = '/$O/AppProduct-99.0.9999.99.dmg' - config = test_config.TestConfig() - pipeline.sign_all( - self.paths, - config, - notarization=model.NotarizeAndStapleLevel.NOWAIT) + config = test_config.TestConfig( + notarize=model.NotarizeAndStapleLevel.NOWAIT) + pipeline.sign_all(self.paths, config) self.assertEqual(1, kwargs['_package_installer_tools'].call_count) @@ -1366,11 +1364,9 @@ kwargs[ '_package_and_sign_dmg'].return_value = '/$O/AppProduct-99.0.9999.99.dmg' - config = test_config.TestConfig() - pipeline.sign_all( - self.paths, - config, - notarization=model.NotarizeAndStapleLevel.WAIT_NOSTAPLE) + config = test_config.TestConfig( + notarize=model.NotarizeAndStapleLevel.WAIT_NOSTAPLE) + pipeline.sign_all(self.paths, config) self.assertEqual(1, kwargs['_package_installer_tools'].call_count) @@ -1406,9 +1402,9 @@ for attr in kwargs: manager.attach_mock(kwargs[attr], attr) - config = test_config.TestConfig() - pipeline.sign_all( - self.paths, config, notarization=model.NotarizeAndStapleLevel.NONE) + config = test_config.TestConfig( + notarize=model.NotarizeAndStapleLevel.NONE) + pipeline.sign_all(self.paths, config) self.assertEqual(1, kwargs['_package_installer_tools'].call_count) @@ -1431,12 +1427,9 @@ for attr in kwargs: manager.attach_mock(kwargs[attr], attr) - config = test_config.TestConfig() - pipeline.sign_all( - self.paths, - config, - disable_packaging=True, - notarization=model.NotarizeAndStapleLevel.NONE) + config = test_config.TestConfig( + notarize=model.NotarizeAndStapleLevel.NONE) + pipeline.sign_all(self.paths, config, disable_packaging=True) manager.assert_has_calls([ # First customize the distribution and sign it. @@ -1480,9 +1473,8 @@ package_as_pkg=True), ] - config = Config() - pipeline.sign_all( - self.paths, config, notarization=model.NotarizeAndStapleLevel.NONE) + config = Config(notarize=model.NotarizeAndStapleLevel.NONE) + pipeline.sign_all(self.paths, config) self.assertEqual(1, kwargs['_package_installer_tools'].call_count) self.assertEqual(3, kwargs['_customize_and_sign_chrome'].call_count) @@ -1534,11 +1526,10 @@ model.Distribution(), ] - config = Config() + config = Config(notarize=model.NotarizeAndStapleLevel.NONE) pipeline.sign_all( self.paths, config, - notarization=model.NotarizeAndStapleLevel.NONE, skip_brands=skip_brands, channels=include_channels)
diff --git a/chrome/installer/mac/signing/signing.py b/chrome/installer/mac/signing/signing.py index c45ab6c..03a1c34 100644 --- a/chrome/installer/mac/signing/signing.py +++ b/chrome/installer/mac/signing/signing.py
@@ -73,9 +73,9 @@ path = os.path.join(paths.work, part.path) if _linker_signed_arm64_needs_force(path): command.append('--force') - if config.notary_user: - # Assume if the config has notary authentication information that the - # products will be notarized, which requires a secure timestamp. + if config.notarize.should_notarize(): + # If the products will be notarized, the signature requires a secure + # timestamp. command.append('--timestamp') if part.sign_with_identifier: command.extend(['--identifier', part.identifier])
diff --git a/chrome/installer/mac/signing/signing_test.py b/chrome/installer/mac/signing/signing_test.py index 4253c59..0cbd942 100644 --- a/chrome/installer/mac/signing/signing_test.py +++ b/chrome/installer/mac/signing/signing_test.py
@@ -112,7 +112,6 @@ '/$W/Test.app' ]) - def test_sign_part_needs_force(self, run_command, linker_signed_arm64_needs_force): linker_signed_arm64_needs_force.return_value = True @@ -138,7 +137,8 @@ def test_sign_part_no_notary(self, run_command, linker_signed_arm64_needs_force): - config = test_config.TestConfig(notary_user=None, notary_password=None) + config = test_config.TestConfig( + notarize=model.NotarizeAndStapleLevel.NONE) part = model.CodeSignedProduct('Test.app', 'test.signing.app') signing.sign_part(self.paths, config, part) run_command.assert_called_once_with(
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index fc38089f..0531524 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc
@@ -246,8 +246,8 @@ } } -// Waits up to a minute for msiexec to release its mutex and then overwrites -// DisplayVersion in the Windows registry. +// Waits for msiexec to release its mutex and then overwrites DisplayVersion in +// the Windows registry. LONG OverwriteDisplayVersionsAfterMsiexec(base::win::ScopedHandle startup_event, const std::wstring& product, const std::wstring& value) { @@ -269,7 +269,7 @@ startup_event.Close(); } - auto wait_result = ::WaitForSingleObject(msi_handle.Get(), 60 * 1000); + const auto wait_result = ::WaitForSingleObject(msi_handle.Get(), INFINITE); if (wait_result == WAIT_FAILED) { // The handle is valid and was opened with SYNCHRONIZE, so the wait should // never fail. If it does, wait ten seconds and proceed with the overwrite @@ -277,12 +277,11 @@ PLOG(ERROR) << "Overwriting DisplayVersion in 10s after failing to wait " "for the MSI mutex"; base::PlatformThread::Sleep(base::Seconds(10)); - } else if (wait_result == WAIT_ABANDONED || wait_result == WAIT_OBJECT_0) { + } else { + CHECK(wait_result == WAIT_ABANDONED || wait_result == WAIT_OBJECT_0) + << "WaitForSingleObject: " << wait_result; VLOG(1) << "Acquired MSI mutex; overwriting DisplayVersion."; acquired_mutex = true; - } else { - DCHECK_EQ(wait_result, static_cast<DWORD>(WAIT_TIMEOUT)); - LOG(ERROR) << "Timed out waiting for MSI mutex."; } } else { // The mutex should still be held by msiexec since the parent setup.exe
diff --git a/chrome/renderer/accessibility/ax_tree_distiller.cc b/chrome/renderer/accessibility/ax_tree_distiller.cc index a61dda6..b1b0933 100644 --- a/chrome/renderer/accessibility/ax_tree_distiller.cc +++ b/chrome/renderer/accessibility/ax_tree_distiller.cc
@@ -136,13 +136,9 @@ void AXTreeDistiller::ProcessScreen2xResult( const ui::AXTreeID& tree_id, const std::vector<ui::AXNodeID>& content_node_ids) { - // If content nodes were identified, run callback. - if (!content_node_ids.empty()) { - on_ax_tree_distilled_callback_.Run(tree_id, content_node_ids); - return; - } + on_ax_tree_distilled_callback_.Run(tree_id, content_node_ids); - // TODO(crbug.com/1266555): If still no content nodes were identified, and + // TODO(crbug.com/1266555): If no content nodes were identified, and // there is a selection, try sending Screen2x a partial tree just containing // the selected nodes. }
diff --git a/chrome/renderer/cart/commerce_hint_agent.cc b/chrome/renderer/cart/commerce_hint_agent.cc index 3b55012..702a3c3b 100644 --- a/chrome/renderer/cart/commerce_hint_agent.cc +++ b/chrome/renderer/cart/commerce_hint_agent.cc
@@ -778,19 +778,21 @@ // Find the first non-null, non-empty element and terminates anytime an // element with wrong size is found. std::string button_text; + std::u16string button_text_utf16; while (!element.IsNull()) { gfx::Size client_size = element.GetClientSize(); if (!commerce_heuristics::IsAddToCartButtonSpec(client_size.height(), client_size.width())) { return false; } - base::TrimWhitespaceASCII(element.TextContent().Ascii(), base::TRIM_ALL, - &button_text); + base::TrimWhitespace(element.TextContent().Utf16(), base::TRIM_ALL, + &button_text_utf16); + button_text = base::UTF16ToUTF8(button_text_utf16); if (button_text.empty() && element.TagName().Ascii() == kInputType && !element.GetAttribute(kValueAttributeName).IsEmpty()) { - base::TrimWhitespaceASCII( - element.GetAttribute(kValueAttributeName).Ascii(), base::TRIM_ALL, - &button_text); + base::TrimWhitespace(element.GetAttribute(kValueAttributeName).Utf16(), + base::TRIM_ALL, &button_text_utf16); + button_text = base::UTF16ToUTF8(button_text_utf16); } if (!button_text.empty()) break;
diff --git a/chrome/renderer/cart/commerce_hint_agent_renderer_browsertest.cc b/chrome/renderer/cart/commerce_hint_agent_renderer_browsertest.cc index 1017705..5690c74 100644 --- a/chrome/renderer/cart/commerce_hint_agent_renderer_browsertest.cc +++ b/chrome/renderer/cart/commerce_hint_agent_renderer_browsertest.cc
@@ -101,21 +101,21 @@ Add to cart </button> - <input class="wrong-button" value="Move To Cart"></input> + <button class="add-to-cart-button wrong-button">加入购物车</button> </body> )HTML"; LoadHTML(html); auto correct_buttons = GetMainFrame()->GetDocument().QuerySelectorAll( - blink::WebString("*[class='correct-button']")); + blink::WebString(".correct-button")); EXPECT_GT(correct_buttons.size(), 0u); for (auto& element : correct_buttons) { EXPECT_TRUE(cart::CommerceHintAgent::IsAddToCartButton(element)); } auto wrong_buttons = GetMainFrame()->GetDocument().QuerySelectorAll( - blink::WebString("*[class='wrong-button']")); + blink::WebString(".wrong-button")); EXPECT_GT(wrong_buttons.size(), 0u); for (auto& element : wrong_buttons) { EXPECT_FALSE(cart::CommerceHintAgent::IsAddToCartButton(element));
diff --git a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc index 025f324..0da34be 100644 --- a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc +++ b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder.cc
@@ -45,7 +45,7 @@ constexpr char kWifiNetworkSsidKey[] = "wifi_ssid"; // Key in wifi_network dictionary containing the password of the wifi network. -constexpr char kWifiNetworkPasswordKey[] = "pre_shared_key"; +constexpr char kWifiNetworkPasswordKey[] = "wifi_pre_shared_key"; // Key in wifi_network dictionary containing the security type of the wifi // network.
diff --git a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder_unittest.cc b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder_unittest.cc index 437b243..8349008 100644 --- a/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder_unittest.cc +++ b/chrome/services/sharing/nearby/quick_start_decoder/quick_start_decoder_unittest.cc
@@ -44,7 +44,7 @@ constexpr char kWifiNetworkSsidKey[] = "wifi_ssid"; // Key in wifi_network dictionary containing the password of the wifi network. -constexpr char kWifiNetworkPasswordKey[] = "pre_shared_key"; +constexpr char kWifiNetworkPasswordKey[] = "wifi_pre_shared_key"; // Key in wifi_network dictionary containing the security type of the wifi // network.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 94049a6..3eb929d 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3040,6 +3040,7 @@ "../browser/extensions/api/activity_log_private/activity_log_private_apitest.cc", "../browser/extensions/api/alarms/alarms_apitest.cc", "../browser/extensions/api/autofill_private/autofill_private_apitest.cc", + "../browser/extensions/api/autofill_private/autofill_util_unittest.cc", "../browser/extensions/api/automation/automation_apitest.cc", "../browser/extensions/api/bookmarks/bookmark_apitest.cc", "../browser/extensions/api/braille_display_private/braille_display_private_apitest.cc", @@ -6104,7 +6105,6 @@ "//chrome/browser/ui:test_support", "//chrome/browser/ui/commander:fuzzy_finder", "//chrome/browser/updates/announcement_notification:unit_tests", - "//chrome/browser/video_tutorials:unit_tests", "//chrome/browser/web_share_target:unit_tests", "//chrome/common:test_support", "//chrome/common:version_header",
diff --git a/chrome/test/chromedriver/BUILD.gn b/chrome/test/chromedriver/BUILD.gn index 07f314b..124e573 100644 --- a/chrome/test/chromedriver/BUILD.gn +++ b/chrome/test/chromedriver/BUILD.gn
@@ -145,6 +145,8 @@ "chrome/devtools_http_client.h", "chrome/download_directory_override_manager.cc", "chrome/download_directory_override_manager.h", + "chrome/fedcm_tracker.cc", + "chrome/fedcm_tracker.h", "chrome/frame_tracker.cc", "chrome/frame_tracker.h", "chrome/geolocation_override_manager.cc", @@ -275,6 +277,8 @@ "element_commands.h", "element_util.cc", "element_util.h", + "fedcm_commands.cc", + "fedcm_commands.h", "key_converter.cc", "key_converter.h", "keycode_text_conversion.h", @@ -460,6 +464,7 @@ "chrome/devtools_endpoint_unittest.cc", "chrome/devtools_http_client_unittest.cc", "chrome/download_directory_override_manager_unittest.cc", + "chrome/fedcm_tracker_unittest.cc", "chrome/frame_tracker_unittest.cc", "chrome/geolocation_override_manager_unittest.cc", "chrome/heap_snapshot_taker_unittest.cc", @@ -482,6 +487,7 @@ "command_listener_proxy_unittest.cc", "commands_unittest.cc", "element_commands_unittest.cc", + "fedcm_commands_unittest.cc", "key_converter_unittest.cc", "keycode_text_conversion_unittest.cc", "log_replay/devtools_log_reader_unittest.cc",
diff --git a/chrome/test/chromedriver/chrome/fedcm_tracker.cc b/chrome/test/chromedriver/chrome/fedcm_tracker.cc new file mode 100644 index 0000000..0f20f95 --- /dev/null +++ b/chrome/test/chromedriver/chrome/fedcm_tracker.cc
@@ -0,0 +1,47 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/test/chromedriver/chrome/fedcm_tracker.h" + +#include "base/logging.h" +#include "chrome/test/chromedriver/chrome/devtools_client.h" +#include "chrome/test/chromedriver/chrome/status.h" + +FedCmTracker::FedCmTracker(DevToolsClient* client) { + client->AddListener(this); +} + +FedCmTracker::~FedCmTracker() = default; + +Status FedCmTracker::Enable(DevToolsClient* client) { + return client->SendCommand("FedCm.enable", base::Value::Dict()); +} + +bool FedCmTracker::ListensToConnections() const { + return false; +} + +Status FedCmTracker::OnEvent(DevToolsClient* client, + const std::string& method, + const base::Value::Dict& params) { + if (method != "FedCm.dialogShown") { + return Status(kOk); + } + + const std::string* id = params.FindString("dialogId"); + last_dialog_id_ = id ? *id : ""; + const std::string* str = params.FindString("title"); + last_title_ = str ? *str : ""; + str = params.FindString("subtitle"); + last_subtitle_ = str ? absl::make_optional(*str) : absl::nullopt; + str = params.FindString("dialogType"); + last_dialog_type_ = str ? *str : ""; + const base::Value::List* accounts = params.FindList("accounts"); + if (accounts) { + last_accounts_ = accounts->Clone(); + } else { + last_accounts_ = base::Value::List(); + } + return Status(kOk); +}
diff --git a/chrome/test/chromedriver/chrome/fedcm_tracker.h b/chrome/test/chromedriver/chrome/fedcm_tracker.h new file mode 100644 index 0000000..71b15f70 --- /dev/null +++ b/chrome/test/chromedriver/chrome/fedcm_tracker.h
@@ -0,0 +1,63 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_TEST_CHROMEDRIVER_CHROME_FEDCM_TRACKER_H_ +#define CHROME_TEST_CHROMEDRIVER_CHROME_FEDCM_TRACKER_H_ + +#include <string> + +#include "base/values.h" +#include "chrome/test/chromedriver/chrome/devtools_event_listener.h" + +// Tracks the FedCM dialog events. +class FedCmTracker : public DevToolsEventListener { + public: + explicit FedCmTracker(DevToolsClient* client); + + FedCmTracker(const FedCmTracker&) = delete; + FedCmTracker& operator=(const FedCmTracker&) = delete; + + ~FedCmTracker() override; + + // Enables the FedCM events. + Status Enable(DevToolsClient* client); + + // DevToolsEventListener: + bool ListensToConnections() const override; + Status OnEvent(DevToolsClient* client, + const std::string& method, + const base::Value::Dict& params) override; + + bool HasDialog() const { return !last_dialog_id_.empty(); } + + const std::string& GetLastDialogId() const { return last_dialog_id_; } + + const base::Value::List& GetLastAccounts() const { return last_accounts_; } + + const std::string& GetLastTitle() const { return last_title_; } + const absl::optional<std::string>& GetLastSubtitle() const { + return last_subtitle_; + } + + const std::string& GetLastDialogType() const { return last_dialog_type_; } + + // To be called when the client issues one of the commands that + // close the dialog. + void DialogClosed() { + last_dialog_id_ = ""; + last_title_ = ""; + last_subtitle_ = ""; + last_dialog_type_ = ""; + last_accounts_ = base::Value::List(); + } + + private: + std::string last_dialog_id_; + std::string last_title_; + absl::optional<std::string> last_subtitle_; + std::string last_dialog_type_; + base::Value::List last_accounts_; +}; + +#endif // CHROME_TEST_CHROMEDRIVER_CHROME_FEDCM_TRACKER_H_
diff --git a/chrome/test/chromedriver/chrome/fedcm_tracker_unittest.cc b/chrome/test/chromedriver/chrome/fedcm_tracker_unittest.cc new file mode 100644 index 0000000..39c2758 --- /dev/null +++ b/chrome/test/chromedriver/chrome/fedcm_tracker_unittest.cc
@@ -0,0 +1,66 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/test/chromedriver/chrome/fedcm_tracker.h" + +#include "base/values.h" +#include "chrome/test/chromedriver/chrome/status.h" +#include "chrome/test/chromedriver/chrome/stub_devtools_client.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::Return; + +namespace { + +class MockDevToolsClient : public StubDevToolsClient { + public: + MOCK_METHOD2(SendCommand, + Status(const std::string& method, + const base::Value::Dict& params)); + MOCK_METHOD1(AddListener, void(DevToolsEventListener* listener)); +}; + +} // namespace + +class FedCmTrackerTest : public testing::Test { + public: + void SetUp() override { + testing::Test::SetUp(); + EXPECT_CALL(devtools_client_, AddListener(_)); + EXPECT_CALL(devtools_client_, SendCommand("FedCm.enable", _)) + .WillOnce(Return(Status(kOk))); + fedcm_tracker_ = std::make_unique<FedCmTracker>(&devtools_client_); + Status status = fedcm_tracker_->Enable(&devtools_client_); + EXPECT_TRUE(status.IsOk()); + } + + protected: + std::unique_ptr<FedCmTracker> fedcm_tracker_; + MockDevToolsClient devtools_client_; +}; + +TEST_F(FedCmTrackerTest, OnDialogShown) { + base::Value::Dict account; + account.Set("accountId", "1"); + account.Set("email", "foo@bar.com"); + account.Set("name", "Foo Bar"); + base::Value::List account_list; + account_list.Append(std::move(account)); + base::Value::Dict event_params; + event_params.Set("dialogId", "5"); + event_params.Set("title", "a title"); + event_params.Set("dialogType", "AccountChooser"); + event_params.Set("accounts", std::move(account_list)); + + EXPECT_FALSE(fedcm_tracker_->HasDialog()); + + fedcm_tracker_->OnEvent(&devtools_client_, "FedCm.dialogShown", event_params); + EXPECT_TRUE(fedcm_tracker_->HasDialog()); + EXPECT_EQ("5", fedcm_tracker_->GetLastDialogId()); + EXPECT_EQ("a title", fedcm_tracker_->GetLastTitle()); + EXPECT_EQ(1u, fedcm_tracker_->GetLastAccounts().size()); + EXPECT_EQ("AccountChooser", fedcm_tracker_->GetLastDialogType()); +}
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.cc b/chrome/test/chromedriver/chrome/stub_web_view.cc index e2d9000f..2e3a33a 100644 --- a/chrome/test/chromedriver/chrome/stub_web_view.cc +++ b/chrome/test/chromedriver/chrome/stub_web_view.cc
@@ -262,6 +262,10 @@ return false; } +Status StubWebView::GetFedCmTracker(FedCmTracker** out_tracker) { + return Status(kUnknownCommand); +} + FrameTracker* StubWebView::GetFrameTracker() const { return nullptr; }
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.h b/chrome/test/chromedriver/chrome/stub_web_view.h index cc3a248..5de8d3e 100644 --- a/chrome/test/chromedriver/chrome/stub_web_view.h +++ b/chrome/test/chromedriver/chrome/stub_web_view.h
@@ -125,6 +125,7 @@ int yoffset) override; bool IsNonBlocking() const override; FrameTracker* GetFrameTracker() const override; + Status GetFedCmTracker(FedCmTracker** out_tracker) override; std::unique_ptr<base::Value> GetCastSinks() override; std::unique_ptr<base::Value> GetCastIssueMessage() override; void SetFrame(const std::string& new_frame_id) override;
diff --git a/chrome/test/chromedriver/chrome/web_view.h b/chrome/test/chromedriver/chrome/web_view.h index 530120c..24145064 100644 --- a/chrome/test/chromedriver/chrome/web_view.h +++ b/chrome/test/chromedriver/chrome/web_view.h
@@ -17,6 +17,7 @@ class TimeDelta; } // namespace base +class FedCmTracker; class FrameTracker; struct Geoposition; class JavaScriptDialogManager; @@ -273,6 +274,9 @@ virtual FrameTracker* GetFrameTracker() const = 0; + // On success, sets *tracker to the FedCmTracker. + virtual Status GetFedCmTracker(FedCmTracker** out_tracker) = 0; + virtual std::unique_ptr<base::Value> GetCastSinks() = 0; virtual std::unique_ptr<base::Value> GetCastIssueMessage() = 0;
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc index a843b64..3242fa3 100644 --- a/chrome/test/chromedriver/chrome/web_view_impl.cc +++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -31,6 +31,7 @@ #include "chrome/test/chromedriver/chrome/devtools_client.h" #include "chrome/test/chromedriver/chrome/devtools_client_impl.h" #include "chrome/test/chromedriver/chrome/download_directory_override_manager.h" +#include "chrome/test/chromedriver/chrome/fedcm_tracker.h" #include "chrome/test/chromedriver/chrome/frame_tracker.h" #include "chrome/test/chromedriver/chrome/geolocation_override_manager.h" #include "chrome/test/chromedriver/chrome/heap_snapshot_taker.h" @@ -1675,6 +1676,19 @@ return parent_->IsNonBlocking(); } +Status WebViewImpl::GetFedCmTracker(FedCmTracker** out_tracker) { + if (!fedcm_tracker_) { + fedcm_tracker_ = std::make_unique<FedCmTracker>(client_.get()); + Status status = fedcm_tracker_->Enable(client_.get()); + if (!status.IsOk()) { + fedcm_tracker_.reset(); + return status; + } + } + *out_tracker = fedcm_tracker_.get(); + return Status(kOk); +} + FrameTracker* WebViewImpl::GetFrameTracker() const { return frame_tracker_.get(); }
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.h b/chrome/test/chromedriver/chrome/web_view_impl.h index ade11fad..7537c097 100644 --- a/chrome/test/chromedriver/chrome/web_view_impl.h +++ b/chrome/test/chromedriver/chrome/web_view_impl.h
@@ -17,6 +17,7 @@ struct BrowserInfo; class DevToolsClient; class DownloadDirectoryOverrideManager; +class FedCmTracker; class FrameTracker; class GeolocationOverrideManager; class MobileEmulationOverrideManager; @@ -166,6 +167,7 @@ const base::Value& element, int* backend_node_id) override; bool IsNonBlocking() const override; + Status GetFedCmTracker(FedCmTracker** out_tracker) override; FrameTracker* GetFrameTracker() const override; std::unique_ptr<base::Value> GetCastSinks() override; std::unique_ptr<base::Value> GetCastIssueMessage() override; @@ -247,6 +249,7 @@ download_directory_override_manager_; std::unique_ptr<HeapSnapshotTaker> heap_snapshot_taker_; std::unique_ptr<CastTracker> cast_tracker_; + std::unique_ptr<FedCmTracker> fedcm_tracker_; bool is_service_worker_; };
diff --git a/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc b/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc index 82fe8b0..1aa4647b 100644 --- a/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc +++ b/chrome/test/chromedriver/chrome/web_view_impl_unittest.cc
@@ -775,6 +775,20 @@ } } +TEST(GetFedCmTracker, OK) { + std::unique_ptr<FakeDevToolsClient> client_uptr = + std::make_unique<FakeDevToolsClient>(); + FakeDevToolsClient* client_ptr = client_uptr.get(); + BrowserInfo browser_info; + WebViewImpl view(client_ptr->GetId(), true, nullptr, &browser_info, + std::move(client_uptr), absl::nullopt, + PageLoadStrategy::kEager); + FedCmTracker* tracker = nullptr; + Status status = view.GetFedCmTracker(&tracker); + EXPECT_TRUE(StatusOk(status)); + EXPECT_NE(nullptr, tracker); +} + class CallUserSyncScriptArgs : public testing::TestWithParam<std::pair<std::string, bool>> { public:
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py index 83ac0bf0..04e74902 100644 --- a/chrome/test/chromedriver/client/chromedriver.py +++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -442,7 +442,8 @@ # make sure that we have ms on the both sides of inequality if (self._executor.HttpTimeout() * 500 < max_kv[1]): raise ChromeDriverException( - 'Timeout "%s" for ChromeDriver exceeds 50%% of the HTTP connection timeout' + 'Timeout "%s" for ChromeDriver exceeds 50%% of the ' + 'HTTP connection timeout' % max_kv[0]) return self.ExecuteCommand(Command.SET_TIMEOUTS, params) @@ -736,6 +737,29 @@ params = {'mode': mode} return self.ExecuteCommand(Command.SET_RPH_REGISTRATION_MODE, params) + def CancelFedCmDialog(self): + return self.ExecuteCommand(Command.CANCEL_FEDCM_DIALOG, {}) + + def SelectAccount(self, index): + params = {'accountIndex': index} + return self.ExecuteCommand(Command.SELECT_ACCOUNT, params) + + def GetAccounts(self): + return self.ExecuteCommand(Command.GET_ACCOUNTS, {}) + + def GetFedCmTitle(self): + return self.ExecuteCommand(Command.GET_FEDCM_TITLE, {}) + + def GetDialogType(self): + return self.ExecuteCommand(Command.GET_DIALOG_TYPE, {}) + + def SetDelayEnabled(self, enabled): + params = {'enabled': enabled} + return self.ExecuteCommand(Command.SET_DELAY_ENABLED, params) + + def ResetCooldown(self): + return self.ExecuteCommand(Command.RESET_COOLDOWN, {}) + def GetSessionId(self): if not hasattr(self, '_session_id'): return None
diff --git a/chrome/test/chromedriver/client/command_executor.py b/chrome/test/chromedriver/client/command_executor.py index 3b55ae72..3863eda 100644 --- a/chrome/test/chromedriver/client/command_executor.py +++ b/chrome/test/chromedriver/client/command_executor.py
@@ -221,6 +221,27 @@ GET_CAST_SINKS = ( _Method.GET, '/session/:sessionId/:vendorId/cast/get_sinks') + CANCEL_FEDCM_DIALOG = ( + _Method.POST, + '/session/:sessionId/fedcm/canceldialog') + SELECT_ACCOUNT = ( + _Method.POST, + '/session/:sessionId/fedcm/selectaccount') + GET_ACCOUNTS = ( + _Method.GET, + '/session/:sessionId/fedcm/accountlist') + GET_FEDCM_TITLE = ( + _Method.GET, + '/session/:sessionId/fedcm/gettitle') + GET_DIALOG_TYPE = ( + _Method.GET, + '/session/:sessionId/fedcm/getdialogtype') + SET_DELAY_ENABLED = ( + _Method.POST, + '/session/:sessionId/fedcm/setdelayenabled') + RESET_COOLDOWN = ( + _Method.POST, + '/session/:sessionId/fedcm/resetcooldown') # Custom Chrome commands. IS_LOADING = (_Method.GET, '/session/:sessionId/is_loading')
diff --git a/chrome/test/chromedriver/docs/event_listener.md b/chrome/test/chromedriver/docs/event_listener.md index 66369f04..b5fdeae 100644 --- a/chrome/test/chromedriver/docs/event_listener.md +++ b/chrome/test/chromedriver/docs/event_listener.md
@@ -62,6 +62,7 @@ * [`DevToolsEventsLogger`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/chromedriver/devtools_events_logger.h?q=DevToolsEventsLogger) * [`DomTracker`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/chromedriver/chrome/dom_tracker.h?q=DomTracker) * [`DownloadDirectoryOverrideManager`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/chromedriver/chrome/download_directory_override_manager.h?q=DownloadDirectoryOverrideManager) +* [`FedCmTracker`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/chromedriver/chrome/fedcm_tracker.h?q=FedCmTracker) * [`FrameTracker`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/chromedriver/chrome/frame_tracker.h?q=FrameTracker) * [`GeolocationOverrideManager`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/chromedriver/chrome/geolocation_override_manager.h?q=GeolocationOverrideManager) * [`HeapSnapshotTaker`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/chromedriver/chrome/heap_snapshot_taker.h?q=HeapSnapshotTaker) @@ -97,3 +98,12 @@ events it receives from Chrome DevTools. Most ChromeDriver commands wait for the loading state to become `kNotLoading` before returning. + +### FedCM Tracker + +The [`FedCmTracker`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/test/chromedriver/chrome/fedcm_tracker.h?q=FedCmTracker) +listens to FedCM dialog events and stores the parameters for later use. + +Since the WebDriver protocol does not support events, we instead provide +accessors that the client can periodically check to detect when a dialog has +been shown.
diff --git a/chrome/test/chromedriver/fedcm_commands.cc b/chrome/test/chromedriver/fedcm_commands.cc new file mode 100644 index 0000000..95cc39c --- /dev/null +++ b/chrome/test/chromedriver/fedcm_commands.cc
@@ -0,0 +1,149 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/test/chromedriver/fedcm_commands.h" + +#include "base/values.h" +#include "chrome/test/chromedriver/chrome/fedcm_tracker.h" +#include "chrome/test/chromedriver/chrome/status.h" +#include "chrome/test/chromedriver/chrome/web_view.h" +#include "chrome/test/chromedriver/session.h" + +Status ExecuteCancelDialog(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout) { + FedCmTracker* tracker = nullptr; + Status status = web_view->GetFedCmTracker(&tracker); + if (!status.IsOk()) { + return status; + } + if (!tracker->HasDialog()) { + return Status(kNoSuchAlert); + } + + base::Value::Dict command_params; + command_params.Set("dialogId", tracker->GetLastDialogId()); + + std::unique_ptr<base::Value> result; + status = web_view->SendCommandAndGetResult("FedCm.dismissDialog", + command_params, &result); + tracker->DialogClosed(); + return status; +} + +Status ExecuteSelectAccount(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout) { + FedCmTracker* tracker = nullptr; + Status status = web_view->GetFedCmTracker(&tracker); + if (!status.IsOk()) { + return status; + } + if (!tracker->HasDialog()) { + return Status(kNoSuchAlert); + } + if (!params.FindInt("accountIndex")) { + return Status(kInvalidArgument, "accountIndex must be specified"); + } + + base::Value::Dict command_params; + command_params.Set("dialogId", tracker->GetLastDialogId()); + command_params.Set("accountIndex", *params.FindInt("accountIndex")); + + std::unique_ptr<base::Value> result; + status = web_view->SendCommandAndGetResult("FedCm.selectAccount", + command_params, &result); + tracker->DialogClosed(); + return status; +} + +Status ExecuteGetAccounts(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout) { + FedCmTracker* tracker = nullptr; + Status status = web_view->GetFedCmTracker(&tracker); + if (!status.IsOk()) { + return status; + } + if (!tracker->HasDialog()) { + return Status(kNoSuchAlert); + } + *value = std::make_unique<base::Value>(tracker->GetLastAccounts().Clone()); + return Status(kOk); +} + +Status ExecuteGetDialogType(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout) { + FedCmTracker* tracker = nullptr; + Status status = web_view->GetFedCmTracker(&tracker); + if (!status.IsOk()) { + return status; + } + if (!tracker->HasDialog()) { + return Status(kNoSuchAlert); + } + *value = std::make_unique<base::Value>(tracker->GetLastDialogType()); + return Status(kOk); +} + +Status ExecuteGetFedCmTitle(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout) { + FedCmTracker* tracker = nullptr; + Status status = web_view->GetFedCmTracker(&tracker); + if (!status.IsOk()) { + return status; + } + if (!tracker->HasDialog()) { + return Status(kNoSuchAlert); + } + base::Value::Dict dict; + dict.Set("title", tracker->GetLastTitle()); + absl::optional<std::string> subtitle = tracker->GetLastSubtitle(); + if (subtitle) { + dict.Set("subtitle", *subtitle); + } + *value = std::make_unique<base::Value>(std::move(dict)); + return Status(kOk); +} + +Status ExecuteSetDelayEnabled(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout) { + if (!params.FindBool("enabled")) { + return Status(kInvalidArgument, "enabled must be specified"); + } + + base::Value::Dict command_params; + command_params.Set("disableRejectionDelay", !*params.FindBool("enabled")); + + std::unique_ptr<base::Value> result; + Status status = web_view->SendCommandAndGetResult("FedCm.enable", + command_params, &result); + return status; +} + +Status ExecuteResetCooldown(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout) { + std::unique_ptr<base::Value> result; + Status status = web_view->SendCommandAndGetResult( + "FedCm.resetCooldown", base::Value::Dict(), &result); + return status; +}
diff --git a/chrome/test/chromedriver/fedcm_commands.h b/chrome/test/chromedriver/fedcm_commands.h new file mode 100644 index 0000000..cd770451 --- /dev/null +++ b/chrome/test/chromedriver/fedcm_commands.h
@@ -0,0 +1,60 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_TEST_CHROMEDRIVER_FEDCM_COMMANDS_H_ +#define CHROME_TEST_CHROMEDRIVER_FEDCM_COMMANDS_H_ + +#include <memory> + +#include "base/functional/callback_forward.h" +#include "base/values.h" + +struct Session; +class Status; +class Timeout; +class WebView; + +Status ExecuteCancelDialog(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout); + +Status ExecuteSelectAccount(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout); + +Status ExecuteGetAccounts(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout); + +Status ExecuteGetFedCmTitle(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout); + +Status ExecuteGetDialogType(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout); + +Status ExecuteSetDelayEnabled(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout); + +Status ExecuteResetCooldown(Session* session, + WebView* web_view, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* value, + Timeout* timeout); + +#endif // CHROME_TEST_CHROMEDRIVER_FEDCM_COMMANDS_H_
diff --git a/chrome/test/chromedriver/fedcm_commands_unittest.cc b/chrome/test/chromedriver/fedcm_commands_unittest.cc new file mode 100644 index 0000000..578a8bb --- /dev/null +++ b/chrome/test/chromedriver/fedcm_commands_unittest.cc
@@ -0,0 +1,226 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/test/chromedriver/fedcm_commands.h" + +#include "chrome/test/chromedriver/chrome/fedcm_tracker.h" +#include "chrome/test/chromedriver/chrome/status.h" +#include "chrome/test/chromedriver/chrome/stub_devtools_client.h" +#include "chrome/test/chromedriver/chrome/stub_web_view.h" +#include "chrome/test/chromedriver/session.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class MockResponseWebView : public StubWebView { + public: + explicit MockResponseWebView(DevToolsClient* client) + : StubWebView("1"), tracker_(client) {} + ~MockResponseWebView() override = default; + + Status SendCommandAndGetResult( + const std::string& command, + const base::Value::Dict& params, + std::unique_ptr<base::Value>* result) override { + last_command_ = command; + return Status(kOk); + } + + Status GetFedCmTracker(FedCmTracker** out_tracker) override { + *out_tracker = &tracker_; + return Status(kOk); + } + + void SendEvent(DevToolsClient* client) { + base::Value::Dict dict; + dict.Set("dialogId", "0"); + dict.Set("title", "Title"); + dict.Set("dialogType", "AccountChooser"); + base::Value::Dict account; + account.Set("accountId", "123"); + account.Set("email", "foo@bar.com"); + account.Set("name", "Foo Bar"); + account.Set("givenName", "Foo"); + account.Set("pictureUrl", "https://pics/pic.jpg"); + account.Set("idpConfigUrl", "https://idp.example/fedcm.json"); + account.Set("idpSigninUrl", "https://idp.example/signin"); + account.Set("loginState", "SignIn"); + + base::Value::List accounts; + accounts.Append(std::move(account)); + dict.Set("accounts", std::move(accounts)); + + tracker_.OnEvent(client, "FedCm.dialogShown", dict); + } + + const std::string& GetLastCommand() const { return last_command_; } + + private: + FedCmTracker tracker_; + std::string last_command_; +}; + +class FedCmCommandsTest : public testing::Test { + public: + FedCmCommandsTest() = default; + + protected: + Session session{"id"}; + StubDevToolsClient client; + MockResponseWebView web_view{&client}; +}; + +} // namespace + +TEST_F(FedCmCommandsTest, ExecuteCancelDialog) { + base::Value::Dict params; + std::unique_ptr<base::Value> value; + + Status status = + ExecuteCancelDialog(&session, &web_view, params, &value, nullptr); + EXPECT_EQ(kNoSuchAlert, status.code()); + + web_view.SendEvent(&client); + + status = ExecuteCancelDialog(&session, &web_view, params, &value, nullptr); + EXPECT_EQ(kOk, status.code()); + + EXPECT_EQ("FedCm.dismissDialog", web_view.GetLastCommand()); +} + +TEST_F(FedCmCommandsTest, ExecuteSelectAccount) { + base::Value::Dict params; + std::unique_ptr<base::Value> value; + + Status status = + ExecuteSelectAccount(&session, &web_view, params, &value, nullptr); + EXPECT_EQ(kNoSuchAlert, status.code()); + + web_view.SendEvent(&client); + + // No account index + status = ExecuteSelectAccount(&session, &web_view, params, &value, nullptr); + EXPECT_EQ(kInvalidArgument, status.code()); + + params.Set("accountIndex", 0); + status = ExecuteSelectAccount(&session, &web_view, params, &value, nullptr); + EXPECT_EQ(kOk, status.code()); + + EXPECT_EQ("FedCm.selectAccount", web_view.GetLastCommand()); +} + +TEST_F(FedCmCommandsTest, ExecuteGetAccounts) { + base::Value::Dict params; + std::unique_ptr<base::Value> value; + + Status status = + ExecuteGetAccounts(&session, &web_view, params, &value, nullptr); + ASSERT_EQ(kNoSuchAlert, status.code()); + + web_view.SendEvent(&client); + + status = ExecuteGetAccounts(&session, &web_view, params, &value, nullptr); + ASSERT_EQ(kOk, status.code()); + base::Value::List* response = value->GetIfList(); + ASSERT_TRUE(response); + ASSERT_EQ(1u, response->size()); + base::Value::Dict* account = response->front().GetIfDict(); + ASSERT_TRUE(account); + std::string* accountId = account->FindString("accountId"); + ASSERT_TRUE(accountId); + EXPECT_EQ(*accountId, "123"); + std::string* email = account->FindString("email"); + ASSERT_TRUE(email); + EXPECT_EQ(*email, "foo@bar.com"); + std::string* name = account->FindString("name"); + ASSERT_TRUE(name); + EXPECT_EQ(*name, "Foo Bar"); + std::string* givenName = account->FindString("givenName"); + ASSERT_TRUE(givenName); + EXPECT_EQ(*givenName, "Foo"); + std::string* pictureUrl = account->FindString("pictureUrl"); + ASSERT_TRUE(pictureUrl); + EXPECT_EQ(*pictureUrl, "https://pics/pic.jpg"); + std::string* idpConfigUrl = account->FindString("idpConfigUrl"); + ASSERT_TRUE(idpConfigUrl); + EXPECT_EQ(*idpConfigUrl, "https://idp.example/fedcm.json"); + std::string* idpSigninUrl = account->FindString("idpSigninUrl"); + ASSERT_TRUE(idpSigninUrl); + EXPECT_EQ(*idpSigninUrl, "https://idp.example/signin"); + std::string* loginState = account->FindString("loginState"); + ASSERT_TRUE(loginState); + EXPECT_EQ(*loginState, "SignIn"); + + // This should not have triggered any commands. + EXPECT_EQ("", web_view.GetLastCommand()); +} + +TEST_F(FedCmCommandsTest, ExecuteGetTitle) { + base::Value::Dict params; + std::unique_ptr<base::Value> value; + + Status status = + ExecuteGetFedCmTitle(&session, &web_view, params, &value, nullptr); + ASSERT_EQ(kNoSuchAlert, status.code()); + + web_view.SendEvent(&client); + + status = ExecuteGetFedCmTitle(&session, &web_view, params, &value, nullptr); + ASSERT_EQ(kOk, status.code()); + base::Value::Dict* dict = value->GetIfDict(); + ASSERT_TRUE(dict); + std::string* title = dict->FindString("title"); + ASSERT_TRUE(title); + EXPECT_EQ(*title, "Title"); + + // This should not have triggered any commands. + EXPECT_EQ("", web_view.GetLastCommand()); +} + +TEST_F(FedCmCommandsTest, ExecuteGetDialogType) { + base::Value::Dict params; + std::unique_ptr<base::Value> value; + + Status status = + ExecuteGetDialogType(&session, &web_view, params, &value, nullptr); + ASSERT_EQ(kNoSuchAlert, status.code()); + + web_view.SendEvent(&client); + + status = ExecuteGetDialogType(&session, &web_view, params, &value, nullptr); + ASSERT_EQ(kOk, status.code()); + std::string* type = value->GetIfString(); + ASSERT_TRUE(type); + EXPECT_EQ(*type, "AccountChooser"); + + // This should not have triggered any commands. + EXPECT_EQ("", web_view.GetLastCommand()); +} + +TEST_F(FedCmCommandsTest, ExecuteSetDelayEnabled) { + base::Value::Dict params; + std::unique_ptr<base::Value> value; + + // No enabled argument. + Status status = + ExecuteSetDelayEnabled(&session, &web_view, params, &value, nullptr); + EXPECT_EQ(kInvalidArgument, status.code()); + + params.Set("enabled", false); + status = ExecuteSetDelayEnabled(&session, &web_view, params, &value, nullptr); + EXPECT_EQ(kOk, status.code()); + + EXPECT_EQ("FedCm.enable", web_view.GetLastCommand()); +} + +TEST_F(FedCmCommandsTest, ExecuteResetCooldown) { + base::Value::Dict params; + std::unique_ptr<base::Value> value; + + Status status = + ExecuteResetCooldown(&session, &web_view, params, &value, nullptr); + EXPECT_EQ(kOk, status.code()); + + EXPECT_EQ("FedCm.resetCooldown", web_view.GetLastCommand()); +}
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc index 963041d..0c555cc5 100644 --- a/chrome/test/chromedriver/server/http_handler.cc +++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -31,6 +31,7 @@ #include "chrome/test/chromedriver/chrome/device_manager.h" #include "chrome/test/chromedriver/chrome/status.h" #include "chrome/test/chromedriver/constants/version.h" +#include "chrome/test/chromedriver/fedcm_commands.h" #include "chrome/test/chromedriver/net/url_request_context_getter.h" #include "chrome/test/chromedriver/server/http_server.h" #include "chrome/test/chromedriver/session.h" @@ -936,6 +937,37 @@ WrapToCommand("SetSPCTransactionMode", base::BindRepeating(&ExecuteSetSPCTransactionMode))), + // Extensions for the Federated Credential Management API: + // https://github.com/fedidcg/FedCM/blob/main/proposals/webdriver.md + CommandMapping(kPost, "session/:sessionId/fedcm/canceldialog", + WrapToCommand("CancelDialog", + base::BindRepeating(&ExecuteCancelDialog))), + + CommandMapping(kPost, "session/:sessionId/fedcm/selectaccount", + WrapToCommand("SelectAccount", + base::BindRepeating(&ExecuteSelectAccount))), + + CommandMapping(kGet, "session/:sessionId/fedcm/accountlist", + WrapToCommand("GetAccounts", + base::BindRepeating(&ExecuteGetAccounts))), + + CommandMapping(kGet, "session/:sessionId/fedcm/gettitle", + WrapToCommand("GetFedCmTitle", + base::BindRepeating(&ExecuteGetFedCmTitle))), + + CommandMapping(kGet, "session/:sessionId/fedcm/getdialogtype", + WrapToCommand("GetDialogType", + base::BindRepeating(&ExecuteGetDialogType))), + + CommandMapping( + kPost, "session/:sessionId/fedcm/setdelayenabled", + WrapToCommand("SetDelayEnabled", + base::BindRepeating(&ExecuteSetDelayEnabled))), + + CommandMapping(kPost, "session/:sessionId/fedcm/resetcooldown", + WrapToCommand("ResetCooldown", + base::BindRepeating(&ExecuteResetCooldown))), + // Extensions for Custom Handlers API: // https://html.spec.whatwg.org/multipage/system-state.html#rph-automation CommandMapping(
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index 10ea2f6..c4284c47 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -3619,6 +3619,7 @@ chrome_switches=['host-resolver-rules=MAP * 127.0.0.1', 'enable-experimental-web-platform-features']) + def testAddVirtualAuthenticator(self): def addAuthenticatorAndRegister(javascriptFragment, addArgs): script = """ @@ -6348,6 +6349,93 @@ # This command crashed ChromeDriver on Android self._driver.GetCastSinks(self._vendor_id) +class FedCmSpecificTest(ChromeDriverBaseTestWithWebServer): + + def setUp(self): + port = self._https_server._server.server_port + self._url_prefix = (self._https_server.GetUrl("localhost") + + "/chromedriver/fedcm") + + def respondWithWellKnownFile(request): + return {'Content-Type': 'application/json'}, bytes(""" + { + "provider_urls": ["%s/fedcm.json"] + } + """ % self._url_prefix, 'utf-8') + self._https_server.SetCallbackForPath('/.well-known/web-identity', + respondWithWellKnownFile) + + script_content = bytes(""" + <script> + let promise = null; + function callFedCm() { + promise = navigator.credentials.get({ + identity: { + providers: [{ + configURL: '%s/fedcm.json', + clientId: '123', + }] + } + }); + } + async function getResult() { + try { + return (await promise).token; + } catch (e) { + return "Error: " + e; + } + } + </script> + """ % self._url_prefix, 'utf-8') + self._https_server.SetDataForPath('/fedcm.html', script_content) + + self._driver = self.CreateDriver( + accept_insecure_certs=True, + chrome_switches=['host-resolver-rules=MAP *:443 127.0.0.1:%s' % port, + 'enable-experimental-web-platform-features']) + + def FedCmDialogCondition(self): + try: + self._driver.GetFedCmTitle() + return True + except: + return False + + def testGetAccounts(self): + self._driver.Load(self._https_server.GetUrl() + '/fedcm.html') + + self._driver.SetDelayEnabled(False) + self._driver.ResetCooldown() + + self.assertRaises(chromedriver.NoSuchAlert, self._driver.GetAccounts) + self._driver.ExecuteScript('callFedCm()') + self.WaitForCondition(self.FedCmDialogCondition) + accounts = self._driver.GetAccounts() + self.assertEqual(2, len(accounts)) + self.assertEqual({'title': 'Sign in to 127.0.0.1 with localhost'}, + self._driver.GetFedCmTitle()) + self.assertEqual('AccountChooser', self._driver.GetDialogType()) + + self._driver.SelectAccount(0) + self.assertRaises(chromedriver.NoSuchAlert, self._driver.GetAccounts) + token = self._driver.ExecuteScript('return getResult()') + self.assertEqual('token', token) + + def testDismissDialog(self): + self._driver.Load(self._https_server.GetUrl() + '/fedcm.html') + + self._driver.ResetCooldown() + self._driver.SetDelayEnabled(False) + + self.assertRaises(chromedriver.NoSuchAlert, self._driver.GetAccounts) + self._driver.ExecuteScript('callFedCm()') + self.WaitForCondition(self.FedCmDialogCondition) + + self._driver.CancelFedCmDialog() + self.assertRaises(chromedriver.NoSuchAlert, self._driver.GetAccounts) + token = self._driver.ExecuteScript('return getResult()') + self.assertEqual('Error: NetworkError: Error retrieving a token.', token) + # 'Z' in the beginning is to make test executed in the end of suite. class ZChromeStartRetryCountTest(unittest.TestCase):
diff --git a/chrome/test/chromedriver/test/webserver.py b/chrome/test/chromedriver/test/webserver.py index 7bfec0e..058a544 100644 --- a/chrome/test/chromedriver/test/webserver.py +++ b/chrome/test/chromedriver/test/webserver.py
@@ -23,8 +23,11 @@ def SendResponseFromFile(self, path): """Sends OK response with the given file as the body.""" + headers = {} + if path.endswith(".json"): + headers["content-type"] = "application/json" with open(path, 'rb') as f: - self.SendResponse({}, f.read()) + self.SendResponse(headers, f.read()) def SendHeaders(self, headers={}, content_length=None): """Sends headers for OK response.""" @@ -79,6 +82,9 @@ return on_request(Request(self), Responder(self)) + def do_POST(self): + on_request(Request(self), Responder(self)) + def log_message(self, *args, **kwargs): """Overriddes base class method to disable logging.""" pass
diff --git a/chrome/test/data/chromedriver/fedcm/accounts.json b/chrome/test/data/chromedriver/fedcm/accounts.json new file mode 100644 index 0000000..beea4d1 --- /dev/null +++ b/chrome/test/data/chromedriver/fedcm/accounts.json
@@ -0,0 +1,17 @@ +{ + "accounts": [{ + "id": "1234", + "given_name": "John", + "name": "John Doe", + "email": "john_doe@idp.example", + "picture": "https://idp.example/profile/123", + "approved_clients": ["123", "456", "789"] + }, { + "id": "5678", + "given_name": "Aisha", + "name": "Aisha Ahmad", + "email": "aisha@idp.example", + "picture": "https://idp.example/profile/567", + "approved_clients": [] + }] +}
diff --git a/chrome/test/data/chromedriver/fedcm/client_metadata.json b/chrome/test/data/chromedriver/fedcm/client_metadata.json new file mode 100644 index 0000000..ddde867a --- /dev/null +++ b/chrome/test/data/chromedriver/fedcm/client_metadata.json
@@ -0,0 +1,4 @@ +{ + "privacy_policy_url": "https://rp.example/privacy_policy.html", + "terms_of_service_url": "https://rp.example/terms_of_service.html" +}
diff --git a/chrome/test/data/chromedriver/fedcm/fedcm.json b/chrome/test/data/chromedriver/fedcm/fedcm.json new file mode 100644 index 0000000..cd3974df --- /dev/null +++ b/chrome/test/data/chromedriver/fedcm/fedcm.json
@@ -0,0 +1,6 @@ +{ + "accounts_endpoint": "accounts.json", + "client_metadata_endpoint": "client_metadata.json", + "id_assertion_endpoint": "token.json", + "signin_url": "https://idp.example/signin" +}
diff --git a/chrome/test/data/chromedriver/fedcm/token.json b/chrome/test/data/chromedriver/fedcm/token.json new file mode 100644 index 0000000..ba6edfe --- /dev/null +++ b/chrome/test/data/chromedriver/fedcm/token.json
@@ -0,0 +1,3 @@ +{ + "token": "token" +}
diff --git a/chrome/test/data/extensions/api_test/autofill_private/test.js b/chrome/test/data/extensions/api_test/autofill_private/test.js index 038ec1d..871ec0d 100644 --- a/chrome/test/data/extensions/api_test/autofill_private/test.js +++ b/chrome/test/data/extensions/api_test/autofill_private/test.js
@@ -541,6 +541,12 @@ chrome.autofillPrivate.isValidIban(IBAN_VALUE, handler1); }, + + function authenticateUserAndFlipMandatoryAuthToggle() { + chrome.autofillPrivate.authenticateUserAndFlipMandatoryAuthToggle(); + chrome.test.assertNoLastError(); + chrome.test.succeed(); + }, ]; /** @const */ @@ -560,6 +566,8 @@ ['addNewIbanNoNickname', 'updateExistingIban_WithNickname'], 'removeExistingIban': ['addNewIbanNoNickname', 'removeExistingIban'], 'isValidIban': ['isValidIban'], + 'authenticateUserAndFlipMandatoryAuthToggle': + ['authenticateUserAndFlipMandatoryAuthToggle'], }; var testConfig = window.location.search.substring(1);
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index c550531..b6bca1b 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -207,6 +207,8 @@ "//net", ] + configs += [ "//build/config/compiler:enable_arc" ] + frameworks = [ "AppKit.framework", "CoreServices.framework", @@ -370,6 +372,8 @@ "mac/setup/ks_tickets.mm", ] + configs += [ "//build/config/compiler:enable_arc" ] + deps = [ "//base" ] } } @@ -600,6 +604,8 @@ "util/mac_util.mm", ] + configs += [ "//build/config/compiler:enable_arc" ] + frameworks = [ "Foundation.framework" ] } @@ -873,6 +879,8 @@ "//third_party/ocmock", ] + configs += [ "//build/config/compiler:enable_arc" ] + data += [ "//chrome/test/data/updater/CountingMetrics.plist", "//chrome/test/data/updater/Keystone.ticketstore",
diff --git a/chrome/updater/configurator.cc b/chrome/updater/configurator.cc index 69f1510b..ad331c4 100644 --- a/chrome/updater/configurator.cc +++ b/chrome/updater/configurator.cc
@@ -225,7 +225,7 @@ updater::GetInstallDirectory(GetUpdaterScope()); return optional_result.has_value() ? absl::optional<base::FilePath>( - optional_result.value().AppendASCII(kCrxCachePath)) + optional_result.value().AppendASCII("crx_cache")) : absl::nullopt; } #endif
diff --git a/chrome/updater/configurator.h b/chrome/updater/configurator.h index f91ef48..515ae6e 100644 --- a/chrome/updater/configurator.h +++ b/chrome/updater/configurator.h
@@ -42,10 +42,6 @@ class PolicyService; class UpdaterPrefs; -#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) -inline constexpr const char* kCrxCachePath = "crx_cache"; -#endif - // This class is free-threaded. Its instance is shared by multiple sequences and // it can't be mutated. class Configurator : public update_client::Configurator {
diff --git a/chrome/updater/device_management/dm_storage_mac.mm b/chrome/updater/device_management/dm_storage_mac.mm index cf55a5f..b285a5a 100644 --- a/chrome/updater/device_management/dm_storage_mac.mm +++ b/chrome/updater/device_management/dm_storage_mac.mm
@@ -5,6 +5,7 @@ #include "chrome/updater/device_management/dm_storage.h" #import <Foundation/Foundation.h> + #include <string> #include "base/files/file_path.h" @@ -14,13 +15,16 @@ #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_ioobject.h" -#include "base/mac/scoped_nsobject.h" #include "base/memory/scoped_refptr.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" #include "chrome/updater/updater_branding.h" #include "chrome/updater/util/mac_util.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace {
diff --git a/chrome/updater/ipc/ipc_names_mac.mm b/chrome/updater/ipc/ipc_names_mac.mm index 687c255..99f39a1 100644 --- a/chrome/updater/ipc/ipc_names_mac.mm +++ b/chrome/updater/ipc/ipc_names_mac.mm
@@ -10,6 +10,10 @@ #include "chrome/updater/updater_version.h" #include "mojo/public/cpp/platform/named_platform_channel.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { mojo::NamedPlatformChannel::ServerName GetUpdateServiceInternalServerName(
diff --git a/chrome/updater/lock_mac.mm b/chrome/updater/lock_mac.mm index 591a1dee..575a49bd 100644 --- a/chrome/updater/lock_mac.mm +++ b/chrome/updater/lock_mac.mm
@@ -20,6 +20,10 @@ #include "chrome/updater/updater_branding.h" #include "chrome/updater/updater_scope.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace { // Mach service name prefix/suffix for the global lock. @@ -86,7 +90,7 @@ private: // The Mach port representing the held lock itself. We only care about - // service ownership; no messages are transfered with this port. + // service ownership; no messages are transferred with this port. base::mac::ScopedMachReceiveRight receive_right_; };
diff --git a/chrome/updater/mac/BUILD.gn b/chrome/updater/mac/BUILD.gn index f5b6de6..137991b8 100644 --- a/chrome/updater/mac/BUILD.gn +++ b/chrome/updater/mac/BUILD.gn
@@ -96,6 +96,8 @@ "privileged_helper/service_protocol.h", ] + configs += [ "//build/config/compiler:enable_arc" ] + deps = [ ":helper_header", "//base", @@ -148,6 +150,8 @@ "//chrome/updater:constants_prod", ] + configs += [ "//build/config/compiler:enable_arc" ] + frameworks = [ "Foundation.framework", "Security.framework", @@ -330,6 +334,8 @@ "//chrome/updater:version_header", ] + configs += [ "//build/config/compiler:enable_arc" ] + visibility = [ ":ksadmin", ":ksadmin_test", @@ -396,6 +402,8 @@ frameworks = [ "CoreFoundation.framework" ] + configs += [ "//build/config/compiler:enable_arc" ] + if (is_asan) { # asan injects a dylib that we package in ../MacOS. ldflags = [ "-Wl,-rpath,@executable_path/../MacOS" ]
diff --git a/chrome/updater/mac/install_from_archive.mm b/chrome/updater/mac/install_from_archive.mm index a44d2643..fb6ed08d 100644 --- a/chrome/updater/mac/install_from_archive.mm +++ b/chrome/updater/mac/install_from_archive.mm
@@ -22,7 +22,6 @@ #include "base/functional/bind.h" #include "base/functional/callback.h" #include "base/logging.h" -#include "base/mac/scoped_nsobject.h" #include "base/numerics/checked_math.h" #include "base/path_service.h" #include "base/process/launch.h" @@ -40,6 +39,10 @@ #include "chrome/updater/util/util.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace {
diff --git a/chrome/updater/mac/keystone/ksadmin.mm b/chrome/updater/mac/keystone/ksadmin.mm index 04a56c1..2e1ab24 100644 --- a/chrome/updater/mac/keystone/ksadmin.mm +++ b/chrome/updater/mac/keystone/ksadmin.mm
@@ -45,6 +45,10 @@ #include "chrome/updater/util/util.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace { @@ -197,7 +201,7 @@ const absl::optional<base::FilePath> path = GetUpdaterExecutablePath(scope); if (path && - [[NSFileManager defaultManager] + [NSFileManager.defaultManager fileExistsAtPath:base::mac::FilePathToNSString(path.value())]) { // Updater is already installed. return; @@ -211,7 +215,7 @@ const absl::optional<base::FilePath> setup_path = GetUpdaterExecutablePath( IsSystemShim() ? UpdaterScope::kSystem : UpdaterScope::kUser); if (!setup_path || - ![[NSFileManager defaultManager] + ![NSFileManager.defaultManager fileExistsAtPath:base::mac::FilePathToNSString(setup_path.value())]) { return; } @@ -301,13 +305,13 @@ KSTicket* KSAdminApp::TicketFromAppState( const updater::UpdateService::AppState& state) { - return [[[KSTicket alloc] + return [[KSTicket alloc] initWithAppId:base::SysUTF8ToNSString(state.app_id) version:base::SysUTF8ToNSString(state.version.GetString()) ecp:state.ecp tag:base::SysUTF8ToNSString(state.ap) brandCode:base::SysUTF8ToNSString(state.brand_code) - brandPath:state.brand_path] autorelease]; + brandPath:state.brand_path]; } scoped_refptr<UpdateService> KSAdminApp::ServiceProxy(
diff --git a/chrome/updater/mac/keystone/ksinstall.mm b/chrome/updater/mac/keystone/ksinstall.mm index 06a08a5e..957b69b 100644 --- a/chrome/updater/mac/keystone/ksinstall.mm +++ b/chrome/updater/mac/keystone/ksinstall.mm
@@ -31,6 +31,10 @@ #include "chrome/updater/util/mac_util.h" #include "chrome/updater/util/util.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace {
diff --git a/chrome/updater/mac/privileged_helper/main.mm b/chrome/updater/mac/privileged_helper/main.mm index d830069..ccbe2fb6 100644 --- a/chrome/updater/mac/privileged_helper/main.mm +++ b/chrome/updater/mac/privileged_helper/main.mm
@@ -9,6 +9,10 @@ #include "base/threading/platform_thread.h" #include "chrome/updater/mac/privileged_helper/server.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + int main(int argc, const char* argv[]) { base::PlatformThread::SetName("UpdaterHelperMain"); base::CommandLine::Init(argc, argv);
diff --git a/chrome/updater/mac/privileged_helper/privileged_helper_unittests.mm b/chrome/updater/mac/privileged_helper/privileged_helper_unittests.mm index 0be980c0..3c2b723 100644 --- a/chrome/updater/mac/privileged_helper/privileged_helper_unittests.mm +++ b/chrome/updater/mac/privileged_helper/privileged_helper_unittests.mm
@@ -10,6 +10,10 @@ #include "chrome/updater/updater_branding.h" #include "testing/gtest/include/gtest/gtest.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
diff --git a/chrome/updater/mac/privileged_helper/server.h b/chrome/updater/mac/privileged_helper/server.h index 5b023ae..78c21cf 100644 --- a/chrome/updater/mac/privileged_helper/server.h +++ b/chrome/updater/mac/privileged_helper/server.h
@@ -5,7 +5,6 @@ #ifndef CHROME_UPDATER_MAC_PRIVILEGED_HELPER_SERVER_H_ #define CHROME_UPDATER_MAC_PRIVILEGED_HELPER_SERVER_H_ -#include "base/mac/scoped_nsobject.h" #include "base/memory/scoped_refptr.h" #include "base/sequence_checker.h" #include "base/task/sequenced_task_runner.h" @@ -13,6 +12,10 @@ #include "chrome/updater/app/app.h" #include "chrome/updater/mac/privileged_helper/service.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { class PrivilegedHelperServer : public App { @@ -39,8 +42,8 @@ scoped_refptr<base::SequencedTaskRunner> main_task_runner_; scoped_refptr<PrivilegedHelperService> service_; - base::scoped_nsobject<NSXPCListener> service_listener_; - base::scoped_nsobject<PrivilegedHelperServiceXPCDelegate> service_delegate_; + NSXPCListener* __strong service_listener_; + PrivilegedHelperServiceXPCDelegate* __strong service_delegate_; int tasks_running_ = 0; };
diff --git a/chrome/updater/mac/privileged_helper/server.mm b/chrome/updater/mac/privileged_helper/server.mm index 4a4b08e7..d107a5bb 100644 --- a/chrome/updater/mac/privileged_helper/server.mm +++ b/chrome/updater/mac/privileged_helper/server.mm
@@ -19,6 +19,10 @@ #include "chrome/updater/mac/privileged_helper/helper_branding.h" #include "chrome/updater/updater_branding.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace { @@ -32,12 +36,12 @@ void PrivilegedHelperServer::Initialize() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - service_delegate_.reset([[PrivilegedHelperServiceXPCDelegate alloc] + service_delegate_ = [[PrivilegedHelperServiceXPCDelegate alloc] initWithService:service_ - server:scoped_refptr<PrivilegedHelperServer>(this)]); - service_listener_.reset([[NSXPCListener alloc] - initWithMachServiceName:base::SysUTF8ToNSString(PRIVILEGED_HELPER_NAME)]); - service_listener_.get().delegate = service_delegate_.get(); + server:scoped_refptr<PrivilegedHelperServer>(this)]; + service_listener_ = [[NSXPCListener alloc] + initWithMachServiceName:base::SysUTF8ToNSString(PRIVILEGED_HELPER_NAME)]; + service_listener_.delegate = service_delegate_; [service_listener_ resume]; } @@ -48,8 +52,8 @@ void PrivilegedHelperServer::Uninitialize() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - service_delegate_.reset(); - service_listener_.reset(); + service_delegate_ = nil; + service_listener_ = nil; Uninstall(); }
diff --git a/chrome/updater/mac/privileged_helper/service.mm b/chrome/updater/mac/privileged_helper/service.mm index 3e99193..5b9174c 100644 --- a/chrome/updater/mac/privileged_helper/service.mm +++ b/chrome/updater/mac/privileged_helper/service.mm
@@ -4,12 +4,8 @@ #include "chrome/updater/mac/privileged_helper/service.h" -#include "base/memory/raw_ptr.h" -#import "base/task/sequenced_task_runner.h" - #import <Foundation/Foundation.h> #include <Security/Security.h> - #include <pwd.h> #include <unistd.h> @@ -27,7 +23,7 @@ #include "base/mac/foundation_util.h" #include "base/mac/mac_util.h" #include "base/mac/scoped_cftyperef.h" -#include "base/mac/scoped_nsobject.h" +#include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/process/launch.h" #include "base/strings/strcat.h" @@ -40,6 +36,10 @@ #include "chrome/updater/updater_branding.h" #include "chrome/updater/util/util.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + @interface PrivilegedHelperServiceImpl : NSObject <PrivilegedHelperServiceProtocol> { raw_ptr<updater::PrivilegedHelperService> _service; @@ -66,12 +66,15 @@ #pragma mark PrivilegedHelperServiceProtocol - (void)setupSystemUpdaterWithBrowserPath:(NSString* _Nonnull)browserPath reply:(void (^_Nonnull)(int rc))reply { - auto cb = base::BindOnce(base::RetainBlock(^(const int rc) { + auto cb = base::BindOnce(^(const int rc) { VLOG(0) << "SetupSystemUpdaterWithUpdaterPath complete. Result: " << rc; - if (reply) + if (reply) { reply(rc); - _server->TaskCompleted(); - })); + } + // This block is fired and then released, so this strong reference to the + // PrivilegedHelperServiceProtocol is OK. + self->_server->TaskCompleted(); + }); _server->TaskStarted(); _callbackRunner->PostTask( @@ -108,11 +111,10 @@ newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(PrivilegedHelperServiceProtocol)]; - base::scoped_nsobject<PrivilegedHelperServiceImpl> obj( + newConnection.exportedObject = [[PrivilegedHelperServiceImpl alloc] initWithService:_service.get() server:_server - callbackRunner:_callbackRunner]); - newConnection.exportedObject = obj.get(); + callbackRunner:_callbackRunner]; [newConnection resume]; return YES; } @@ -195,8 +197,8 @@ base::ScopedCFTypeRef<SecStaticCodeRef> code; base::ScopedCFTypeRef<CFErrorRef> errors; if (SecStaticCodeCreateWithPath( - base::mac::NSToCFCast(base::mac::FilePathToNSURL(updater_app_bundle)), - kSecCSDefaultFlags, code.InitializeInto()) != errSecSuccess) { + base::mac::FilePathToCFURL(updater_app_bundle), kSecCSDefaultFlags, + code.InitializeInto()) != errSecSuccess) { return false; } if (SecRequirementCreateWithString(
diff --git a/chrome/updater/mac/setup/keystone.mm b/chrome/updater/mac/setup/keystone.mm index ff78bb6..ff66e75f 100644 --- a/chrome/updater/mac/setup/keystone.mm +++ b/chrome/updater/mac/setup/keystone.mm
@@ -15,7 +15,6 @@ #include "base/logging.h" #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" -#include "base/mac/scoped_nsobject.h" #include "base/process/launch.h" #include "base/process/process.h" #include "base/strings/string_split.h" @@ -32,10 +31,13 @@ #include "chrome/updater/util/util.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + // Class to read the Keystone apps' client-regulated-counting data. @interface CountingMetricsStore : NSObject { - base::scoped_nsobject<NSDictionary<NSString*, NSDictionary<NSString*, id>*>> - _metrics; + NSDictionary<NSString*, NSDictionary<NSString*, id>*>* __strong _metrics; } + (instancetype)storeAtPath:(const base::FilePath&)path; @@ -48,22 +50,19 @@ @implementation CountingMetricsStore + (instancetype)storeAtPath:(const base::FilePath&)path { - return [[[CountingMetricsStore alloc] + return [[CountingMetricsStore alloc] initWithURL:[base::mac::FilePathToNSURL(path) - URLByAppendingPathComponent:@"CountingMetrics.plist"]] - autorelease]; + URLByAppendingPathComponent:@"CountingMetrics.plist"]]; } - (instancetype)initWithURL:(NSURL*)url { if ((self = [super init])) { NSError* error = nil; - _metrics.reset([[NSDictionary alloc] initWithContentsOfURL:url - error:&error]); + _metrics = [[NSDictionary alloc] initWithContentsOfURL:url error:&error]; if (error) { LOG(WARNING) << "Failed to read client-regulated-counting data."; - [self release]; - return nil; + self = nil; } } return self; @@ -135,7 +134,7 @@ // CopyDir() does not remove files in destination. // Uninstalls the existing Keystone bundle to avoid possible left-over // files that breaks bundle signature. A manual delete follows - // in case uninstall is unsucessful. + // in case uninstall is unsuccessful. UninstallKeystone(scope); const base::FilePath dest_keystone_bundle_path = dest_path.Append(FILE_PATH_LITERAL(KEYSTONE_NAME ".bundle"));
diff --git a/chrome/updater/mac/setup/ks_tickets.h b/chrome/updater/mac/setup/ks_tickets.h index a203fed9..54f5b39b 100644 --- a/chrome/updater/mac/setup/ks_tickets.h +++ b/chrome/updater/mac/setup/ks_tickets.h
@@ -7,6 +7,10 @@ #import <Foundation/Foundation.h> +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + extern NSString* _Nonnull const kCRUTicketBrandKey; extern NSString* _Nonnull const kCRUTicketTagKey; @@ -21,23 +25,23 @@ @end @interface KSTicket : NSObject <NSSecureCoding> { - NSString* productID_; - NSString* version_; - NSString* brandCode_; - KSPathExistenceChecker* existenceChecker_; - NSURL* serverURL_; - NSString* serverType_; - NSDate* creationDate_; - NSString* tag_; - NSString* tagPath_; - NSString* tagKey_; - NSString* brandPath_; - NSString* brandKey_; - NSString* versionPath_; - NSString* versionKey_; - NSString* cohort_; - NSString* cohortHint_; - NSString* cohortName_; + NSString* __strong productID_; + NSString* __strong version_; + NSString* __strong brandCode_; + KSPathExistenceChecker* __strong existenceChecker_; + NSURL* __strong serverURL_; + NSString* __strong serverType_; + NSDate* __strong creationDate_; + NSString* __strong tag_; + NSString* __strong tagPath_; + NSString* __strong tagKey_; + NSString* __strong brandPath_; + NSString* __strong brandKey_; + NSString* __strong versionPath_; + NSString* __strong versionKey_; + NSString* __strong cohort_; + NSString* __strong cohortHint_; + NSString* __strong cohortName_; int32_t ticketVersion_; }
diff --git a/chrome/updater/mac/setup/ks_tickets.mm b/chrome/updater/mac/setup/ks_tickets.mm index f6d159a..28ba94a3 100644 --- a/chrome/updater/mac/setup/ks_tickets.mm +++ b/chrome/updater/mac/setup/ks_tickets.mm
@@ -14,6 +14,10 @@ #include "base/notreached.h" #include "base/strings/sys_string_conversions.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + NSString* const kCRUTicketBrandKey = @"KSBrandID"; NSString* const kCRUTicketTagKey = @"KSChannelID"; @@ -53,8 +57,7 @@ NSDictionary* store = nil; NSKeyedUnarchiver* unpacker = - [[[NSKeyedUnarchiver alloc] initForReadingFromData:storeData - error:&error] autorelease]; + [[NSKeyedUnarchiver alloc] initForReadingFromData:storeData error:&error]; if (!unpacker) { VLOG(0) << base::SysNSStringToUTF8( [NSString stringWithFormat:@"Ticket error %@", error]); @@ -77,10 +80,10 @@ VLOG(0) << "Error unpacking ticket store: " << unpacker.error; SCOPED_CRASH_KEY_STRING32( "updater ticket error", "description", - base::SysNSStringToUTF8([unpacker.error localizedDescription])); + base::SysNSStringToUTF8(unpacker.error.localizedDescription)); SCOPED_CRASH_KEY_STRING32( "updater ticket error", "reason", - base::SysNSStringToUTF8([unpacker.error localizedFailureReason])); + base::SysNSStringToUTF8(unpacker.error.localizedFailureReason)); base::debug::DumpWithoutCrashing(); return nil; } @@ -104,22 +107,16 @@ return YES; } -- (void)dealloc { - [path_ release]; - [super dealloc]; -} - - (instancetype)initWithCoder:(NSCoder*)coder { if ((self = [super init])) { - path_ = [[coder decodeObjectOfClass:[NSString class] - forKey:@"path"] retain]; + path_ = [coder decodeObjectOfClass:[NSString class] forKey:@"path"]; } return self; } - (instancetype)initWithFilePath:(const base::FilePath&)filePath { if ((self = [super init])) { - path_ = [base::mac::FilePathToNSString(filePath) retain]; + path_ = base::mac::FilePathToNSString(filePath); } return self; } @@ -144,15 +141,10 @@ return YES; } -- (void)dealloc { - [bundle_id_ release]; - [super dealloc]; -} - - (instancetype)initWithCoder:(NSCoder*)coder { if ((self = [super init])) { - bundle_id_ = [[coder decodeObjectOfClass:[NSString class] - forKey:@"bundle_id"] retain]; + bundle_id_ = [coder decodeObjectOfClass:[NSString class] + forKey:@"bundle_id"]; } return self; } @@ -177,15 +169,9 @@ return YES; } -- (void)dealloc { - [query_ release]; - [super dealloc]; -} - - (instancetype)initWithCoder:(NSCoder*)coder { if ((self = [super init])) { - query_ = [[coder decodeObjectOfClass:[NSString class] - forKey:@"query"] retain]; + query_ = [coder decodeObjectOfClass:[NSString class] forKey:@"query"]; } return self; } @@ -264,42 +250,40 @@ - (instancetype)initWithCoder:(NSCoder*)coder { if ((self = [super init])) { - productID_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketProductIDKey] retain]; - version_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketVersionKey] retain]; + productID_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketProductIDKey]; + version_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketVersionKey]; if ([[coder decodeObjectForKey:kKSTicketExistenceCheckerKey] isKindOfClass:[KSPathExistenceChecker class]]) { existenceChecker_ = - [[coder decodeObjectOfClass:[KSPathExistenceChecker class] - forKey:kKSTicketExistenceCheckerKey] retain]; + [coder decodeObjectOfClass:[KSPathExistenceChecker class] + forKey:kKSTicketExistenceCheckerKey]; } - serverURL_ = [[self decodeServerURL:coder] retain]; - creationDate_ = - [[coder decodeObjectOfClass:[NSDate class] - forKey:kKSTicketCreationDateKey] retain]; - serverType_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketServerTypeKey] retain]; - tag_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketTagKey] retain]; - tagPath_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketTagPathKey] retain]; - tagKey_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketTagKeyKey] retain]; - brandPath_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketBrandPathKey] retain]; - brandKey_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketBrandKeyKey] retain]; - versionPath_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketVersionPathKey] retain]; - versionKey_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketVersionKeyKey] retain]; - cohort_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketCohortKey] retain]; - cohortHint_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketCohortHintKey] retain]; - cohortName_ = [[coder decodeObjectOfClass:[NSString class] - forKey:kKSTicketCohortNameKey] retain]; + serverURL_ = [self decodeServerURL:coder]; + creationDate_ = [coder decodeObjectOfClass:[NSDate class] + forKey:kKSTicketCreationDateKey]; + serverType_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketServerTypeKey]; + tag_ = [coder decodeObjectOfClass:[NSString class] forKey:kKSTicketTagKey]; + tagPath_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketTagPathKey]; + tagKey_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketTagKeyKey]; + brandPath_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketBrandPathKey]; + brandKey_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketBrandKeyKey]; + versionPath_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketVersionPathKey]; + versionKey_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketVersionKeyKey]; + cohort_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketCohortKey]; + cohortHint_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketCohortHintKey]; + cohortName_ = [coder decodeObjectOfClass:[NSString class] + forKey:kKSTicketCohortNameKey]; ticketVersion_ = [coder decodeInt32ForKey:kKSTicketTicketVersionKey]; } return self; @@ -312,53 +296,30 @@ brandCode:(NSString*)brandCode brandPath:(const base::FilePath&)brandPath { if ((self = [super init])) { - productID_ = [appId retain]; - version_ = [version retain]; + productID_ = appId; + version_ = version; if (!ecp.empty()) { existenceChecker_ = [[KSPathExistenceChecker alloc] initWithFilePath:ecp]; - tagPath_ = [[NSString stringWithFormat:@"%@/Contents/Info.plist", - base::mac::FilePathToNSString(ecp)] - retain]; - tagKey_ = [kCRUTicketTagKey retain]; + tagPath_ = [NSString stringWithFormat:@"%@/Contents/Info.plist", + base::mac::FilePathToNSString(ecp)]; + tagKey_ = kCRUTicketTagKey; } - tag_ = [tag retain]; + tag_ = tag; - brandCode_ = [brandCode retain]; + brandCode_ = brandCode; if (!brandPath.empty()) { - brandPath_ = [base::mac::FilePathToNSString(brandPath) retain]; - brandKey_ = [kCRUTicketBrandKey retain]; + brandPath_ = base::mac::FilePathToNSString(brandPath); + brandKey_ = kCRUTicketBrandKey; } - serverURL_ = [[NSURL - URLWithString:@"https://tools.google.com/service/update2"] retain]; - serverType_ = [@"Omaha" retain]; + serverURL_ = + [NSURL URLWithString:@"https://tools.google.com/service/update2"]; + serverType_ = @"Omaha"; ticketVersion_ = 1; } return self; } -- (void)dealloc { - [productID_ release]; - [version_ release]; - [existenceChecker_ release]; - [serverURL_ release]; - [creationDate_ release]; - [serverType_ release]; - [tag_ release]; - [tagPath_ release]; - [tagKey_ release]; - [brandCode_ release]; - [brandPath_ release]; - [brandKey_ release]; - [versionPath_ release]; - [versionKey_ release]; - [cohort_ release]; - [cohortHint_ release]; - [cohortName_ release]; - - [super dealloc]; -} - - (void)encodeWithCoder:(NSCoder*)coder { [coder encodeObject:productID_ forKey:kKSTicketProductIDKey]; [coder encodeObject:version_ forKey:kKSTicketVersionKey]; @@ -455,7 +416,7 @@ // Dates used to be parsed and stored as GMT and printed in GMT. That // changed in 10.7 to be GMT with timezone information, so use a custom // description string that matches our old output. - NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; + NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; NSString* gmtDate = [dateFormatter stringFromDate:creationDate_]; @@ -485,7 +446,7 @@ id plistContent = [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListImmutable - format:0 + format:nil error:nil]; if (!plistContent || ![plistContent isKindOfClass:[NSDictionary class]]) { return nil;
diff --git a/chrome/updater/mac/setup/ks_tickets_unittest.mm b/chrome/updater/mac/setup/ks_tickets_unittest.mm index cc94c5c..bacb828 100644 --- a/chrome/updater/mac/setup/ks_tickets_unittest.mm +++ b/chrome/updater/mac/setup/ks_tickets_unittest.mm
@@ -10,6 +10,10 @@ #include "chrome/common/chrome_paths.h" #include "testing/gtest/include/gtest/gtest.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { TEST(KSTicketsTest, Decode) {
diff --git a/chrome/updater/mac/setup/setup.mm b/chrome/updater/mac/setup/setup.mm index 96fe8a5..ce58fdec 100644 --- a/chrome/updater/mac/setup/setup.mm +++ b/chrome/updater/mac/setup/setup.mm
@@ -17,7 +17,6 @@ #include "base/logging.h" #include "base/mac/bundle_locations.h" #include "base/mac/foundation_util.h" -#include "base/mac/scoped_nsobject.h" #include "base/path_service.h" #include "base/process/launch.h" #include "base/process/process.h" @@ -44,6 +43,10 @@ #include "components/crash/core/common/crash_key.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace { @@ -96,12 +99,11 @@ bool CreateWakeLaunchdJobPlist(UpdaterScope scope) { base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::BlockingType::MAY_BLOCK); - absl::optional<base::ScopedCFTypeRef<CFDictionaryRef>> plist = - CreateWakeLaunchdPlist(scope); + NSDictionary* plist = CreateWakeLaunchdPlist(scope); if (!plist) { return false; } - return EnsureWakeLaunchItemPresence(scope, *plist); + return EnsureWakeLaunchItemPresence(scope, plist); } void CleanAfterInstallFailure(UpdaterScope scope) {
diff --git a/chrome/updater/mac/setup/setup_unittest.mm b/chrome/updater/mac/setup/setup_unittest.mm index 7293b86..91c2e40 100644 --- a/chrome/updater/mac/setup/setup_unittest.mm +++ b/chrome/updater/mac/setup/setup_unittest.mm
@@ -20,6 +20,10 @@ #include "chrome/updater/updater_scope.h" #include "testing/gtest/include/gtest/gtest.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater_setup { namespace {
diff --git a/chrome/updater/mac/setup/wake_task.h b/chrome/updater/mac/setup/wake_task.h index 208695e..d1cfe723 100644 --- a/chrome/updater/mac/setup/wake_task.h +++ b/chrome/updater/mac/setup/wake_task.h
@@ -5,16 +5,16 @@ #ifndef CHROME_UPDATER_MAC_SETUP_WAKE_TASK_H_ #define CHROME_UPDATER_MAC_SETUP_WAKE_TASK_H_ -#include <CoreFoundation/CoreFoundation.h> +#include <Foundation/Foundation.h> -#include "base/mac/scoped_cftyperef.h" #include "chrome/updater/updater_scope.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace updater { -absl::optional<base::ScopedCFTypeRef<CFDictionaryRef>> CreateWakeLaunchdPlist( - UpdaterScope scope); +// Returns the dictionary to use for the wake launchd plist. Can return nil on +// error (e.g. if the target cannot be found). +NSDictionary* CreateWakeLaunchdPlist(UpdaterScope scope); } // namespace updater
diff --git a/chrome/updater/mac/setup/wake_task.mm b/chrome/updater/mac/setup/wake_task.mm index 13f7755b..59d592d 100644 --- a/chrome/updater/mac/setup/wake_task.mm +++ b/chrome/updater/mac/setup/wake_task.mm
@@ -4,11 +4,10 @@ #include "chrome/updater/mac/setup/wake_task.h" -#include <CoreFoundation/CoreFoundation.h> +#include <Foundation/Foundation.h> #include "base/files/file_path.h" #include "base/mac/foundation_util.h" -#include "base/mac/scoped_cftyperef.h" #include "base/strings/strcat.h" #include "base/strings/sys_string_conversions.h" #include "chrome/updater/constants.h" @@ -18,6 +17,10 @@ #include "chrome/updater/util/util.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace { @@ -50,11 +53,10 @@ } // namespace -absl::optional<base::ScopedCFTypeRef<CFDictionaryRef>> CreateWakeLaunchdPlist( - UpdaterScope scope) { +NSDictionary* CreateWakeLaunchdPlist(UpdaterScope scope) { absl::optional<base::FilePath> target = GetWakeTaskTarget(scope); if (!target) { - return absl::nullopt; + return nil; } // See the man page for launchd.plist. @@ -80,9 +82,7 @@ @"AssociatedBundleIdentifiers" : @MAC_BUNDLE_IDENTIFIER_STRING }; - return base::ScopedCFTypeRef<CFDictionaryRef>( - base::mac::CFCast<CFDictionaryRef>(launchd_plist), - base::scoped_policy::RETAIN); + return launchd_plist; } } // namespace updater
diff --git a/chrome/updater/mac/setup/wake_task_unittest.mm b/chrome/updater/mac/setup/wake_task_unittest.mm index 61f80b67..5ba35fc 100644 --- a/chrome/updater/mac/setup/wake_task_unittest.mm +++ b/chrome/updater/mac/setup/wake_task_unittest.mm
@@ -4,10 +4,9 @@ #include "chrome/updater/mac/setup/wake_task.h" -#include <CoreFoundation/CoreFoundation.h> +#include <Foundation/Foundation.h> #include "base/files/file_path.h" -#include "base/mac/foundation_util.h" #include "base/mac/scoped_cftyperef.h" #include "base/strings/strcat.h" #include "base/strings/sys_string_conversions.h" @@ -18,6 +17,10 @@ #include "chrome/updater/util/util.h" #include "testing/gtest/include/gtest/gtest.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { // This is a change detector test. If the wake plist changes, macOS may notify @@ -69,9 +72,8 @@ }; break; } - EXPECT_TRUE([expected - isEqualToDictionary:base::mac::CFToNSCast( - *CreateWakeLaunchdPlist(GetTestScope()))]); + EXPECT_TRUE( + [expected isEqualToDictionary:CreateWakeLaunchdPlist(GetTestScope())]); } } // namespace updater
diff --git a/chrome/updater/mac/signing/pipeline.py b/chrome/updater/mac/signing/pipeline.py index 05afcf1..6d3b842 100644 --- a/chrome/updater/mac/signing/pipeline.py +++ b/chrome/updater/mac/signing/pipeline.py
@@ -113,7 +113,6 @@ def sign_all(orig_paths, config, disable_packaging=False, - notarization=model.NotarizeAndStapleLevel.STAPLE, skip_brands=[], channels=[]): """Code signs, packages, and signs the package, placing the result into @@ -124,9 +123,6 @@ orig_paths: A |model.Paths| object. config: The |config.CodeSignConfig| object. disable_packaging: Ignored. - notarization: The level of notarization to be performed. If - |disable_packaging| is False, the dmg will undergo the same - notarization. skip_brands: Ignored. channels: Ignored. """ @@ -138,7 +134,7 @@ config.packaging_basename) _sign_app(paths, config, dest_dir) - if notarization.should_notarize(): + if config.notarize.should_notarize(): zip_file = os.path.join(notary_paths.work, config.packaging_basename + '.zip') commands.run_command([ @@ -149,10 +145,10 @@ uuid = notarize.submit(zip_file, config) # Wait for the app notarization result to come back and staple. - if notarization.should_wait(): + if config.notarize.should_wait(): for _ in notarize.wait_for_results([uuid], config): pass # We are only waiting for a single notarization. - if notarization.should_staple(): + if config.notarize.should_staple(): notarize.staple_bundled_parts( # Only staple to the outermost app. parts.get_parts(config)[-1:], @@ -169,9 +165,9 @@ dmg_path = _package_and_sign_dmg(package_paths, config) # Notarize the package, then staple. - if notarization.should_wait(): + if config.notarize.should_wait(): for _ in notarize.wait_for_results( [notarize.submit(dmg_path, config)], config): pass # We are only waiting for a single notarization. - if notarization.should_staple(): + if config.notarize.should_staple(): notarize.staple(dmg_path)
diff --git a/chrome/updater/net/network_fetcher_mac.mm b/chrome/updater/net/network_fetcher_mac.mm index 577e763..124bf21 100644 --- a/chrome/updater/net/network_fetcher_mac.mm +++ b/chrome/updater/net/network_fetcher_mac.mm
@@ -18,7 +18,6 @@ #include "base/functional/callback.h" #include "base/functional/callback_helpers.h" #import "base/mac/foundation_util.h" -#import "base/mac/scoped_nsobject.h" #include "base/memory/scoped_refptr.h" #include "base/sequence_checker.h" #include "base/strings/string_util.h" @@ -32,6 +31,10 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + using ResponseStartedCallback = update_client::NetworkFetcher::ResponseStartedCallback; using ProgressCallback = update_client::NetworkFetcher::ProgressCallback; @@ -91,7 +94,7 @@ @implementation CRUUpdaterNetworkDataDelegate { PostRequestCompleteCallback _postRequestCompleteCallback; - base::scoped_nsobject<NSMutableData> _downloadedData; + NSMutableData* __strong _downloadedData; } - (instancetype) @@ -104,7 +107,7 @@ initWithResponseStartedCallback:std::move(responseStartedCallback) progressCallback:progressCallback]) { _postRequestCompleteCallback = std::move(postRequestCompleteCallback); - _downloadedData.reset([[NSMutableData alloc] init]); + _downloadedData = [[NSMutableData alloc] init]; } return self; } @@ -222,7 +225,7 @@ willCacheResponse:(NSCachedURLResponse*)proposedResponse completionHandler: (void (^)(NSCachedURLResponse* _Nullable))completionHandler { - completionHandler(NULL); + completionHandler(nullptr); } - (void)URLSession:(NSURLSession*)session @@ -326,25 +329,24 @@ PostRequestCompleteCallback post_request_complete_callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - base::scoped_nsobject<CRUUpdaterNetworkDataDelegate> delegate( + CRUUpdaterNetworkDataDelegate* delegate = [[CRUUpdaterNetworkDataDelegate alloc] initWithResponseStartedCallback:std::move(response_started_callback) progressCallback:progress_callback postRequestCompleteCallback:std::move( - post_request_complete_callback)]); + post_request_complete_callback)]; NSURLSession* session = - [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration - defaultSessionConfiguration] + [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration + .defaultSessionConfiguration delegate:delegate delegateQueue:nil]; - base::scoped_nsobject<NSMutableURLRequest> urlRequest( - [[NSMutableURLRequest alloc] initWithURL:net::NSURLWithGURL(url)]); - [urlRequest setHTTPMethod:@"POST"]; - base::scoped_nsobject<NSData> body( - [[NSData alloc] initWithBytes:post_data.c_str() length:post_data.size()]); - [urlRequest setHTTPBody:body]; + NSMutableURLRequest* urlRequest = + [[NSMutableURLRequest alloc] initWithURL:net::NSURLWithGURL(url)]; + urlRequest.HTTPMethod = @"POST"; + urlRequest.HTTPBody = [[NSData alloc] initWithBytes:post_data.c_str() + length:post_data.size()]; [urlRequest addValue:base::SysUTF8ToNSString(content_type) forHTTPHeaderField:@"Content-Type"]; @@ -368,22 +370,22 @@ DownloadToFileCompleteCallback download_to_file_complete_callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - base::scoped_nsobject<CRUUpdaterNetworkDownloadDelegate> delegate( + CRUUpdaterNetworkDownloadDelegate* delegate = [[CRUUpdaterNetworkDownloadDelegate alloc] initWithResponseStartedCallback:std::move(response_started_callback) progressCallback:progress_callback filePath:file_path downloadToFileCompleteCallback: - std::move(download_to_file_complete_callback)]); + std::move(download_to_file_complete_callback)]; NSURLSession* session = - [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration - defaultSessionConfiguration] + [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration + .defaultSessionConfiguration delegate:delegate delegateQueue:nil]; - base::scoped_nsobject<NSMutableURLRequest> urlRequest( - [[NSMutableURLRequest alloc] initWithURL:net::NSURLWithGURL(url)]); + NSMutableURLRequest* urlRequest = + [[NSMutableURLRequest alloc] initWithURL:net::NSURLWithGURL(url)]; NSURLSessionDownloadTask* downloadTask = [session downloadTaskWithRequest:urlRequest];
diff --git a/chrome/updater/policy/mac/managed_preference_policy_manager.mm b/chrome/updater/policy/mac/managed_preference_policy_manager.mm index 5a6f23b..31d6e203 100644 --- a/chrome/updater/policy/mac/managed_preference_policy_manager.mm +++ b/chrome/updater/policy/mac/managed_preference_policy_manager.mm
@@ -7,8 +7,8 @@ #include <string> #include <vector> +#include "base/mac/bridging.h" #include "base/mac/scoped_cftyperef.h" -#include "base/mac/scoped_nsobject.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_refptr.h" #include "base/strings/sys_string_conversions.h" @@ -18,6 +18,10 @@ #include "chrome/updater/policy/manager.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { static NSString* const kManagedPreferencesUpdatePolicies = @"updatePolicies"; @@ -60,7 +64,7 @@ private: ~ManagedPreferencePolicyManager() override; - base::scoped_nsobject<CRUManagedPreferencePolicyManager> impl_; + CRUManagedPreferencePolicyManager* __strong impl_; }; ManagedPreferencePolicyManager::ManagedPreferencePolicyManager( @@ -71,11 +75,11 @@ ManagedPreferencePolicyManager::~ManagedPreferencePolicyManager() = default; bool ManagedPreferencePolicyManager::HasActiveDevicePolicies() const { - return [impl_ managed]; + return impl_.managed; } std::string ManagedPreferencePolicyManager::source() const { - return base::SysNSStringToUTF8([impl_ source]); + return base::SysNSStringToUTF8(impl_.source); } absl::optional<base::TimeDelta> @@ -199,21 +203,21 @@ NSDictionary* ReadManagedPreferencePolicyDictionary() { base::ScopedCFTypeRef<CFPropertyListRef> policies(CFPreferencesCopyAppValue( - (__bridge CFStringRef)kManagedPreferencesUpdatePolicies, - (__bridge CFStringRef)kKeystoneSharedPreferenceSuite)); + base::mac::NSToCFPtrCast(kManagedPreferencesUpdatePolicies), + base::mac::NSToCFPtrCast(kKeystoneSharedPreferenceSuite))); if (!policies) return nil; if (!CFPreferencesAppValueIsForced( - (__bridge CFStringRef)kManagedPreferencesUpdatePolicies, - (__bridge CFStringRef)kKeystoneSharedPreferenceSuite)) { + base::mac::NSToCFPtrCast(kManagedPreferencesUpdatePolicies), + base::mac::NSToCFPtrCast(kKeystoneSharedPreferenceSuite))) { return nil; } if (CFGetTypeID(policies) != CFDictionaryGetTypeID()) return nil; - return reinterpret_cast<NSDictionary*>(CFBridgingRelease(policies.release())); + return base::mac::CFToNSOwnershipCast((CFDictionaryRef)policies.release()); } scoped_refptr<PolicyManagerInterface> CreateManagedPreferencePolicyManager() {
diff --git a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm index 2f09f04..e014fc5 100644 --- a/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm +++ b/chrome/updater/policy/mac/managed_preference_policy_manager_impl.mm
@@ -4,11 +4,17 @@ #import "chrome/updater/policy/mac/managed_preference_policy_manager_impl.h" +#include <Foundation/Foundation.h> + #include "base/enterprise_util.h" -#include "base/mac/scoped_nsobject.h" +#include "base/mac/foundation_util.h" #include "chrome/updater/constants.h" #include "chrome/updater/policy/manager.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + // Constants for managed preference policy keys. static NSString* kGlobalPolicyKey = @"global"; static NSString* kUpdateDefaultKey = @"UpdateDefault"; @@ -45,14 +51,6 @@ return static_cast<int>(result); } -// Reads a policy NSString value. Returns nil for all unexpected cases. -base::scoped_nsobject<NSString> ReadPolicyString(id value) { - if ([value isKindOfClass:[NSString class]]) - return base::scoped_nsobject<NSString>([value copy]); - else - return base::scoped_nsobject<NSString>(nil); -} - // For historical reasons, "update" policy has different enum values in Manage // Preferences from the Device Management. This function converts the former // to latter. @@ -92,7 +90,7 @@ /// Class that manages Mac global-level policies. @interface CRUManagedPreferenceGlobalPolicySettings : NSObject { - base::scoped_nsobject<NSString> _downloadPreference; + NSString* __strong _downloadPreference; }; @property(nonatomic, readonly) int lastCheckPeriodMinutes; @@ -113,8 +111,8 @@ - (instancetype)initWithDictionary:(CRUAppPolicyDictionary*)policyDict { if (([super init])) { - _downloadPreference = updater::ReadPolicyString( - [policyDict objectForKey:kDownloadPreferenceKey]); + _downloadPreference = + base::mac::ObjCCast<NSString>(policyDict[kDownloadPreferenceKey]); _defaultUpdatePolicy = updater::TranslateUpdatePolicyValue( updater::ReadPolicyInteger(policyDict[kUpdateDefaultKey])); _updatesSuppressed.start_hour_ = @@ -134,7 +132,7 @@ - (NSString*)downloadPreference { if (_downloadPreference) { - return [NSString stringWithString:_downloadPreference]; + return _downloadPreference; } else { return nil; } @@ -156,8 +154,8 @@ /// Class that manages policies for a single App. @interface CRUManagedPreferenceAppPolicySettings : NSObject { - base::scoped_nsobject<NSString> _targetChannel; - base::scoped_nsobject<NSString> _targetVersionPrefix; + NSString* __strong _targetChannel; + NSString* __strong _targetVersionPrefix; } @property(nonatomic, readonly) int updatePolicy; @@ -174,15 +172,14 @@ - (instancetype)initWithDictionary:(CRUAppPolicyDictionary*)policyDict { if (([super init])) { - _updatePolicy = - updater::TranslateUpdatePolicyValue(updater::ReadPolicyInteger( - [policyDict objectForKey:kUpdateDefaultKey])); + _updatePolicy = updater::TranslateUpdatePolicyValue( + updater::ReadPolicyInteger(policyDict[kUpdateDefaultKey])); _targetChannel = - updater::ReadPolicyString([policyDict objectForKey:kTargetChannelKey]); - _targetVersionPrefix = updater::ReadPolicyString( - [policyDict objectForKey:kTargetVersionPrefixKey]); - _rollbackToTargetVersion = updater::ReadPolicyInteger( - [policyDict objectForKey:kRollbackToTargetVersionKey]); + base::mac::ObjCCast<NSString>(policyDict[kTargetChannelKey]); + _targetVersionPrefix = + base::mac::ObjCCast<NSString>(policyDict[kTargetVersionPrefixKey]); + _rollbackToTargetVersion = + updater::ReadPolicyInteger(policyDict[kRollbackToTargetVersionKey]); } return self; @@ -207,10 +204,9 @@ @end @implementation CRUManagedPreferencePolicyManager { - base::scoped_nsobject<CRUManagedPreferenceGlobalPolicySettings> _globalPolicy; - base::scoped_nsobject< - NSMutableDictionary<NSString*, CRUManagedPreferenceAppPolicySettings*>> - _appPolicies; + CRUManagedPreferenceGlobalPolicySettings* __strong _globalPolicy; + NSMutableDictionary<NSString*, CRUManagedPreferenceAppPolicySettings*>* + __strong _appPolicies; } @synthesize managed = _managed; @@ -220,24 +216,24 @@ _managed = policies.count > 0 && base::IsManagedOrEnterpriseDevice(); // Always create a global policy instance for default values. - _globalPolicy.reset([[CRUManagedPreferenceGlobalPolicySettings alloc] - initWithDictionary:nil]); + _globalPolicy = [[CRUManagedPreferenceGlobalPolicySettings alloc] + initWithDictionary:nil]; - _appPolicies.reset([[NSMutableDictionary alloc] init]); - for (NSString* appid in policies.allKeys) { + _appPolicies = [[NSMutableDictionary alloc] init]; + for (NSString* __strong appid in policies.allKeys) { if (![policies[appid] isKindOfClass:[CRUAppPolicyDictionary class]]) continue; CRUAppPolicyDictionary* policyDict = policies[appid]; appid = appid.lowercaseString; if ([appid isEqualToString:kGlobalPolicyKey]) { - _globalPolicy.reset([[CRUManagedPreferenceGlobalPolicySettings alloc] - initWithDictionary:policyDict]); + _globalPolicy = [[CRUManagedPreferenceGlobalPolicySettings alloc] + initWithDictionary:policyDict]; } else { - base::scoped_nsobject<CRUManagedPreferenceAppPolicySettings> - appSettings([[CRUManagedPreferenceAppPolicySettings alloc] - initWithDictionary:policyDict]); - [_appPolicies setObject:appSettings.get() forKey:appid]; + CRUManagedPreferenceAppPolicySettings* appSettings = + [[CRUManagedPreferenceAppPolicySettings alloc] + initWithDictionary:policyDict]; + [_appPolicies setObject:appSettings forKey:appid]; } } }
diff --git a/chrome/updater/policy/mac/managed_preference_policy_manager_impl_unittest.mm b/chrome/updater/policy/mac/managed_preference_policy_manager_impl_unittest.mm index fca259d..a462edc 100644 --- a/chrome/updater/policy/mac/managed_preference_policy_manager_impl_unittest.mm +++ b/chrome/updater/policy/mac/managed_preference_policy_manager_impl_unittest.mm
@@ -5,11 +5,14 @@ #include "chrome/updater/policy/mac/managed_preference_policy_manager_impl.h" #include "base/enterprise_util.h" -#include "base/mac/scoped_nsobject.h" #include "chrome/updater/constants.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest_mac.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { TEST(CRUManagedPreferencePolicyManagerTest, TestPolicyValues) { @@ -30,9 +33,8 @@ @"TargetVersionPrefix" : @"82.", }, }; - base::scoped_nsobject<CRUManagedPreferencePolicyManager> policyManager( - [[CRUManagedPreferencePolicyManager alloc] - initWithDictionary:policyDict]); + CRUManagedPreferencePolicyManager* policyManager = + [[CRUManagedPreferencePolicyManager alloc] initWithDictionary:policyDict]; EXPECT_NSEQ([policyManager source], @"ManagedPreference"); EXPECT_EQ([policyManager managed], base::IsManagedOrEnterpriseDevice()); @@ -66,17 +68,15 @@ TEST(CRUManagedPreferencePolicyManagerTest, TestEmptyPolicyValues) { CRUUpdatePolicyDictionary* policyDict = @{}; - base::scoped_nsobject<CRUManagedPreferencePolicyManager> policyManager( - [[CRUManagedPreferencePolicyManager alloc] - initWithDictionary:policyDict]); + CRUManagedPreferencePolicyManager* policyManager = + [[CRUManagedPreferencePolicyManager alloc] initWithDictionary:policyDict]; EXPECT_FALSE([policyManager managed]); } TEST(CRUManagedPreferencePolicyManagerTest, TestNoGlobalPolicy) { CRUUpdatePolicyDictionary* policyDict = @{@"some.app" : @{}}; - base::scoped_nsobject<CRUManagedPreferencePolicyManager> policyManager( - [[CRUManagedPreferencePolicyManager alloc] - initWithDictionary:policyDict]); + CRUManagedPreferencePolicyManager* policyManager = + [[CRUManagedPreferencePolicyManager alloc] initWithDictionary:policyDict]; EXPECT_NSEQ([policyManager source], @"ManagedPreference"); EXPECT_EQ([policyManager managed], base::IsManagedOrEnterpriseDevice()); @@ -113,9 +113,8 @@ }, @"com.google.Foo" : @"PolicyValueIsNotDictionary", }; - base::scoped_nsobject<CRUManagedPreferencePolicyManager> policyManager( - [[CRUManagedPreferencePolicyManager alloc] - initWithDictionary:policyDict]); + CRUManagedPreferencePolicyManager* policyManager = + [[CRUManagedPreferencePolicyManager alloc] initWithDictionary:policyDict]; EXPECT_NSEQ([policyManager source], @"ManagedPreference"); EXPECT_EQ([policyManager managed], base::IsManagedOrEnterpriseDevice());
diff --git a/chrome/updater/setup_mac.mm b/chrome/updater/setup_mac.mm index d4c0482..1b4a1ef 100644 --- a/chrome/updater/setup_mac.mm +++ b/chrome/updater/setup_mac.mm
@@ -12,6 +12,10 @@ #include "chrome/updater/posix/setup.h" #include "chrome/updater/updater_scope.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { void InstallCandidate(UpdaterScope scope,
diff --git a/chrome/updater/test/integration_tests_mac.mm b/chrome/updater/test/integration_tests_mac.mm index 7674c18..2a19f66f 100644 --- a/chrome/updater/test/integration_tests_mac.mm +++ b/chrome/updater/test/integration_tests_mac.mm
@@ -41,8 +41,11 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "url/gurl.h" -namespace updater { -namespace test { +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace updater::test { namespace { base::FilePath GetExecutablePath() { @@ -54,7 +57,7 @@ absl::optional<base::FilePath> GetActiveFile(UpdaterScope /*scope*/, const std::string& id) { - // The active user is always managaged in the updater scope for the user. + // The active user is always managed in the updater scope for the user. const absl::optional<base::FilePath> path = GetLibraryFolderPath(UpdaterScope::kUser); if (!path) @@ -353,5 +356,4 @@ // TODO(crbug.com/1286574). } -} // namespace test -} // namespace updater +} // namespace updater::test
diff --git a/chrome/updater/tools/BUILD.gn b/chrome/updater/tools/BUILD.gn index 2d9bd9f8..f626aa2 100644 --- a/chrome/updater/tools/BUILD.gn +++ b/chrome/updater/tools/BUILD.gn
@@ -53,6 +53,7 @@ "//chrome/updater:ks_ticket", ] + configs += [ "//build/config/compiler:enable_arc" ] frameworks = [ "Foundation.framework" ] } }
diff --git a/chrome/updater/tools/keystone_ticketstore_tool.mm b/chrome/updater/tools/keystone_ticketstore_tool.mm index 248a272..54a4e45 100644 --- a/chrome/updater/tools/keystone_ticketstore_tool.mm +++ b/chrome/updater/tools/keystone_ticketstore_tool.mm
@@ -12,6 +12,10 @@ #include "base/strings/sys_string_conversions.h" #import "chrome/updater/mac/setup/ks_tickets.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + @interface KSTicket (TestingTool) @end @@ -32,35 +36,35 @@ cohortName:(NSString*)cohortName creationDate:(NSDate*)creationData { if ((self = [super init])) { - productID_ = [appId retain]; - version_ = [version retain]; + productID_ = appId; + version_ = version; if (ecp.length) { existenceChecker_ = [[KSPathExistenceChecker alloc] initWithFilePath:base::mac::NSStringToFilePath(ecp)]; } - tag_ = [tag retain]; + tag_ = tag; if (tagPath.length) { - tagPath_ = [tagPath retain]; + tagPath_ = tagPath; } if (tagKey.length) { - tagKey_ = [tagKey retain]; + tagKey_ = tagKey; } - brandCode_ = [brandCode retain]; + brandCode_ = brandCode; if (brandPath.length) { - brandPath_ = [brandPath retain]; + brandPath_ = brandPath; } if (brandKey.length) { - brandKey_ = [brandKey retain]; + brandKey_ = brandKey; } - serverURL_ = [[NSURL - URLWithString:@"https://tools.google.com/service/update2"] retain]; - serverType_ = [@"Omaha" retain]; - versionPath_ = [versionPath retain]; - versionKey_ = [versionKey retain]; - cohort_ = [cohort retain]; - cohortHint_ = [cohortHint retain]; - cohortName_ = [cohortName retain]; - creationDate_ = [creationData retain]; + serverURL_ = + [NSURL URLWithString:@"https://tools.google.com/service/update"]; + serverType_ = @"Omaha"; + versionPath_ = versionPath; + versionKey_ = versionKey; + cohort_ = cohort; + cohortHint_ = cohortHint; + cohortName_ = cohortName; + creationDate_ = creationData; ticketVersion_ = 1; } return self;
diff --git a/chrome/updater/update_usage_stats_task_mac.mm b/chrome/updater/update_usage_stats_task_mac.mm index 4520f50..0f943b2e 100644 --- a/chrome/updater/update_usage_stats_task_mac.mm +++ b/chrome/updater/update_usage_stats_task_mac.mm
@@ -19,6 +19,10 @@ #include "third_party/crashpad/crashpad/client/crash_report_database.h" #include "third_party/crashpad/crashpad/client/settings.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace {
diff --git a/chrome/updater/util/mac_util.h b/chrome/updater/util/mac_util.h index 4ba0868..511bfc3 100644 --- a/chrome/updater/util/mac_util.h +++ b/chrome/updater/util/mac_util.h
@@ -5,9 +5,6 @@ #ifndef CHROME_UPDATER_UTIL_MAC_UTIL_H_ #define CHROME_UPDATER_UTIL_MAC_UTIL_H_ -#include <CoreFoundation/CoreFoundation.h> - -#include "base/mac/scoped_cftyperef.h" #include "chrome/updater/updater_scope.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -15,6 +12,10 @@ class FilePath; } // namespace base +#if __OBJC__ +@class NSDictionary; +#endif // __OBJC__ + namespace updater { // For user installations returns: the "~/Library" for the logged in user. @@ -45,12 +46,14 @@ // Recursively remove quarantine attributes on the path. bool RemoveQuarantineAttributes(const base::FilePath& path); +#if __OBJC__ + // Ensure that the LaunchAgents/LaunchDaemons directory contains the wake item // plist, with the specified contents. If not, the plist will be overwritten and // the item reloaded. May block. -bool EnsureWakeLaunchItemPresence( - UpdaterScope scope, - base::ScopedCFTypeRef<CFDictionaryRef> contents); +bool EnsureWakeLaunchItemPresence(UpdaterScope scope, NSDictionary* contents); + +#endif // __OBJC__ } // namespace updater
diff --git a/chrome/updater/util/mac_util.mm b/chrome/updater/util/mac_util.mm index fb02a99..4b8cebf 100644 --- a/chrome/updater/util/mac_util.mm +++ b/chrome/updater/util/mac_util.mm
@@ -15,7 +15,6 @@ #include "base/logging.h" #include "base/mac/foundation_util.h" #include "base/mac/mac_util.h" -#include "base/mac/scoped_cftyperef.h" #include "base/process/launch.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" @@ -30,6 +29,10 @@ #include "chrome/updater/util/util.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace { @@ -282,9 +285,7 @@ } } -bool EnsureWakeLaunchItemPresence( - UpdaterScope scope, - base::ScopedCFTypeRef<CFDictionaryRef> contents) { +bool EnsureWakeLaunchItemPresence(UpdaterScope scope, NSDictionary* contents) { const absl::optional<base::FilePath> path = GetWakeTaskPlistPath(scope); if (!path) { VLOG(1) << "Failed to find wake plist path."; @@ -300,9 +301,8 @@ // If the file is unchanged, avoid a spammy notification by not touching it. if (previousPlistExists && - [base::mac::CFToNSCast(contents) - isEqualToDictionary:[NSDictionary - dictionaryWithContentsOfURL:url]]) { + [contents isEqualToDictionary:[NSDictionary + dictionaryWithContentsOfURL:url]]) { VLOG(2) << "Skipping unnecessary update to " << path; return true; } @@ -336,7 +336,7 @@ } // Overwrite the plist. - if (![base::mac::CFToNSCast(contents) writeToURL:url atomically:YES]) { + if (![contents writeToURL:url atomically:YES]) { VLOG(1) << "Failed to write " << url; return false; }
diff --git a/chrome/updater/util/util_mac_unittest.mm b/chrome/updater/util/util_mac_unittest.mm index 37018d8..821d3c1c 100644 --- a/chrome/updater/util/util_mac_unittest.mm +++ b/chrome/updater/util/util_mac_unittest.mm
@@ -9,6 +9,10 @@ #include "base/files/scoped_temp_dir.h" #include "testing/gtest/include/gtest/gtest.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace updater { namespace {
diff --git a/chromecast/media/cma/backend/proxy/audio_channel_broker_impl.h b/chromecast/media/cma/backend/proxy/audio_channel_broker_impl.h index d02a1e1..b24f81b9 100644 --- a/chromecast/media/cma/backend/proxy/audio_channel_broker_impl.h +++ b/chromecast/media/cma/backend/proxy/audio_channel_broker_impl.h
@@ -65,9 +65,6 @@ template <typename TParams, typename TResult> struct GrpcCall { // The response to a gRPC Call. - // - // TODO(rwkeane): It's possible that this gets deleted by the async method, - // and that the reactor will need to be created as a subclass. class Response : public grpc::ClientUnaryReactor { public: using Callback =
diff --git a/chromecast/media/cma/backend/proxy/proxy_call_translator_unittest.cc b/chromecast/media/cma/backend/proxy/proxy_call_translator_unittest.cc index 6cd8124..dd15a24 100644 --- a/chromecast/media/cma/backend/proxy/proxy_call_translator_unittest.cc +++ b/chromecast/media/cma/backend/proxy/proxy_call_translator_unittest.cc
@@ -166,7 +166,6 @@ target_buffer_info.buffer_id = buffer_id; target_buffer_info.timestamp_micros = timestamp; - // TODO(rwkeane): Validate the duration in the ResumeAsync call. EXPECT_CALL(*decoder_channel_, ResumeAsync(testing::_)) .WillOnce( testing::WithArgs<0>(CompareTimestampInfos(buffer_id, timestamp)));
diff --git a/chromecast/media/cma/backend/proxy/push_buffer_queue.cc b/chromecast/media/cma/backend/proxy/push_buffer_queue.cc index bdd3762..04b2333 100644 --- a/chromecast/media/cma/backend/proxy/push_buffer_queue.cc +++ b/chromecast/media/cma/backend/proxy/push_buffer_queue.cc
@@ -111,9 +111,6 @@ // The former case is not expected to occur, but is handled to be safe. // The latter case is only expected if the buffer is written to when not // enough space is available to handle the new write. - // - // TODO(rwkeane): Eliminate handling of the former case after validating this - // doesn't occur in practice. if (!succeeded) { consecuitive_read_failures_++; if (+consecuitive_read_failures_ > kMaximumFailedReadAttempts) {
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd index 3ee7e7e..d286117 100644 --- a/chromeos/chromeos_strings.grd +++ b/chromeos/chromeos_strings.grd
@@ -2830,6 +2830,51 @@ <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT5" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 5"> backlit color </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT6" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 6"> + keyboard underglow + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT7" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 7"> + keyboard light + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT8" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 8"> + keyboard multicolor + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT9" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 9"> + keyboard hue + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT10" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 10"> + keyboard customize + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT11" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 11"> + keyboard brighten + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT12" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 12"> + keyboard brighter + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT13" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 13"> + keyboard brightness + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT14" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 14"> + keyboard dim + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT15" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 15"> + keyboard dimming + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT16" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 16"> + keyboard darken + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT17" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 17"> + keyboard darker + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT18" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 18"> + key color + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT19" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 19"> + keyboard zone + </message> + <message name="IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT20" desc="Text for search result item which, when clicked, navigates the user to personalization app keyboard backlight setting. Alternate phrase 20"> + rgb controls + </message> <!-- Traffic Counters UI --> <message name="IDS_TRAFFIC_COUNTERS_UNKNOWN" desc="Traffic counters related to an unknown source">
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT10.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT10.png.sha1 new file mode 100644 index 0000000..9bdcf2f --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT10.png.sha1
@@ -0,0 +1 @@ +a38074e82119222a847b5361088225970eee26d7 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT11.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT11.png.sha1 new file mode 100644 index 0000000..50c7295 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT11.png.sha1
@@ -0,0 +1 @@ +1499117f53e0d95781800e93cba33ef4d2553a71 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT12.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT12.png.sha1 new file mode 100644 index 0000000..c363065 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT12.png.sha1
@@ -0,0 +1 @@ +7b251a0fe571d7a55411792192270a88517738f0 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT13.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT13.png.sha1 new file mode 100644 index 0000000..060f12c --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT13.png.sha1
@@ -0,0 +1 @@ +f5fa5615a6f6d5745ae61aa6b3c5fa8d1a524f96 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT14.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT14.png.sha1 new file mode 100644 index 0000000..31bae51a --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT14.png.sha1
@@ -0,0 +1 @@ +86792e59aba95f8dee03b996ff245923b83898ee \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT15.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT15.png.sha1 new file mode 100644 index 0000000..29dbdb7b --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT15.png.sha1
@@ -0,0 +1 @@ +0b9bf8ff10b426e86ce989541a2746203dea2ddd \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT16.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT16.png.sha1 new file mode 100644 index 0000000..5daf691 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT16.png.sha1
@@ -0,0 +1 @@ +7702c8334f54455722fa87f693cbd7fbb8871047 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT17.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT17.png.sha1 new file mode 100644 index 0000000..49d204f --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT17.png.sha1
@@ -0,0 +1 @@ +376ca9d654536f9575ece6afd5a9f0299f3b5bb8 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT18.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT18.png.sha1 new file mode 100644 index 0000000..770b874 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT18.png.sha1
@@ -0,0 +1 @@ +2eb68c6809db159ce0de60cd17b2e0d705547bff \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT19.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT19.png.sha1 new file mode 100644 index 0000000..8370946 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT19.png.sha1
@@ -0,0 +1 @@ +41722984a6008df26b600af7b9e0844ea234d73d \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT20.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT20.png.sha1 new file mode 100644 index 0000000..567d97a --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT20.png.sha1
@@ -0,0 +1 @@ +ab348d76c1535f34831986cb70828e7d8a1ce62e \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT6.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT6.png.sha1 new file mode 100644 index 0000000..c70e99e --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT6.png.sha1
@@ -0,0 +1 @@ +d07ad2ba6bd150deb284d186ad287401ab10e519 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT7.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT7.png.sha1 new file mode 100644 index 0000000..35564b1b --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT7.png.sha1
@@ -0,0 +1 @@ +5fdcc3f66803bd14db061305b07b51f89597f150 \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT8.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT8.png.sha1 new file mode 100644 index 0000000..45c0891 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT8.png.sha1
@@ -0,0 +1 @@ +5ed8f812e8628ff57a9e3b1de6c7b084d5aa68da \ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT9.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT9.png.sha1 new file mode 100644 index 0000000..21c14c2 --- /dev/null +++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_SEARCH_RESULT_KEYBOARD_BACKLIGHT_ALT9.png.sha1
@@ -0,0 +1 @@ +9a13f9e764f477021d1d5cff8da026b22fc08ca2 \ No newline at end of file
diff --git a/chromeos/profiles/arm-exp.afdo.newest.txt b/chromeos/profiles/arm-exp.afdo.newest.txt index e9c8498..e138b8f 100644 --- a/chromeos/profiles/arm-exp.afdo.newest.txt +++ b/chromeos/profiles/arm-exp.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-none-115-5715.0-1683546756-benchmark-115.0.5759.0-r1-redacted.afdo.xz +chromeos-chrome-arm-none-115-5715.0-1683546756-benchmark-115.0.5761.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/arm.afdo.newest.txt b/chromeos/profiles/arm.afdo.newest.txt index e9c8498..e138b8f 100644 --- a/chromeos/profiles/arm.afdo.newest.txt +++ b/chromeos/profiles/arm.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-arm-none-115-5715.0-1683546756-benchmark-115.0.5759.0-r1-redacted.afdo.xz +chromeos-chrome-arm-none-115-5715.0-1683546756-benchmark-115.0.5761.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/atom.afdo.newest.txt b/chromeos/profiles/atom.afdo.newest.txt index 4b4f1ce..3a7b334 100644 --- a/chromeos/profiles/atom.afdo.newest.txt +++ b/chromeos/profiles/atom.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-atom-115-5735.12-1683543901-benchmark-115.0.5759.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-atom-115-5735.12-1683543901-benchmark-115.0.5761.0-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/bigcore.afdo.newest.txt b/chromeos/profiles/bigcore.afdo.newest.txt index 9199876..4233befd 100644 --- a/chromeos/profiles/bigcore.afdo.newest.txt +++ b/chromeos/profiles/bigcore.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-bigcore-115-5735.12-1683542912-benchmark-115.0.5759.0-r1-redacted.afdo.xz +chromeos-chrome-amd64-bigcore-115-5735.12-1683542912-benchmark-115.0.5761.0-r1-redacted.afdo.xz
diff --git a/components/autofill/core/browser/data_model/credit_card.cc b/components/autofill/core/browser/data_model/credit_card.cc index f3ed46e..c5f755e 100644 --- a/components/autofill/core/browser/data_model/credit_card.cc +++ b/components/autofill/core/browser/data_model/credit_card.cc
@@ -892,6 +892,11 @@ return StripSeparators(number_) == StripSeparators(other.number_); } +bool CreditCard::HasSameExpirationDateAs(const CreditCard& other) const { + return expiration_month() == other.expiration_month() && + expiration_year() == other.expiration_year(); +} + bool CreditCard::operator==(const CreditCard& credit_card) const { return guid() == credit_card.guid() && origin() == credit_card.origin() && record_type() == credit_card.record_type() &&
diff --git a/components/autofill/core/browser/data_model/credit_card.h b/components/autofill/core/browser/data_model/credit_card.h index a486ede..433be566 100644 --- a/components/autofill/core/browser/data_model/credit_card.h +++ b/components/autofill/core/browser/data_model/credit_card.h
@@ -242,6 +242,9 @@ // number as `this`. [[nodiscard]] bool HasSameNumberAs(const CreditCard& other) const; + // Returns true if expiration date for `this` card is the same as `other`. + [[nodiscard]] bool HasSameExpirationDateAs(const CreditCard& other) const; + // Equality operators compare GUIDs, origins, and the contents. // Usage metadata (use count, use date, modification date) are NOT compared. bool operator==(const CreditCard& credit_card) const;
diff --git a/components/autofill/core/browser/data_model/credit_card_unittest.cc b/components/autofill/core/browser/data_model/credit_card_unittest.cc index 5017eb1..5cd1eaed 100644 --- a/components/autofill/core/browser/data_model/credit_card_unittest.cc +++ b/components/autofill/core/browser/data_model/credit_card_unittest.cc
@@ -605,6 +605,35 @@ EXPECT_TRUE(masked_server_card.HasSameNumberAs(full_server_card)); } +// Test that `HasSameExpirationDateAs` returns true only if two cards have the +// same expiration year and month. +TEST(CreditCardTest, HasSameExpirationDateAs) { + CreditCard card_1; + test::SetCreditCardInfo(&card_1, "John Dillinger", "4111 1111 1111 1111", + "09", "2017", "1"); + + CreditCard card_2; + // Set the same expiration date as `card_1`. + test::SetCreditCardInfo(&card_2, "John Dillinger", "4111 1111 1111 1111", + "09", "2017", "1"); + EXPECT_TRUE(card_1.HasSameExpirationDateAs(card_2)); + + // Set the same month and different year as `card_1`. + test::SetCreditCardInfo(&card_2, "John Dillinger", "4111 1111 1111 1111", + "09", "2018", "1"); + EXPECT_FALSE(card_1.HasSameExpirationDateAs(card_2)); + + // Set the same year and different month as `card_1`. + test::SetCreditCardInfo(&card_2, "John Dillinger", "4111 1111 1111 1111", + "01", "2017", "1"); + EXPECT_FALSE(card_1.HasSameExpirationDateAs(card_2)); + + // Set the different expiration date as `card_1`. + test::SetCreditCardInfo(&card_2, "John Dillinger", "4111 1111 1111 1111", + "01", "2018", "1"); + EXPECT_FALSE(card_1.HasSameExpirationDateAs(card_2)); +} + struct SetExpirationYearFromStringTestCase { std::string expiration_year; int expected_year;
diff --git a/components/autofill/core/browser/form_parsing/address_field.cc b/components/autofill/core/browser/form_parsing/address_field.cc index 1415214..deaaaff8e 100644 --- a/components/autofill/core/browser/form_parsing/address_field.cc +++ b/components/autofill/core/browser/form_parsing/address_field.cc
@@ -82,6 +82,9 @@ constexpr MatchParams kStateMatchType = kDefaultMatchParamsWith<MatchFieldType::kSelect, MatchFieldType::kSearch>; +constexpr MatchParams kLandmarkMatchType = + kDefaultMatchParamsWith<MatchFieldType::kTextArea, MatchFieldType::kSearch>; + } // namespace std::unique_ptr<FormField> AddressField::Parse( @@ -133,8 +136,8 @@ continue; } else if (address_field->ParseAddress(scanner, page_language, pattern_source) || - address_field->ParseDependentLocalityCityStateCountryZipCode( - scanner, page_language, pattern_source) || + address_field->ParseAddressField(scanner, page_language, + pattern_source) || address_field->ParseCompany(scanner, page_language, pattern_source)) { has_trailing_non_labeled_fields = false; @@ -177,7 +180,7 @@ address_field->state_ || address_field->zip_ || address_field->zip4_ || address_field->street_name_ || address_field->house_number_ || address_field->country_ || address_field->apartment_number_ || - address_field->dependent_locality_) { + address_field->dependent_locality_ || address_field->landmark_) { // Don't slurp non-labeled fields at the end into the address. if (has_trailing_non_labeled_fields) scanner->RewindTo(begin_trailing_non_labeled_fields); @@ -226,6 +229,8 @@ kBaseAddressParserScore, field_candidates); AddClassification(apartment_number_, ADDRESS_HOME_APT_NUM, kBaseAddressParserScore, field_candidates); + AddClassification(landmark_, ADDRESS_HOME_LANDMARK, kBaseAddressParserScore, + field_candidates); } bool AddressField::ParseCompany(AutofillScanner* scanner, @@ -521,6 +526,23 @@ &state_, {log_manager_, "kStateRe"}); } +bool AddressField::ParseLandmark(AutofillScanner* scanner, + const LanguageCode& page_language, + PatternSource pattern_source) { + const bool is_enabled_landmark_parsing = base::FeatureList::IsEnabled( + features::kAutofillEnableSupportForExtraSettingsVisibleFields); + // TODO(crbug.com/1441904) Remove feature check when launched. + if (landmark_ || !is_enabled_landmark_parsing) { + return false; + } + + base::span<const MatchPatternRef> landmark_patterns = + GetMatchPatterns("LANDMARK", page_language, pattern_source); + return ParseFieldSpecifics(scanner, kLandmarkRe, kLandmarkMatchType, + landmark_patterns, &landmark_, + {log_manager_, "kLandmarkRe"}); +} + AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelSeparately( AutofillScanner* scanner, const std::u16string& pattern, @@ -558,17 +580,16 @@ return RESULT_MATCH_NONE; } -bool AddressField::ParseDependentLocalityCityStateCountryZipCode( - AutofillScanner* scanner, - const LanguageCode& page_language, - PatternSource pattern_source) { +bool AddressField::ParseAddressField(AutofillScanner* scanner, + const LanguageCode& page_language, + PatternSource pattern_source) { // The |scanner| is not pointing at a field. if (scanner->IsEnd()) return false; int num_of_missing_types = 0; for (const auto* field : - {dependent_locality_, city_, state_, country_, zip_}) { + {dependent_locality_, city_, state_, country_, zip_, landmark_}) { if (!field) ++num_of_missing_types; } @@ -589,6 +610,9 @@ return ParseCountry(scanner, page_language, pattern_source); if (!zip_) return ParseZipCode(scanner, page_language, pattern_source); + if (!landmark_) { + return ParseLandmark(scanner, page_language, pattern_source); + } } // Check for matches to both the name and the label. @@ -609,6 +633,11 @@ ParseNameAndLabelForCountry(scanner, page_language, pattern_source); if (country_result == RESULT_MATCH_NAME_LABEL) return true; + ParseNameLabelResult landmark_result = + ParseNameAndLabelForLandmark(scanner, page_language, pattern_source); + if (landmark_result == RESULT_MATCH_NAME_LABEL) { + return true; + } ParseNameLabelResult zip_result = ParseNameAndLabelForZipCode(scanner, page_language, pattern_source); if (zip_result == RESULT_MATCH_NAME_LABEL) @@ -631,6 +660,9 @@ return SetFieldAndAdvanceCursor(scanner, &state_); if (country_result != RESULT_MATCH_NONE) return SetFieldAndAdvanceCursor(scanner, &country_); + if (landmark_result != RESULT_MATCH_NONE) { + return SetFieldAndAdvanceCursor(scanner, &landmark_); + } if (zip_result != RESULT_MATCH_NONE) return ParseZipCode(scanner, page_language, pattern_source); } @@ -661,6 +693,9 @@ return SetFieldAndAdvanceCursor(scanner, &state_); if (country_result == result) return SetFieldAndAdvanceCursor(scanner, &country_); + if (landmark_result == result) { + return SetFieldAndAdvanceCursor(scanner, &landmark_); + } if (zip_result == result) return ParseZipCode(scanner, page_language, pattern_source); } @@ -789,4 +824,22 @@ {log_manager_, "kCountryLocationRe"}); } +AddressField::ParseNameLabelResult AddressField::ParseNameAndLabelForLandmark( + AutofillScanner* scanner, + const LanguageCode& page_language, + PatternSource pattern_source) { + const bool is_enabled_landmark_parsing = base::FeatureList::IsEnabled( + features::kAutofillEnableSupportForExtraSettingsVisibleFields); + // TODO(crbug.com/1441904) Remove feature check when launched. + if (landmark_ || !is_enabled_landmark_parsing) { + return RESULT_MATCH_NONE; + } + + base::span<const MatchPatternRef> landmark_patterns = + GetMatchPatterns("LANDMARK", page_language, pattern_source); + return ParseNameAndLabelSeparately(scanner, kLandmarkRe, kLandmarkMatchType, + landmark_patterns, &landmark_, + {log_manager_, "kLandmarkRe"}); +} + } // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/address_field.h b/components/autofill/core/browser/form_parsing/address_field.h index af3e2d9..6a9f2fd9 100644 --- a/components/autofill/core/browser/form_parsing/address_field.h +++ b/components/autofill/core/browser/form_parsing/address_field.h
@@ -83,13 +83,16 @@ const LanguageCode& page_language, PatternSource pattern_source); + bool ParseLandmark(AutofillScanner* scanner, + const LanguageCode& page_language, + PatternSource pattern_source); + // Parses the current field pointed to by |scanner|, if it exists, and tries // to determine if the field's type corresponds to one of the following: - // dependent locality, city, state, country, zip, or none of those. - bool ParseDependentLocalityCityStateCountryZipCode( - AutofillScanner* scanner, - const LanguageCode& page_language, - PatternSource pattern_source); + // dependent locality, city, state, country, zip, landmark or none of those. + bool ParseAddressField(AutofillScanner* scanner, + const LanguageCode& page_language, + PatternSource pattern_source); // Like ParseFieldSpecifics(), but applies |pattern| against the name and // label of the current field separately. If the return value is @@ -127,6 +130,11 @@ const LanguageCode& page_language, PatternSource pattern_source); + ParseNameLabelResult ParseNameAndLabelForLandmark( + AutofillScanner* scanner, + const LanguageCode& page_language, + PatternSource pattern_source); + ParseNameLabelResult ParseNameAndLabelForState( AutofillScanner* scanner, const LanguageCode& page_language, @@ -176,6 +184,9 @@ // This field is not a raw_ptr<> because it was filtered by the rewriter for: // #addr-of RAW_PTR_EXCLUSION AutofillField* country_ = nullptr; + // This field is not a raw_ptr<> because it was filtered by the rewriter for: + // #addr-of + RAW_PTR_EXCLUSION AutofillField* landmark_ = nullptr; }; } // namespace autofill
diff --git a/components/autofill/core/browser/form_parsing/address_field_unittest.cc b/components/autofill/core/browser/form_parsing/address_field_unittest.cc index 68912c55..f2be5ff 100644 --- a/components/autofill/core/browser/form_parsing/address_field_unittest.cc +++ b/components/autofill/core/browser/form_parsing/address_field_unittest.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "components/autofill/core/browser/form_parsing/address_field.h" +#include "components/autofill/core/browser/field_types.h" #include <memory> @@ -133,6 +134,17 @@ ClassifyAndVerify(); } +// Tests that the landmark is correctly classified. +TEST_P(AddressFieldTest, ParseLandmark) { + // TODO(crbug.com/1441904): Remove once launched. + base::test::ScopedFeatureList enabled; + enabled.InitAndEnableFeature( + features::kAutofillEnableSupportForExtraSettingsVisibleFields); + + AddTextFormFieldData("landmark", "Landmark", ADDRESS_HOME_LANDMARK); + ClassifyAndVerify(); +} + TEST_P(AddressFieldTest, ParseCity) { AddTextFormFieldData("city", "City", ADDRESS_HOME_CITY); ClassifyAndVerify(); @@ -178,8 +190,10 @@ ParseDependentLocalityCityStateCountryZipcodeTogether) { // TODO(crbug.com/1157405): Remove once launched. base::test::ScopedFeatureList enabled; - enabled.InitAndEnableFeature( - features::kAutofillEnableDependentLocalityParsing); + enabled.InitWithFeatures( + {features::kAutofillEnableDependentLocalityParsing, + features::kAutofillEnableSupportForExtraSettingsVisibleFields}, + {}); AddTextFormFieldData("neighborhood", "Neighborhood", ADDRESS_HOME_DEPENDENT_LOCALITY); @@ -187,6 +201,7 @@ AddTextFormFieldData("state", "State", ADDRESS_HOME_STATE); AddTextFormFieldData("country", "Country", ADDRESS_HOME_COUNTRY); AddTextFormFieldData("zip", "Zip", ADDRESS_HOME_ZIP); + AddTextFormFieldData("landmark", "Landmark", ADDRESS_HOME_LANDMARK); ClassifyAndVerify(); }
diff --git a/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json b/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json index d5c4b67..83a4a66 100644 --- a/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json +++ b/components/autofill/core/browser/form_parsing/resources/legacy_regex_patterns.json
@@ -1224,6 +1224,35 @@ } ] }, + "LANDMARK": { + "en": [ + { + "positive_pattern": "landmark", + "positive_score": 1.1, + "negative_pattern": null, + "match_field_attributes": ["LABEL", "NAME"], + "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"] + } + ], + "pt": [ + { + "positive_pattern": "(?:ponto|complemento).*referência", + "positive_score": 1.1, + "negative_pattern": null, + "match_field_attributes": ["LABEL", "NAME"], + "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"] + } + ], + "es": [ + { + "positive_pattern": "punto.*referencia", + "positive_score": 1.1, + "negative_pattern": null, + "match_field_attributes": ["LABEL", "NAME"], + "match_field_input_types": ["TEXT", "TEXT_AREA", "SEARCH"] + } + ] + }, "SEARCH_TERM": { "en": [ {
diff --git a/components/autofill/core/common/autofill_regex_constants.h b/components/autofill/core/common/autofill_regex_constants.h index a692ae54..863233c 100644 --- a/components/autofill/core/common/autofill_regex_constants.h +++ b/components/autofill/core/common/autofill_regex_constants.h
@@ -179,6 +179,10 @@ u"|((\\b|_|\\*)(eyalet|[şs]ehir|[İii̇]l(imiz)?|kent)(\\b|_|\\*))" // tr u"|^시[·・]?도" // ko-KR u"|provinci"; // id +inline constexpr char16_t kLandmarkRe[] = + u"landmark" + u"|(?:ponto|complemento).*referência" // pt-BR, pt-PT + u"|punto.*referencia"; // es ///////////////////////////////////////////////////////////////////////////// // search_field.cc
diff --git a/components/bookmarks/browser/bookmark_model.cc b/components/bookmarks/browser/bookmark_model.cc index bd06a39e..ebef4443 100644 --- a/components/bookmarks/browser/bookmark_model.cc +++ b/components/bookmarks/browser/bookmark_model.cc
@@ -304,8 +304,15 @@ // `MoveToOtherModelWithNewNodeIdsAndUuids` can only be triggered by a user // action at the moment. `AddNode` will take care of scheduling a save for // `dest_model`. - dest_model->AddNode(AsMutable(dest_parent), dest_parent->children().size(), - std::move(subtree_copy), /*added_by_user=*/true); + const BookmarkNode* added_node = dest_model->AddNode( + AsMutable(dest_parent), dest_parent->children().size(), + std::move(subtree_copy), /*added_by_user=*/true); + + // Current implementation requires that `BookmarkNodeAdded` is sent for all + // descendants (see `BookmarkNodeAdded` documentation). + // TODO(crbug.com/1440384): Revise the `BookmarkModelObserver` API. + dest_model->NotifyNodeAddedForAllDescendants(added_node, + /*added_by_user=*/true); // TODO(crbug.com/1441911): Make sure this flow can never cause data loss. if (store_) { @@ -1042,17 +1049,18 @@ // We might be restoring a folder node that have already contained a set of // child nodes. We need to notify all of them. - NotifyNodeAddedForAllDescendants(node_ptr); + NotifyNodeAddedForAllDescendants(node_ptr, /*added_by_user=*/false); } -void BookmarkModel::NotifyNodeAddedForAllDescendants(const BookmarkNode* node) { +void BookmarkModel::NotifyNodeAddedForAllDescendants(const BookmarkNode* node, + bool added_by_user) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); for (size_t i = 0; i < node->children().size(); ++i) { for (BookmarkModelObserver& observer : observers_) { - observer.BookmarkNodeAdded(this, node, i, false); + observer.BookmarkNodeAdded(this, node, i, added_by_user); } - NotifyNodeAddedForAllDescendants(node->children()[i].get()); + NotifyNodeAddedForAllDescendants(node->children()[i].get(), added_by_user); } }
diff --git a/components/bookmarks/browser/bookmark_model.h b/components/bookmarks/browser/bookmark_model.h index 679ac01..6cbd83ca 100644 --- a/components/bookmarks/browser/bookmark_model.h +++ b/components/bookmarks/browser/bookmark_model.h
@@ -390,7 +390,8 @@ std::unique_ptr<BookmarkNode> node) override; // Notifies the observers for adding every descendant of |node|. - void NotifyNodeAddedForAllDescendants(const BookmarkNode* node); + void NotifyNodeAddedForAllDescendants(const BookmarkNode* node, + bool added_by_user); // Removes the node from internal maps and recurses through all children. If // the node is a url, its url is added to removed_urls.
diff --git a/components/bookmarks/browser/bookmark_model_observer.h b/components/bookmarks/browser/bookmark_model_observer.h index 84303f85..7bb8104a 100644 --- a/components/bookmarks/browser/bookmark_model_observer.h +++ b/components/bookmarks/browser/bookmark_model_observer.h
@@ -37,9 +37,14 @@ const BookmarkNode* new_parent, size_t new_index) = 0; - // Invoked when a node has been added. `added_by_user` is true when a new - // bookmark was added by the user and false when a node is added by sync - // or duplicated. + // Invoked when a node has been added. If the added node has any descendants, + // BookmarkModel` will invoke `BookmarkNodeAdded` recursively for all these + // descendants. + // TODO(crbug.com/1440384): See if this should send only one notification, + // for consistency with `BookmarkNodeRemoved`. + // + // `added_by_user` is true when a new bookmark was added by the user and false + // when a node is added by sync or duplicated. virtual void BookmarkNodeAdded(BookmarkModel* model, const BookmarkNode* parent, size_t index,
diff --git a/components/bookmarks/browser/bookmark_model_unittest.cc b/components/bookmarks/browser/bookmark_model_unittest.cc index a8532e7..0d0966e 100644 --- a/components/bookmarks/browser/bookmark_model_unittest.cc +++ b/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -30,6 +30,7 @@ #include "base/uuid.h" #include "build/build_config.h" #include "components/bookmarks/browser/bookmark_model_observer.h" +#include "components/bookmarks/browser/bookmark_node.h" #include "components/bookmarks/browser/bookmark_undo_delegate.h" #include "components/bookmarks/browser/bookmark_utils.h" #include "components/bookmarks/browser/titled_url_match.h" @@ -52,7 +53,9 @@ using base::ASCIIToUTF16; using base::Time; +using testing::Invoke; using testing::Mock; +using testing::WithArg; namespace bookmarks { namespace { @@ -1997,9 +2000,21 @@ BookmarkNodeRemoved(local_or_syncable_model_.get(), root, 0, folder, removed_urls)) .InSequence(local_or_syncable_sequence); - // Not associated with the sequence and allowed to be invoked at any point. + + testing::Sequence account_sequence; EXPECT_CALL(account_observer_, - BookmarkNodeAdded(account_model_.get(), dest_folder, 0, true)); + BookmarkNodeAdded(account_model_.get(), dest_folder, 0, true)) + .InSequence(account_sequence); + const BookmarkNode* captured_foo_parent = nullptr; + EXPECT_CALL(account_observer_, + BookmarkNodeAdded(account_model_.get(), testing::_, 0, true)) + .InSequence(account_sequence) + .WillOnce(testing::SaveArg<1>(&captured_foo_parent)); + const BookmarkNode* captured_bar_parent = nullptr; + EXPECT_CALL(account_observer_, + BookmarkNodeAdded(account_model_.get(), testing::_, 1, true)) + .InSequence(account_sequence) + .WillOnce(testing::SaveArg<1>(&captured_bar_parent)); local_or_syncable_model_->MoveToOtherModelWithNewNodeIdsAndUuids( folder, account_model_.get(), dest_folder); @@ -2008,6 +2023,8 @@ const BookmarkNode* moved_folder = dest_folder->children()[0].get(); EXPECT_EQ(moved_folder->GetTitle(), u"folder"); ASSERT_EQ(moved_folder->children().size(), 2u); + EXPECT_EQ(captured_foo_parent, moved_folder); + EXPECT_EQ(captured_bar_parent, moved_folder); const BookmarkNode* moved_foo = moved_folder->children()[0].get(); EXPECT_EQ(moved_foo->GetTitle(), u"foo"); EXPECT_EQ(moved_foo->GetTitledUrlNodeUrl(), GURL("http://foo.com"));
diff --git a/components/browser_ui/styles/android/java/res/values/themes.xml b/components/browser_ui/styles/android/java/res/values/themes.xml index 738166d0..970bcaf 100644 --- a/components/browser_ui/styles/android/java/res/values/themes.xml +++ b/components/browser_ui/styles/android/java/res/values/themes.xml
@@ -53,17 +53,19 @@ <item name="windowActionBar">true</item> <item name="windowNoTitle">false</item> <item name="actionBarStyle">@style/ActionBarWithBackButton</item> - <item name="actionBarTheme">@style/DarkModeRippleColor</item> + <item name="actionBarTheme">@style/DarkModeActionBarTheme</item> </style> - <!-- Black action bar with white back button --> + <!-- Black action bar with back button --> <style name="ActionBarWithBackButton"> <item name="displayOptions">homeAsUp</item> - <item name="background">@android:color/black</item> - <item name="homeAsUpIndicator">@drawable/ic_arrow_back_white_24dp</item> + <item name="homeAsUpIndicator">@drawable/ic_arrow_back_24dp</item> </style> - <style name="DarkModeRippleColor"> + <style name="DarkModeActionBarTheme"> + <item name="background">@android:color/black</item> + <item name="colorControlNormal">@android:color/white</item> + <!-- Click event uses dark mode colors --> <item name="colorControlHighlight">@color/ripple_material_dark</item> </style> </resources>
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableListAdapter.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableListAdapter.java index fcb0d4b..c03350a 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableListAdapter.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableListAdapter.java
@@ -159,12 +159,12 @@ public DragReorderableListAdapter(Context context) { mContext = context; - Resources resource = context.getResources(); + Resources resources = context.getResources(); // Set the alpha to 90% when dragging which is 230/255 mDraggedBackgroundColor = ColorUtils.setAlphaComponent( ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_1), - resource.getInteger(R.integer.list_item_dragged_alpha)); - mDraggedElevation = resource.getDimension(R.dimen.list_item_dragged_elevation); + resources.getInteger(R.integer.list_item_dragged_alpha)); + mDraggedElevation = resources.getDimension(R.dimen.list_item_dragged_elevation); } @Override
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableRecyclerViewAdapter.java b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableRecyclerViewAdapter.java index 8d21c55..d3342f10a5 100644 --- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableRecyclerViewAdapter.java +++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/dragreorder/DragReorderableRecyclerViewAdapter.java
@@ -190,12 +190,12 @@ public DragReorderableRecyclerViewAdapter(Context context, ModelList modelList) { super(modelList); - Resources resource = context.getResources(); + Resources resources = context.getResources(); // Set the alpha to 90% when dragging which is 230/255 mDraggedBackgroundColor = ColorUtils.setAlphaComponent( ChromeColors.getSurfaceColor(context, R.dimen.default_elevation_4), - resource.getInteger(R.integer.list_item_dragged_alpha)); - mDraggedElevation = resource.getDimension(R.dimen.list_item_dragged_elevation); + resources.getInteger(R.integer.list_item_dragged_alpha)); + mDraggedElevation = resources.getDimension(R.dimen.list_item_dragged_elevation); } /**
diff --git a/components/cronet/android/api.txt b/components/cronet/android/api.txt index 35eed29..3d99b4a9d 100644 --- a/components/cronet/android/api.txt +++ b/components/cronet/android/api.txt
@@ -127,6 +127,7 @@ public abstract java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException; public abstract java.net.URLStreamHandlerFactory createURLStreamHandlerFactory(); public abstract org.chromium.net.UrlRequest$Builder newUrlRequestBuilder(java.lang.String, org.chromium.net.UrlRequest$Callback, java.util.concurrent.Executor); + public org.chromium.net.BidirectionalStream$Builder newBidirectionalStreamBuilder(java.lang.String, org.chromium.net.BidirectionalStream$Callback, java.util.concurrent.Executor); public int getActiveRequestCount(); public void addRequestFinishedListener(org.chromium.net.RequestFinishedInfo$Listener); public void removeRequestFinishedListener(org.chromium.net.RequestFinishedInfo$Listener); @@ -265,10 +266,11 @@ public static final int EFFECTIVE_CONNECTION_TYPE_4G; public static final long UNBIND_NETWORK_HANDLE; public org.chromium.net.ExperimentalCronetEngine(); - public abstract org.chromium.net.ExperimentalUrlRequest$Builder newUrlRequestBuilder(java.lang.String, org.chromium.net.UrlRequest$Callback, java.util.concurrent.Executor); public abstract org.chromium.net.ExperimentalBidirectionalStream$Builder newBidirectionalStreamBuilder(java.lang.String, org.chromium.net.BidirectionalStream$Callback, java.util.concurrent.Executor); + public abstract org.chromium.net.ExperimentalUrlRequest$Builder newUrlRequestBuilder(java.lang.String, org.chromium.net.UrlRequest$Callback, java.util.concurrent.Executor); public void bindToNetwork(long); public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException; + public org.chromium.net.BidirectionalStream$Builder newBidirectionalStreamBuilder(java.lang.String, org.chromium.net.BidirectionalStream$Callback, java.util.concurrent.Executor); public org.chromium.net.UrlRequest$Builder newUrlRequestBuilder(java.lang.String, org.chromium.net.UrlRequest$Callback, java.util.concurrent.Executor); } public abstract class org.chromium.net.ExperimentalUrlRequest$Builder extends org.chromium.net.UrlRequest$Builder { @@ -629,4 +631,4 @@ public static org.chromium.net.apihelpers.JsonCronetCallback forJsonBody(org.chromium.net.apihelpers.RedirectHandler, org.chromium.net.apihelpers.CronetRequestCompletionListener<org.json.JSONObject>); public static org.chromium.net.apihelpers.UrlRequestCallbacks$CallbackAndResponseFuturePair<org.json.JSONObject, org.chromium.net.apihelpers.JsonCronetCallback> forJsonBody(org.chromium.net.apihelpers.RedirectHandler); } -Stamp: 6e33940b3c477daafb6804ef0a1bf987 +Stamp: c29f4b3fe59fe6ba3660d72d322adc2d
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java index 603915ad..759fb9b 100644 --- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java +++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -719,6 +719,25 @@ String url, UrlRequest.Callback callback, Executor executor); /** + * Creates a builder for {@link BidirectionalStream} objects. All callbacks for generated {@code + * BidirectionalStream} objects will be invoked on {@code executor}. {@code executor} must not + * run tasks on the current thread, otherwise the networking operations may block and exceptions + * may be thrown at shutdown time. + * + * @param url URL for the generated streams. + * @param callback the {@link BidirectionalStream.Callback} object that gets invoked upon + * different events occurring. + * @param executor the {@link Executor} on which {@code callback} methods will be invoked. + * @return the created builder. + * + * {@hide} + */ + public BidirectionalStream.Builder newBidirectionalStreamBuilder( + String url, BidirectionalStream.Callback callback, Executor executor) { + throw new UnsupportedOperationException("Not implemented."); + } + + /** * Returns the number of in-flight requests. * <p> * A request is in-flight if its start() method has been called but it hasn't reached a final
diff --git a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java index e0bc6e0..5047c5b 100644 --- a/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java +++ b/components/cronet/android/api/src/org/chromium/net/ExperimentalCronetEngine.java
@@ -237,26 +237,13 @@ } @Override - public abstract ExperimentalUrlRequest.Builder newUrlRequestBuilder( - String url, UrlRequest.Callback callback, Executor executor); - - /** - * Creates a builder for {@link BidirectionalStream} objects. All callbacks for - * generated {@code BidirectionalStream} objects will be invoked on - * {@code executor}. {@code executor} must not run tasks on the - * current thread, otherwise the networking operations may block and exceptions - * may be thrown at shutdown time. - * - * @param url URL for the generated streams. - * @param callback the {@link BidirectionalStream.Callback} object that gets invoked upon - * different events occurring. - * @param executor the {@link Executor} on which {@code callback} methods will be invoked. - * - * @return the created builder. - */ public abstract ExperimentalBidirectionalStream.Builder newBidirectionalStreamBuilder( String url, BidirectionalStream.Callback callback, Executor executor); + @Override + public abstract ExperimentalUrlRequest.Builder newUrlRequestBuilder( + String url, UrlRequest.Callback callback, Executor executor); + /** * Binds the engine to the specified network handle. All requests created through this engine * will use the network associated to this handle. If this network disconnects all requests will
diff --git a/components/cronet/android/implementation_api_version.txt b/components/cronet/android/implementation_api_version.txt index a45fd52..7273c0fa 100644 --- a/components/cronet/android/implementation_api_version.txt +++ b/components/cronet/android/implementation_api_version.txt
@@ -1 +1 @@ -24 +25
diff --git a/components/cronet/android/interface_api_version.txt b/components/cronet/android/interface_api_version.txt index a45fd52..7273c0fa 100644 --- a/components/cronet/android/interface_api_version.txt +++ b/components/cronet/android/interface_api_version.txt
@@ -1 +1 @@ -24 +25
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc index bcfe32ec..f54531e 100644 --- a/components/exo/shell_surface_base.cc +++ b/components/exo/shell_surface_base.cc
@@ -459,6 +459,25 @@ system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_NONE); } +void ShellSurfaceBase::UpdateShape() { + if (!host_window() || !host_window()->layer()) { + return; + } + + if (!shape_rects_dp_.has_value()) { + host_window()->layer()->SetAlphaShape(nullptr); + return; + } + + auto scaled_rects = std::make_unique<std::vector<gfx::Rect>>(); + for (const gfx::Rect& rect_dp : shape_rects_dp_.value()) { + const float scale_factor = host_window()->layer()->device_scale_factor(); + scaled_rects->push_back(gfx::ScaleToEnclosedRect(rect_dp, scale_factor)); + } + + host_window()->layer()->SetAlphaShape(std::move(scaled_rects)); +} + void ShellSurfaceBase::SetApplicationId(const char* application_id) { // Store the value in |application_id_| in case the window does not exist yet. if (application_id) @@ -1692,7 +1711,8 @@ aura::Window* window = widget_->GetNativeWindow(); - if (!shadow_bounds_) { + // Window shadows should be disabled if a window shape has been set. + if (!shadow_bounds_ || shape_rects_dp_.has_value()) { wm::SetShadowElevation(window, wm::kShadowElevationNone); } else { // Use a small style shadow for popup surface. @@ -1893,6 +1913,7 @@ // Apply new window geometry. geometry_ = pending_geometry_; display_id_ = pending_display_id_; + shape_rects_dp_ = pending_shape_rects_dp_; // Apply new minimum/maximium size. bool size_constraint_changed = minimum_size_ != pending_minimum_size_ || @@ -1949,6 +1970,7 @@ } UpdateSurfaceBounds(); + UpdateShape(); // Don't show yet if the shell surface doesn't have content or is minimized // while waiting for content. @@ -2056,6 +2078,20 @@ initial_z_order_ = z_order; } +void ShellSurfaceBase::SetShape(absl::optional<cc::Region> shape) { + pending_shape_rects_dp_.reset(); + if (!shape) { + return; + } + + ShapeRects shape_rects_dp; + for (gfx::Rect rect : shape.value()) { + shape_rects_dp.push_back(std::move(rect)); + } + + pending_shape_rects_dp_ = std::move(shape_rects_dp); +} + // static bool ShellSurfaceBase::IsPopupWithGrab(aura::Window* window) { ShellSurfaceBase* shell_surface = exo::GetShellSurfaceBaseForWindow(window);
diff --git a/components/exo/shell_surface_base.h b/components/exo/shell_surface_base.h index 9efdb05..05d85634 100644 --- a/components/exo/shell_surface_base.h +++ b/components/exo/shell_surface_base.h
@@ -58,6 +58,8 @@ public wm::ActivationChangeObserver, public wm::TooltipObserver { public: + using ShapeRects = std::vector<gfx::Rect>; + // The |origin| is the initial position in screen coordinates. The position // specified as part of the geometry is relative to the shell surface. ShellSurfaceBase(Surface* surface, @@ -225,6 +227,10 @@ // initialized, it saves `z_order` for when it is initialized. void SetZOrder(ui::ZOrderLevel z_order); + // Sets the shape of the toplevel window, applied on commit. If shape is null + // this will unset the window shape. + void SetShape(absl::optional<cc::Region> shape); + // SurfaceDelegate: void OnSurfaceCommit() override; bool IsInputEnabled(Surface* surface) const override; @@ -385,6 +391,9 @@ // Applies |system_modal_| to |widget_|. void UpdateSystemModal(); + // Applies `shape_rects_dp_` to the host window's layer. + void UpdateShape(); + // Returns the "visible bounds" for the surface from the user's perspective. gfx::Rect GetVisibleBounds() const; @@ -434,6 +443,8 @@ gfx::Rect geometry_; gfx::Rect pending_geometry_; absl::optional<gfx::Rect> initial_bounds_; + absl::optional<ShapeRects> shape_rects_dp_; + absl::optional<ShapeRects> pending_shape_rects_dp_; int64_t display_id_ = display::kInvalidDisplayId; int64_t pending_display_id_ = display::kInvalidDisplayId;
diff --git a/components/exo/shell_surface_unittest.cc b/components/exo/shell_surface_unittest.cc index e1ca2dc..ff3fe0e 100644 --- a/components/exo/shell_surface_unittest.cc +++ b/components/exo/shell_surface_unittest.cc
@@ -132,6 +132,14 @@ window; } +cc::Region CreateRegion(ShellSurface::ShapeRects shape_rects) { + cc::Region shape_region; + for (const gfx::Rect& rect : shape_rects) { + shape_region.Union(rect); + } + return shape_region; +} + } // namespace TEST_F(ShellSurfaceTest, AcknowledgeConfigure) { @@ -3112,4 +3120,92 @@ EXPECT_NE(root_before, parent_widget->GetNativeWindow()->GetRootWindow()); } +// Assert SetShape() applies the shape to the host window's layer on commit. +TEST_F(ShellSurfaceTest, SetShapeAppliedAfterSurfaceCommit) { + std::unique_ptr<ShellSurface> shell_surface = + test::ShellSurfaceBuilder({64, 64}).BuildShellSurface(); + shell_surface->OnSetServerStartResize(); + shell_surface->OnSetFrame(SurfaceFrameType::NORMAL); + shell_surface->root_surface()->Commit(); + ASSERT_TRUE(shell_surface->GetWidget()); + + // Windows shadows should be applied. + EXPECT_NE(wm::kShadowElevationNone, + wm::GetShadowElevationConvertDefault( + shell_surface->GetWidget()->GetNativeWindow())); + + // Create a window shape from two unique rects. + const cc::Region shape_region = + CreateRegion({{10, 10, 32, 32}, {20, 20, 32, 32}}); + + // Apply the shape to the surface. This should not yet be reflected on the + // host window's layer. + shell_surface->SetShape(shape_region); + const ShellSurfaceBase::ShapeRects* layer_shape_rects = + shell_surface->host_window()->layer()->alpha_shape(); + EXPECT_FALSE(layer_shape_rects); + + // After surface commit the shape should have been applied to the layer. + shell_surface->root_surface()->Commit(); + layer_shape_rects = shell_surface->host_window()->layer()->alpha_shape(); + EXPECT_TRUE(layer_shape_rects); + EXPECT_EQ(shape_region, CreateRegion(*layer_shape_rects)); + + // Window shadows should be disabled when window shapes are set. + EXPECT_EQ(wm::kShadowElevationNone, + wm::GetShadowElevationConvertDefault( + shell_surface->GetWidget()->GetNativeWindow())); +} + +// Assert SetShape() updates the host window's layer with the most recent shape +// when the surface commits. +TEST_F(ShellSurfaceTest, SetShapeUpdatesAndUnsetsCorrectlyAfterCommit) { + std::unique_ptr<ShellSurface> shell_surface = + test::ShellSurfaceBuilder({64, 64}).BuildShellSurface(); + shell_surface->OnSetServerStartResize(); + shell_surface->OnSetFrame(SurfaceFrameType::NORMAL); + shell_surface->root_surface()->Commit(); + ASSERT_TRUE(shell_surface->GetWidget()); + + // Create several unique window shapes. + const cc::Region shape_region_1 = + CreateRegion({{5, 5, 32, 32}, {10, 10, 32, 32}}); + const cc::Region shape_region_2 = + CreateRegion({{15, 15, 32, 32}, {20, 20, 32, 32}}); + const cc::Region shape_region_3 = + CreateRegion({{25, 25, 32, 32}, {30, 40, 32, 32}}); + + // Apply two shapes to the surface without committing. Neither should be + // applied to the host window's layer. + shell_surface->SetShape(shape_region_1); + shell_surface->SetShape(shape_region_2); + const ShellSurfaceBase::ShapeRects* layer_shape_rects = + shell_surface->host_window()->layer()->alpha_shape(); + EXPECT_FALSE(layer_shape_rects); + + // After surface commit only the most recent shape should have been applied. + shell_surface->root_surface()->Commit(); + layer_shape_rects = shell_surface->host_window()->layer()->alpha_shape(); + EXPECT_TRUE(layer_shape_rects); + EXPECT_EQ(shape_region_2, CreateRegion(*layer_shape_rects)); + + // Apply another shape to the surface. The layer shape should not change. + shell_surface->SetShape(shape_region_3); + layer_shape_rects = shell_surface->host_window()->layer()->alpha_shape(); + EXPECT_TRUE(layer_shape_rects); + EXPECT_EQ(shape_region_2, CreateRegion(*layer_shape_rects)); + + // The new shape should have been applied after the surface is committed. + shell_surface->root_surface()->Commit(); + layer_shape_rects = shell_surface->host_window()->layer()->alpha_shape(); + EXPECT_TRUE(layer_shape_rects); + EXPECT_EQ(shape_region_3, CreateRegion(*layer_shape_rects)); + + // Setting a null shape should unset the host window's layer shape. + shell_surface->SetShape(absl::nullopt); + shell_surface->root_surface()->Commit(); + layer_shape_rects = shell_surface->host_window()->layer()->alpha_shape(); + EXPECT_FALSE(layer_shape_rects); +} + } // namespace exo
diff --git a/components/exo/wayland/protocol/aura-shell.xml b/components/exo/wayland/protocol/aura-shell.xml index fd76839..14e89da4f 100644 --- a/components/exo/wayland/protocol/aura-shell.xml +++ b/components/exo/wayland/protocol/aura-shell.xml
@@ -24,7 +24,7 @@ DEALINGS IN THE SOFTWARE. </copyright> - <interface name="zaura_shell" version="52"> + <interface name="zaura_shell" version="53"> <description summary="aura_shell"> The global interface exposing aura shell capabilities is used to instantiate an interface extension for a wl_surface object. @@ -764,7 +764,7 @@ </event> </interface> - <interface name="zaura_toplevel" version="52"> + <interface name="zaura_toplevel" version="53"> <description summary="aura shell interface to the toplevel shell"> An interface to the toplevel shell, which allows the client to access shell specific functionality. @@ -1139,6 +1139,18 @@ </description> <arg name="persistable" type="uint" enum="persistable" summary="is the argument persistable"/> </request> + + <!-- Version 53 additions --> + <request name="set_shape" since="53"> + <description summary="set the shape of the surface in DP"> + Sets the shape of the toplevel window in DP. Passing NULL will reset the + shape of the window. + + This should be used only in support of the existing (deprecated) Chrome + Apps SetShape API and not for any other purpose. + </description> + <arg name="region" type="object" interface="wl_region" allow-null="true"/> + </request> </interface> <interface name="zaura_popup" version="46">
diff --git a/components/exo/wayland/zaura_shell.cc b/components/exo/wayland/zaura_shell.cc index a3aeaf9..cac1de80 100644 --- a/components/exo/wayland/zaura_shell.cc +++ b/components/exo/wayland/zaura_shell.cc
@@ -885,6 +885,10 @@ shell_surface_->SetPersistable(persistable); } +void AuraToplevel::SetShape(absl::optional<cc::Region> shape) { + shell_surface_->SetShape(std::move(shape)); +} + void AuraToplevel::IntentToSnap(uint32_t snap_direction) { switch (snap_direction) { case ZAURA_SURFACE_SNAP_DIRECTION_NONE: @@ -1433,6 +1437,15 @@ persistable == ZAURA_TOPLEVEL_PERSISTABLE_PERSISTABLE); } +void aura_toplevel_set_shape(wl_client* client, + wl_resource* resource, + wl_resource* region_resource) { + GetUserDataAs<AuraToplevel>(resource)->SetShape( + region_resource ? absl::optional<cc::Region>( + *GetUserDataAs<SkRegion>(region_resource)) + : absl::nullopt); +} + const struct zaura_toplevel_interface aura_toplevel_implementation = { aura_toplevel_set_orientation_lock, aura_toplevel_surface_submission_in_pixel_coordinates, @@ -1457,6 +1470,7 @@ aura_toplevel_intent_to_snap, aura_toplevel_unset_snap, aura_toplevel_set_persistable, + aura_toplevel_set_shape, }; void aura_popup_surface_submission_in_pixel_coordinates(wl_client* client,
diff --git a/components/exo/wayland/zaura_shell.h b/components/exo/wayland/zaura_shell.h index bddb1a3..527645b 100644 --- a/components/exo/wayland/zaura_shell.h +++ b/components/exo/wayland/zaura_shell.h
@@ -32,7 +32,7 @@ namespace wayland { class SerialTracker; -constexpr uint32_t kZAuraShellVersion = 52; +constexpr uint32_t kZAuraShellVersion = 53; // Adds bindings to the Aura Shell. Normally this implies Ash on ChromeOS // builds. On non-ChromeOS builds the protocol provides access to Aura windowing @@ -165,6 +165,7 @@ void SetFullscreenMode(uint32_t mode); void SetScaleFactor(float scale_factor); void SetPersistable(bool persistable); + void SetShape(absl::optional<cc::Region> shape); raw_ptr<ShellSurface, ExperimentalAsh> shell_surface_; const raw_ptr<SerialTracker, ExperimentalAsh> serial_tracker_;
diff --git a/components/image_fetcher/BUILD.gn b/components/image_fetcher/BUILD.gn index 532be03..7e74fc2 100644 --- a/components/image_fetcher/BUILD.gn +++ b/components/image_fetcher/BUILD.gn
@@ -50,6 +50,17 @@ ] } +android_library("test_support_java") { + sources = [ "android/java/src/org/chromium/components/image_fetcher/test/TestImageFetcher.java" ] + + deps = [ + ":java", + "//base:base_java", + "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/gif_player:gif_player_java", + ] +} + robolectric_library("junit") { sources = [ "android/junit/src/org/chromium/components/image_fetcher/CachedImageFetcherTest.java",
diff --git a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java index e9ecb53..c25b28d 100644 --- a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java +++ b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/ImageFetcher.java
@@ -33,8 +33,6 @@ public static final String PRICE_DROP_NOTIFICATION = "PriceDropNotification"; public static final String POWER_BOOKMARKS_CLIENT_NAME = "PowerBookmarks"; public static final String QUERY_TILE_UMA_CLIENT_NAME = "QueryTiles"; - public static final String VIDEO_TUTORIALS_IPH_UMA_CLIENT_NAME = "VideoTutorialsIPH"; - public static final String VIDEO_TUTORIALS_LIST_UMA_CLIENT_NAME = "VideoTutorialsList"; public static final String WEB_ID_ACCOUNT_SELECTION_UMA_CLIENT_NAME = "WebIDAccountSelection"; public static final String WEB_NOTES_UMA_CLIENT_NAME = "WebNotes";
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestImageFetcher.java b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/test/TestImageFetcher.java similarity index 94% rename from chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestImageFetcher.java rename to components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/test/TestImageFetcher.java index d6b34a5..91924fa 100644 --- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestImageFetcher.java +++ b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/test/TestImageFetcher.java
@@ -2,7 +2,7 @@ // 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.video_tutorials.test; +package org.chromium.components.image_fetcher.test; import android.graphics.Bitmap;
diff --git a/components/keyed_service/core/simple_key_map.h b/components/keyed_service/core/simple_key_map.h index c910e995..c4b9733 100644 --- a/components/keyed_service/core/simple_key_map.h +++ b/components/keyed_service/core/simple_key_map.h
@@ -7,6 +7,7 @@ #include <map> +#include "base/memory/raw_ptr.h" #include "base/no_destructor.h" #include "components/keyed_service/core/keyed_service_export.h" @@ -53,7 +54,7 @@ SimpleKeyMap(); ~SimpleKeyMap(); - std::map<content::BrowserContext*, SimpleFactoryKey*> mapping_; + std::map<raw_ptr<content::BrowserContext>, SimpleFactoryKey*> mapping_; }; #endif // COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_KEY_MAP_H_
diff --git a/components/leveldb_proto/public/shared_proto_database_client_list.h b/components/leveldb_proto/public/shared_proto_database_client_list.h index eae1c4a..4a0182a 100644 --- a/components/leveldb_proto/public/shared_proto_database_client_list.h +++ b/components/leveldb_proto/public/shared_proto_database_client_list.h
@@ -90,6 +90,7 @@ ProtoDbType::FEED_CONTENT_DATABASE, ProtoDbType::FEED_JOURNAL_DATABASE, ProtoDbType::VIDEO_TUTORIALS_DATABASE, + ProtoDbType::VIDEO_TUTORIALS_V2_DATABASE, ProtoDbType::LAST, // Marks the end of list. };
diff --git a/components/metrics/generate_expired_histograms_array.gni b/components/metrics/generate_expired_histograms_array.gni index e807f03..c403dd8 100644 --- a/components/metrics/generate_expired_histograms_array.gni +++ b/components/metrics/generate_expired_histograms_array.gni
@@ -175,7 +175,6 @@ "//tools/metrics/histograms/metadata/update_engine/histograms.xml", "//tools/metrics/histograms/metadata/v8/histograms.xml", "//tools/metrics/histograms/metadata/variations/histograms.xml", - "//tools/metrics/histograms/metadata/video_tutorials/histograms.xml", "//tools/metrics/histograms/metadata/views/histograms.xml", "//tools/metrics/histograms/metadata/web_apk/histograms.xml", "//tools/metrics/histograms/metadata/web_audio/histograms.xml",
diff --git a/components/mirroring/service/remoting_sender_unittest.cc b/components/mirroring/service/remoting_sender_unittest.cc index b7d42fc..be50d31 100644 --- a/components/mirroring/service/remoting_sender_unittest.cc +++ b/components/mirroring/service/remoting_sender_unittest.cc
@@ -78,9 +78,8 @@ MOCK_METHOD1(SetTargetPlayoutDelay, void(base::TimeDelta)); MOCK_CONST_METHOD0(GetTargetPlayoutDelay, base::TimeDelta()); MOCK_CONST_METHOD0(NeedsKeyFrame, bool()); - MOCK_CONST_METHOD1( - ShouldDropNextFrame, - media::cast::CastStreamingFrameDropReason(base::TimeDelta)); + MOCK_METHOD1(ShouldDropNextFrame, + media::cast::CastStreamingFrameDropReason(base::TimeDelta)); MOCK_METHOD1(GetRecordedRtpTimestamp, media::cast::RtpTimeTicks(media::cast::FrameId)); MOCK_CONST_METHOD0(GetUnacknowledgedFrameCount, int());
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc index 068d4675..9a96098 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -289,10 +289,6 @@ OmniboxPopupSelection::NORMAL); } -OmniboxPopupView* OmniboxEditModel::get_popup_view() { - return popup_view_; -} - metrics::OmniboxEventProto::PageClassification OmniboxEditModel::GetPageClassification() const { return delegate()->GetLocationBarModel()->GetPageClassification(
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h index 16a98bf..c6cea53 100644 --- a/components/omnibox/browser/omnibox_edit_model.h +++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -85,7 +85,8 @@ } void set_popup_view(OmniboxPopupView* popup_view); - OmniboxPopupView* get_popup_view(); + OmniboxPopupView* get_popup_view() { return popup_view_; } + const OmniboxPopupView* get_popup_view() const { return popup_view_; } OmniboxEditModelDelegate* delegate() const { return edit_model_delegate_; }
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 c7c3513..e9d4df8 100644 --- a/components/password_manager/core/browser/form_parsing/form_parser.cc +++ b/components/password_manager/core/browser/form_parsing/form_parser.cc
@@ -220,15 +220,9 @@ // the construction of a PasswordForm. struct SignificantFields { raw_ptr<const FormFieldData> username = nullptr; - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #addr-of - RAW_PTR_EXCLUSION const FormFieldData* password = nullptr; - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #addr-of - RAW_PTR_EXCLUSION const FormFieldData* new_password = nullptr; - // This field is not a raw_ptr<> because it was filtered by the rewriter for: - // #addr-of - RAW_PTR_EXCLUSION const FormFieldData* confirmation_password = nullptr; + raw_ptr<const FormFieldData> password = nullptr; + raw_ptr<const FormFieldData> new_password = nullptr; + raw_ptr<const FormFieldData> confirmation_password = nullptr; // True if the information about fields could only be derived after relaxing // some constraints. The resulting PasswordForm should only be used for // fallback UI. @@ -264,6 +258,70 @@ new_password = nullptr; confirmation_password = nullptr; } + + // Detects different password fields from |passwords| and sets |password|, + // |new_password|, |confirmation_password| if found. + void LocateSpecificPasswords( + const std::vector<const FormFieldData*>& passwords) { + DCHECK(!password); + DCHECK(!new_password); + DCHECK(!confirmation_password); + + switch (passwords.size()) { + case 1: + password = passwords[0]; + break; + case 2: + if (!passwords[0]->value.empty() && + passwords[0]->value == passwords[1]->value) { + // Two identical non-empty passwords: assume we are seeing a new + // password with a confirmation. This can be either a sign-up form or + // a password change form that does not ask for the old password. + new_password = passwords[0]; + confirmation_password = passwords[1]; + } else { + // Assume first is old password, second is new (no choice but to + // guess). If the passwords are both empty, it is impossible to tell + // if they are the old and the new one, or the new one and its + // confirmation. In that case Chrome errs on the side of filling and + // classifies them as old & new to allow filling of change password + // forms. + password = passwords[0]; + new_password = passwords[1]; + } + break; + default: + // If there are more than 3 passwords it is not very clear what this + // form it is. Consider only the first 3 passwords in such case as a + // best-effort solution. + if (!passwords[0]->value.empty() && + passwords[0]->value == passwords[1]->value && + passwords[0]->value == passwords[2]->value) { + // All passwords are the same. Assume that the first field is the + // current password. + password = passwords[0]; + } else if (passwords[1]->value == passwords[2]->value) { + // New password is the duplicated one, and comes second; or empty form + // with at least 3 password fields. + password = passwords[0]; + new_password = passwords[1]; + confirmation_password = passwords[2]; + } else if (passwords[0]->value == passwords[1]->value) { + // It is strange that the new password comes first, but trust more + // which fields are duplicated than the ordering of fields. Assume + // that any password fields after the new password contain sensitive + // information that isn't actually a password (security hint, SSN, + // etc.) + new_password = passwords[0]; + confirmation_password = passwords[1]; + } else { + // Three different passwords, or first and last match with middle + // different. No idea which is which. Let's save the first password. + // Password selection in a prompt will allow to correct the choice. + password = passwords[0]; + } + } + } }; // For debugging. @@ -691,72 +749,6 @@ return result; } -// Detects different password fields from |passwords|. -void LocateSpecificPasswords(const std::vector<const FormFieldData*>& passwords, - const FormFieldData** current_password, - const FormFieldData** new_password, - const FormFieldData** confirmation_password) { - DCHECK(current_password); - DCHECK(!*current_password); - DCHECK(new_password); - DCHECK(!*new_password); - DCHECK(confirmation_password); - DCHECK(!*confirmation_password); - - switch (passwords.size()) { - case 1: - *current_password = passwords[0]; - break; - case 2: - if (!passwords[0]->value.empty() && - passwords[0]->value == passwords[1]->value) { - // Two identical non-empty passwords: assume we are seeing a new - // password with a confirmation. This can be either a sign-up form or a - // password change form that does not ask for the old password. - *new_password = passwords[0]; - *confirmation_password = passwords[1]; - } else { - // Assume first is old password, second is new (no choice but to guess). - // If the passwords are both empty, it is impossible to tell if they - // are the old and the new one, or the new one and its confirmation. In - // that case Chrome errs on the side of filling and classifies them as - // old & new to allow filling of change password forms. - *current_password = passwords[0]; - *new_password = passwords[1]; - } - break; - default: - // If there are more than 3 passwords it is not very clear what this form - // it is. Consider only the first 3 passwords in such case as a - // best-effort solution. - if (!passwords[0]->value.empty() && - passwords[0]->value == passwords[1]->value && - passwords[0]->value == passwords[2]->value) { - // All passwords are the same. Assume that the first field is the - // current password. - *current_password = passwords[0]; - } else if (passwords[1]->value == passwords[2]->value) { - // New password is the duplicated one, and comes second; or empty form - // with at least 3 password fields. - *current_password = passwords[0]; - *new_password = passwords[1]; - *confirmation_password = passwords[2]; - } else if (passwords[0]->value == passwords[1]->value) { - // It is strange that the new password comes first, but trust more which - // fields are duplicated than the ordering of fields. Assume that - // any password fields after the new password contain sensitive - // information that isn't actually a password (security hint, SSN, etc.) - *new_password = passwords[0]; - *confirmation_password = passwords[1]; - } else { - // Three different passwords, or first and last match with middle - // different. No idea which is which. Let's save the first password. - // Password selection in a prompt will allow to correct the choice. - *current_password = passwords[0]; - } - } -} - // Tries to find username field among text fields from |processed_fields| // occurring before |first_relevant_password|. Returns nullptr if the username // is not found. If |mode| is SAVING, ignores all fields with empty values. @@ -858,9 +850,7 @@ &found_fields->is_fallback, found_fields->username); if (passwords.empty()) return; - LocateSpecificPasswords(passwords, &found_fields->password, - &found_fields->new_password, - &found_fields->confirmation_password); + found_fields->LocateSpecificPasswords(passwords); if (!found_fields->HasPasswords()) return; for (auto it = processed_fields.begin(); it != processed_fields.end();
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc index 39bf207b..5a3f8f34 100644 --- a/components/password_manager/core/browser/password_store.cc +++ b/components/password_manager/core/browser/password_store.cc
@@ -264,7 +264,7 @@ base::BindOnce(&GetLoginsOrEmptyListOnFailure) .Then(base::BindOnce(&PasswordStore::UnblocklistInternal, this, std::move(completion))), - FormSupportsPSL(form_digest), {form_digest}); + /*include_psl=*/false, {form_digest}); } void PasswordStore::GetLogins(const PasswordFormDigest& form, @@ -505,8 +505,7 @@ std::vector<PasswordForm> forms_to_remove; for (auto& form : forms) { - // Ignore PSL matches for blocked entries. - if (form->blocked_by_user && !form->is_public_suffix_match) { + if (form->blocked_by_user) { forms_to_remove.push_back(std::move(*form)); } }
diff --git a/components/password_manager/core/common/BUILD.gn b/components/password_manager/core/common/BUILD.gn index e560bfa59..4b0cbcd1 100644 --- a/components/password_manager/core/common/BUILD.gn +++ b/components/password_manager/core/common/BUILD.gn
@@ -42,7 +42,10 @@ sources += [ "password_manager_feature_variations_android.h" ] } - deps = [ "//base" ] + deps = [ + "//base", + "//build:blink_buildflags", + ] } if (is_ios) {
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc index 740eccb..a611b40 100644 --- a/components/password_manager/core/common/password_manager_features.cc +++ b/components/password_manager/core/common/password_manager_features.cc
@@ -5,6 +5,7 @@ #include "components/password_manager/core/common/password_manager_features.h" #include "base/feature_list.h" +#include "build/blink_buildflags.h" #include "build/build_config.h" namespace password_manager::features { @@ -176,15 +177,23 @@ "PasswordReuseDetectionEnabled", base::FEATURE_ENABLED_BY_DEFAULT); +// Enables different experiments that modify content and behavior of the +// existing generated password suggestion dropdown. +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // Desktop +BASE_FEATURE(kPasswordGenerationExperiment, + "PasswordGenerationExperiment", + base::FEATURE_DISABLED_BY_DEFAULT); +#endif + // Enables requesting and saving passwords grouping information from the // affiliation service. // TODO(crbug.com/1359392): Remove once launched on all platforms. BASE_FEATURE(kPasswordsGrouping, "PasswordsGrouping", -#if BUILDFLAG(IS_IOS) - base::FEATURE_ENABLED_BY_DEFAULT -#else +#if BUILDFLAG(USE_BLINK) base::FEATURE_DISABLED_BY_DEFAULT +#else + base::FEATURE_ENABLED_BY_DEFAULT #endif ); @@ -230,10 +239,6 @@ "PasswordGenerationBottomSheet", base::FEATURE_DISABLED_BY_DEFAULT); -BASE_FEATURE(kShowUPMErrorNotification, - "ShowUpmErrorNotification", - base::FEATURE_DISABLED_BY_DEFAULT); - // Enables the intent fetching for the credential manager in Google Mobile // Services. It does not enable launching the credential manager. BASE_FEATURE(kUnifiedCredentialManagerDryRun,
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h index c6d7bbc..fc65c01 100644 --- a/components/password_manager/core/common/password_manager_features.h +++ b/components/password_manager/core/common/password_manager_features.h
@@ -64,6 +64,9 @@ BASE_DECLARE_FEATURE(kPasswordManagerRedesign); #endif BASE_DECLARE_FEATURE(kPasswordReuseDetectionEnabled); +#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // Desktop +BASE_DECLARE_FEATURE(kPasswordGenerationExperiment); +#endif BASE_DECLARE_FEATURE(kPasswordsGrouping); BASE_DECLARE_FEATURE(kPasswordsImportM2); BASE_DECLARE_FEATURE(kPasswordStrengthIndicator); @@ -78,7 +81,6 @@ BASE_DECLARE_FEATURE(kPasskeyManagementUsingAccountSettingsAndroid); BASE_DECLARE_FEATURE(kPasswordEditDialogWithDetails); BASE_DECLARE_FEATURE(kPasswordGenerationBottomSheet); -BASE_DECLARE_FEATURE(kShowUPMErrorNotification); BASE_DECLARE_FEATURE(kUnifiedCredentialManagerDryRun); BASE_DECLARE_FEATURE(kUnifiedPasswordManagerAndroid); BASE_DECLARE_FEATURE(kUnifiedPasswordManagerLocalPasswordsMigrationWarning);
diff --git a/components/permissions/permission_request_manager.cc b/components/permissions/permission_request_manager.cc index 02ebba3..7db2994a 100644 --- a/components/permissions/permission_request_manager.cc +++ b/components/permissions/permission_request_manager.cc
@@ -17,6 +17,7 @@ #include "base/rand_util.h" #include "base/ranges/algorithm.h" #include "base/task/sequenced_task_runner.h" +#include "base/time/clock.h" #include "base/time/time.h" #include "components/back_forward_cache/back_forward_cache_disable.h" #include "components/permissions/features.h" @@ -24,6 +25,7 @@ #include "components/permissions/permission_decision_auto_blocker.h" #include "components/permissions/permission_prompt.h" #include "components/permissions/permission_request.h" +#include "components/permissions/permission_uma_util.h" #include "components/permissions/permission_util.h" #include "components/permissions/permissions_client.h" #include "components/permissions/request_type.h" @@ -558,6 +560,17 @@ PermissionAction::GRANTED); PermissionGrantedIncludingDuplicates(*requests_iter, /*is_one_time=*/false); + +#if !BUILDFLAG(IS_ANDROID) + absl::optional<ContentSettingsType> content_settings_type = + RequestTypeToContentSettingsType((*requests_iter)->request_type()); + if (content_settings_type.has_value()) { + PermissionUmaUtil::RecordPermissionRegrantForUnusedSites( + (*requests_iter)->requesting_origin(), content_settings_type.value(), + PermissionSourceUI::PROMPT, web_contents()->GetBrowserContext(), + base::Time::Now()); + } +#endif } NotifyRequestDecided(PermissionAction::GRANTED);
diff --git a/components/permissions/permission_uma_util.cc b/components/permissions/permission_uma_util.cc index d2c754e..affc69c 100644 --- a/components/permissions/permission_uma_util.cc +++ b/components/permissions/permission_uma_util.cc
@@ -4,17 +4,21 @@ #include "components/permissions/permission_uma_util.h" +#include <cstdint> #include <utility> #include "base/command_line.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/no_destructor.h" +#include "base/notreached.h" #include "base/strings/strcat.h" +#include "base/time/clock.h" #include "base/time/time.h" #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "components/content_settings/core/common/content_settings_types.h" +#include "components/permissions/constants.h" #include "components/permissions/permission_actions_history.h" #include "components/permissions/permission_decision_auto_blocker.h" #include "components/permissions/permission_request.h" @@ -23,6 +27,7 @@ #include "components/permissions/prediction_service/prediction_common.h" #include "components/permissions/prediction_service/prediction_request_features.h" #include "components/permissions/request_type.h" +#include "components/permissions/unused_site_permissions_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "services/metrics/public/cpp/metrics_utils.h" @@ -1578,4 +1583,42 @@ } } +void PermissionUmaUtil::RecordPermissionRegrantForUnusedSites( + const GURL& origin, + ContentSettingsType content_settings_type, + PermissionSourceUI source_ui, + content::BrowserContext* browser_context, + base::Time current_time) { + auto* hcsm = PermissionsClient::Get()->GetSettingsMap(browser_context); + absl::optional<uint32_t> days_since_revocation = + UnusedSitePermissionsService::GetDaysSinceRevocation( + origin, content_settings_type, current_time, hcsm); + if (!days_since_revocation.has_value()) { + return; + } + std::string source_ui_string; + // We are only interested in permission updates through the UI that go from + // Ask to Allow. This can only be done through the permission prompt and the + // site settings page. + switch (source_ui) { + case PermissionSourceUI::PROMPT: + source_ui_string = "Prompt"; + break; + case PermissionSourceUI::SITE_SETTINGS: + source_ui_string = "Settings"; + break; + default: + NOTREACHED(); + } + base::UmaHistogramExactLinear( + "Settings.SafetyCheck.UnusedSitePermissionsRegrantDays" + + source_ui_string + "." + + PermissionUtil::GetPermissionString(content_settings_type), + days_since_revocation.value(), 31); + base::UmaHistogramExactLinear( + "Settings.SafetyCheck.UnusedSitePermissionsRegrantDays" + + source_ui_string + ".All", + days_since_revocation.value(), 31); +} + } // namespace permissions
diff --git a/components/permissions/permission_uma_util.h b/components/permissions/permission_uma_util.h index c91340c..66fed70e 100644 --- a/components/permissions/permission_uma_util.h +++ b/components/permissions/permission_uma_util.h
@@ -608,6 +608,15 @@ static void RecordTopLevelPermissionsHeaderPolicyOnNavigation( content::RenderFrameHost* render_frame_host); + // Logs a metric that captures how long since revocation, due to a site being + // considered unused, the user regrants a revoked permission. + static void RecordPermissionRegrantForUnusedSites( + const GURL& origin, + ContentSettingsType request_type, + PermissionSourceUI source_ui, + content::BrowserContext* browser_context, + base::Time current_time); + // A scoped class that will check the current resolved content setting on // construction and report a revocation metric accordingly if the revocation // condition is met (from ALLOW to something else).
diff --git a/components/permissions/permission_uma_util_unittest.cc b/components/permissions/permission_uma_util_unittest.cc index ccf80c7..a089d0d 100644 --- a/components/permissions/permission_uma_util_unittest.cc +++ b/components/permissions/permission_uma_util_unittest.cc
@@ -7,12 +7,18 @@ #include "base/files/scoped_temp_dir.h" #include "base/strings/strcat.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/simple_test_clock.h" +#include "base/time/clock.h" +#include "base/time/time.h" #include "components/content_settings/core/browser/host_content_settings_map.h" #include "components/content_settings/core/common/content_settings_pattern.h" #include "components/content_settings/core/common/content_settings_types.h" +#include "components/content_settings/core/common/features.h" +#include "components/permissions/constants.h" #include "components/permissions/permission_request_manager.h" #include "components/permissions/permission_util.h" #include "components/permissions/test/test_permissions_client.h" +#include "components/permissions/unused_site_permissions_service.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_task_environment.h" @@ -423,6 +429,72 @@ 1); } +#if !BUILDFLAG(IS_ANDROID) +TEST_F(PermissionUmaUtilTest, RecordPermissionRegrantForUnusedSites) { + const GURL origin = GURL("https://example1.com:443"); + content::TestBrowserContext browser_context; + base::HistogramTester histograms; + ContentSettingsType content_type = ContentSettingsType::GEOLOCATION; + std::string permission_string = + PermissionUtil::GetPermissionString(content_type); + base::SimpleTestClock clock; + base::Time now(base::Time::Now()); + clock.SetNow(now); + HostContentSettingsMap* hcsm = + PermissionsClient::Get()->GetSettingsMap(&browser_context); + hcsm->SetClockForTesting(&clock); + + std::string prefix = "Settings.SafetyCheck.UnusedSitePermissionsRegrantDays"; + + // Record regrant before permission has been revoked. + PermissionUmaUtil::RecordPermissionRegrantForUnusedSites( + origin, content_type, PermissionSourceUI::PROMPT, &browser_context, now); + histograms.ExpectTotalCount(prefix + "Prompt." + permission_string, 0); + histograms.ExpectTotalCount(prefix + "Prompt.All", 0); + + // Create a revoked permission. + base::Value::Dict dict = base::Value::Dict(); + base::Value::List permission_type_list = base::Value::List(); + permission_type_list.Append(static_cast<int32_t>(content_type)); + dict.Set(permissions::kRevokedKey, + base::Value::List(std::move(permission_type_list))); + // Set expiration to five days before the clean-up threshold to mimic that the + // permission was revoked five days ago. + base::Time past(now - base::Days(5)); + const content_settings::ContentSettingConstraints constraint{ + .expiration = + past + content_settings::features:: + kSafetyCheckUnusedSitePermissionsRevocationCleanUpThreshold + .Get()}; + hcsm->SetWebsiteSettingDefaultScope( + origin, origin, ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, + base::Value(dict.Clone()), constraint); + + // Regrant another permission through the prompt. + PermissionUmaUtil::RecordPermissionRegrantForUnusedSites( + origin, ContentSettingsType::NOTIFICATIONS, PermissionSourceUI::PROMPT, + &browser_context, now); + histograms.ExpectTotalCount(prefix + "Prompt." + + PermissionUtil::GetPermissionString( + ContentSettingsType::NOTIFICATIONS), + 0); + histograms.ExpectTotalCount(prefix + "Prompt.All", 0); + + // Regrant the geolocation permission through the prompt. + PermissionUmaUtil::RecordPermissionRegrantForUnusedSites( + origin, content_type, PermissionSourceUI::PROMPT, &browser_context, now); + histograms.ExpectBucketCount(prefix + "Prompt." + permission_string, 5, 1); + histograms.ExpectBucketCount(prefix + "Prompt.All", 5, 1); + + // Regrant the geolocation permission through site settings. + PermissionUmaUtil::RecordPermissionRegrantForUnusedSites( + origin, content_type, PermissionSourceUI::SITE_SETTINGS, &browser_context, + now); + histograms.ExpectBucketCount(prefix + "Settings." + permission_string, 5, 1); + histograms.ExpectBucketCount(prefix + "Settings.All", 5, 1); +} +#endif + TEST_F(PermissionsDelegationUmaUtilTest, SameOriginFrame) { base::HistogramTester histograms; auto* main_frame = GetMainFrameAndNavigate(kTopLevelUrl);
diff --git a/components/permissions/unused_site_permissions_service.cc b/components/permissions/unused_site_permissions_service.cc index dfe2c87..3dd9574 100644 --- a/components/permissions/unused_site_permissions_service.cc +++ b/components/permissions/unused_site_permissions_service.cc
@@ -441,4 +441,43 @@ clock_ = clock; } +// static +absl::optional<uint32_t> UnusedSitePermissionsService::GetDaysSinceRevocation( + const GURL& origin, + ContentSettingsType content_settings_type, + base::Time current_time, + HostContentSettingsMap* hcsm) { + content_settings::SettingInfo info; + base::Value stored_value(hcsm->GetWebsiteSetting( + origin, origin, ContentSettingsType::REVOKED_UNUSED_SITE_PERMISSIONS, + &info)); + if (!stored_value.is_dict()) { + return absl::nullopt; + } + base::Value::List* permission_type_list = + stored_value.GetDict().FindList(permissions::kRevokedKey); + if (!permission_type_list) { + return absl::nullopt; + } + base::Time revoked_time = + info.metadata.expiration - + content_settings::features:: + kSafetyCheckUnusedSitePermissionsRevocationCleanUpThreshold.Get(); + ; + uint32_t days_since_revoked = (current_time - revoked_time).InDays(); + + for (auto& permission_type : *permission_type_list) { + auto type_int = permission_type.GetIfInt(); + if (!type_int.has_value()) { + continue; + } + if (content_settings_type == + static_cast<ContentSettingsType>(type_int.value())) { + return days_since_revoked; + } + } + + return absl::nullopt; +} + } // namespace permissions
diff --git a/components/permissions/unused_site_permissions_service.h b/components/permissions/unused_site_permissions_service.h index ec5a691..20175b0 100644 --- a/components/permissions/unused_site_permissions_service.h +++ b/components/permissions/unused_site_permissions_service.h
@@ -12,6 +12,7 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/time/clock.h" +#include "base/time/time.h" #include "base/timer/timer.h" #include "components/content_settings/core/common/content_settings.h" #include "components/content_settings/core/common/content_settings_pattern.h" @@ -106,6 +107,12 @@ constraint, const url::Origin origin); + static absl::optional<uint32_t> GetDaysSinceRevocation( + const GURL& origin, + ContentSettingsType content_settings_type, + base::Time current_time, + HostContentSettingsMap* hcsm); + // Test support: void SetClockForTesting(base::Clock* clock); std::vector<ContentSettingEntry> GetTrackedUnusedPermissionsForTesting();
diff --git a/components/permissions/unused_site_permissions_service_unittest.cc b/components/permissions/unused_site_permissions_service_unittest.cc index d89b16e..5503b6d 100644 --- a/components/permissions/unused_site_permissions_service_unittest.cc +++ b/components/permissions/unused_site_permissions_service_unittest.cc
@@ -10,6 +10,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/simple_test_clock.h" #include "base/time/clock.h" +#include "base/time/time.h" #include "base/values.h" #include "components/content_settings/core/browser/content_settings_utils.h" #include "components/content_settings/core/browser/host_content_settings_map.h" @@ -535,4 +536,52 @@ EXPECT_EQ(revoked_permissions_list.size(), 0U); } +TEST_F(UnusedSitePermissionsServiceTest, GetDaysSinceRevocation) { + base::test::ScopedFeatureList scoped_feature; + scoped_feature.InitAndEnableFeature( + content_settings::features::kSafetyCheckUnusedSitePermissions); + + const GURL url = GURL("https://example1.com:443"); + const ContentSettingsType type = ContentSettingsType::GEOLOCATION; + const content_settings::ContentSettingConstraints constraint{ + .track_last_visit_for_autoexpiration = true}; + + absl::optional<uint32_t> days_since_revocation; + + // Permission has not yet been revoked, so shouldn't return a number of days + // since revocation. + days_since_revocation = UnusedSitePermissionsService::GetDaysSinceRevocation( + url, ContentSettingsType::GEOLOCATION, clock()->Now(), hcsm()); + ASSERT_FALSE(days_since_revocation.has_value()); + + hcsm()->SetContentSettingDefaultScope( + url, url, type, ContentSetting::CONTENT_SETTING_ALLOW, constraint); + EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 0u); + + // Travel 70 days through time so that the granted permission is revoked. + clock()->Advance(base::Days(70)); + service()->UpdateUnusedPermissionsForTesting(); + EXPECT_EQ(GetRevokedUnusedPermissions(hcsm()).size(), 1u); + + days_since_revocation = UnusedSitePermissionsService::GetDaysSinceRevocation( + url, ContentSettingsType::GEOLOCATION, clock()->Now(), hcsm()); + ASSERT_TRUE(days_since_revocation.has_value()); + EXPECT_EQ(days_since_revocation.value(), 0u); + + // Forward the clock for five days, which would be the number of days since + // revocation. + clock()->Advance(base::Days(5)); + + days_since_revocation = UnusedSitePermissionsService::GetDaysSinceRevocation( + url, ContentSettingsType::GEOLOCATION, clock()->Now(), hcsm()); + ASSERT_TRUE(days_since_revocation.has_value()); + EXPECT_EQ(days_since_revocation.value(), 5u); + + // Revoked permission is cleaned up after >30 days. + clock()->Advance(base::Days(40)); + days_since_revocation = UnusedSitePermissionsService::GetDaysSinceRevocation( + url, ContentSettingsType::GEOLOCATION, clock()->Now(), hcsm()); + ASSERT_FALSE(days_since_revocation.has_value()); +} + } // namespace permissions
diff --git a/components/power_metrics/BUILD.gn b/components/power_metrics/BUILD.gn index 2e1313b..4bb1972 100644 --- a/components/power_metrics/BUILD.gn +++ b/components/power_metrics/BUILD.gn
@@ -29,6 +29,7 @@ "smc_mac.h", "smc_mac.mm", ] + configs += [ "//build/config/compiler:enable_arc" ] } if (is_win) { @@ -64,6 +65,7 @@ "energy_impact_mac_unittest.mm", "resource_coalition_mac_unittest.mm", ] + configs += [ "//build/config/compiler:enable_arc" ] data = [ "test/data/" ]
diff --git a/components/power_metrics/energy_impact_mac.mm b/components/power_metrics/energy_impact_mac.mm index 0c00212a..998558d 100644 --- a/components/power_metrics/energy_impact_mac.mm +++ b/components/power_metrics/energy_impact_mac.mm
@@ -15,20 +15,24 @@ #include "components/power_metrics/mach_time_mac.h" #include "components/power_metrics/resource_coalition_mac.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace power_metrics { namespace { NSDictionary* MaybeGetDictionaryFromPath(const base::FilePath& path) { // The folder where the energy coefficient plist files are stored. - NSString* plist_path_string = base::SysUTF8ToNSString(path.value().c_str()); - return [NSDictionary dictionaryWithContentsOfFile:plist_path_string]; + return + [NSDictionary dictionaryWithContentsOfURL:base::mac::FilePathToNSURL(path) + error:nil]; } double GetNamedCoefficientOrZero(NSDictionary* dict, NSString* key) { - NSObject* value = [dict objectForKey:key]; - NSNumber* num = base::mac::ObjCCast<NSNumber>(value); - return [num floatValue]; + NSNumber* num = base::mac::ObjCCast<NSNumber>(dict[key]); + return num.floatValue; } } // namespace @@ -112,12 +116,14 @@ const base::FilePath& plist_file) { @autoreleasepool { NSDictionary* dict = MaybeGetDictionaryFromPath(plist_file); - if (!dict) + if (!dict) { return absl::nullopt; + } - NSDictionary* energy_constants = [dict objectForKey:@"energy_constants"]; - if (!energy_constants) + NSDictionary* energy_constants = dict[@"energy_constants"]; + if (!energy_constants) { return absl::nullopt; + } EnergyImpactCoefficients coefficients{}; coefficients.kcpu_time =
diff --git a/components/power_metrics/energy_impact_mac_unittest.mm b/components/power_metrics/energy_impact_mac_unittest.mm index cd3ef53..2c181049 100644 --- a/components/power_metrics/energy_impact_mac_unittest.mm +++ b/components/power_metrics/energy_impact_mac_unittest.mm
@@ -9,6 +9,10 @@ #include "components/power_metrics/resource_coalition_mac.h" #include "testing/gtest/include/gtest/gtest.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace power_metrics { namespace { @@ -45,7 +49,7 @@ TEST(EnergyImpactTest, ReadCoefficientsFromPath) { base::FilePath test_path = GetTestDataPath(); - // Validate that attempting to read from a non-exisent file fails. + // Validate that attempting to read from a non-existent file fails. auto coefficients = internal::ReadCoefficientsFromPath( test_path.Append(FILE_PATH_LITERAL("does-not-exist.plist"))); EXPECT_FALSE(coefficients.has_value());
diff --git a/components/power_metrics/m1_sensors_mac.h b/components/power_metrics/m1_sensors_mac.h index e054332..ff8471a6 100644 --- a/components/power_metrics/m1_sensors_mac.h +++ b/components/power_metrics/m1_sensors_mac.h
@@ -8,10 +8,10 @@ #ifndef COMPONENTS_POWER_METRICS_M1_SENSORS_MAC_H_ #define COMPONENTS_POWER_METRICS_M1_SENSORS_MAC_H_ -#include <memory> - #include <IOKit/hidsystem/IOHIDEventSystemClient.h> +#include <memory> + #include "base/mac/scoped_cftyperef.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -37,7 +37,8 @@ virtual TemperaturesCelsius ReadTemperatures(); protected: - M1SensorsReader(base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system); + explicit M1SensorsReader( + base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system); private: base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system_;
diff --git a/components/power_metrics/m1_sensors_mac.mm b/components/power_metrics/m1_sensors_mac.mm index fbe94fe..9c32756 100644 --- a/components/power_metrics/m1_sensors_mac.mm +++ b/components/power_metrics/m1_sensors_mac.mm
@@ -4,16 +4,22 @@ #include "components/power_metrics/m1_sensors_mac.h" +#include <CoreFoundation/CoreFoundation.h> #import <Foundation/Foundation.h> #import <IOKit/hid/IOHIDDeviceKeys.h> #import <IOKit/hidsystem/IOHIDServiceClient.h> #include <utility> +#include "base/mac/bridging.h" #include "base/mac/foundation_util.h" #include "base/memory/ptr_util.h" #include "components/power_metrics/m1_sensors_internal_types_mac.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + extern "C" { extern IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef); @@ -57,11 +63,10 @@ return nullptr; NSDictionary* filter = @{ - @kIOHIDPrimaryUsagePageKey : [NSNumber numberWithInt:kHIDPage_AppleVendor], - @kIOHIDPrimaryUsageKey : - [NSNumber numberWithInt:kHIDUsage_AppleVendor_TemperatureSensor], + @kIOHIDPrimaryUsagePageKey : @(kHIDPage_AppleVendor), + @kIOHIDPrimaryUsageKey : @(kHIDUsage_AppleVendor_TemperatureSensor), }; - IOHIDEventSystemClientSetMatching(system, base::mac::NSToCFCast(filter)); + IOHIDEventSystemClientSetMatching(system, base::mac::NSToCFPtrCast(filter)); return base::WrapUnique(new M1SensorsReader(std::move(system))); } @@ -77,17 +82,17 @@ double sum_p_core_temp = 0; double sum_e_core_temp = 0; - for (id service_obj in base::mac::CFToNSCast(services.get())) { - IOHIDServiceClientRef service = (IOHIDServiceClientRef)service_obj; + for (CFIndex i = 0; i < CFArrayGetCount(services); ++i) { + IOHIDServiceClientRef service = + (IOHIDServiceClientRef)CFArrayGetValueAtIndex(services, i); - base::ScopedCFTypeRef<CFStringRef> product_cf( - base::mac::CFCast<CFStringRef>( - IOHIDServiceClientCopyProperty(service, CFSTR(kIOHIDProductKey)))); - if (product_cf == nil) + base::ScopedCFTypeRef<CFStringRef> product(base::mac::CFCast<CFStringRef>( + IOHIDServiceClientCopyProperty(service, CFSTR(kIOHIDProductKey)))); + if (product == nil) { continue; + } - if ([base::mac::CFToNSCast(product_cf.get()) - hasPrefix:@"pACC MTR Temp Sensor"]) { + if (CFStringHasPrefix(product, CFSTR("pACC MTR Temp Sensor"))) { absl::optional<double> temp = GetEventFloatValue(service, kIOHIDEventTypeTemperature); if (temp.has_value()) { @@ -96,8 +101,7 @@ } } - if ([base::mac::CFToNSCast(product_cf.get()) - hasPrefix:@"eACC MTR Temp Sensor"]) { + if (CFStringHasPrefix(product, CFSTR("eACC MTR Temp Sensor"))) { absl::optional<double> temp = GetEventFloatValue(service, kIOHIDEventTypeTemperature); if (temp.has_value()) {
diff --git a/components/power_metrics/mach_time_mac.mm b/components/power_metrics/mach_time_mac.mm index a688242..ea6c0bcb 100644 --- a/components/power_metrics/mach_time_mac.mm +++ b/components/power_metrics/mach_time_mac.mm
@@ -7,6 +7,10 @@ #include "base/check.h" #include "base/mac/mach_logging.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace power_metrics { uint64_t MachTimeToNs(uint64_t mach_time,
diff --git a/components/power_metrics/resource_coalition_mac.h b/components/power_metrics/resource_coalition_mac.h index 723c1542..cfa2b42 100644 --- a/components/power_metrics/resource_coalition_mac.h +++ b/components/power_metrics/resource_coalition_mac.h
@@ -36,7 +36,7 @@ int64_t coalition_id); // Returns a `coalition_resource_usage` in which each member is the result of -// substracting the corresponding fields in `left` and `right`. +// subtracting the corresponding fields in `left` and `right`. coalition_resource_usage GetCoalitionResourceUsageDifference( const coalition_resource_usage& left, const coalition_resource_usage& right); @@ -68,4 +68,4 @@ } // namespace power_metrics -#endif // COMPONENTS_PPOWER_METRICS_RESOURCE_COALITION_MAC_H_ +#endif // COMPONENTS_POWER_METRICS_RESOURCE_COALITION_MAC_H_
diff --git a/components/power_metrics/resource_coalition_mac.mm b/components/power_metrics/resource_coalition_mac.mm index 3cc0c6c3..03b7f98 100644 --- a/components/power_metrics/resource_coalition_mac.mm +++ b/components/power_metrics/resource_coalition_mac.mm
@@ -10,6 +10,10 @@ #include "components/power_metrics/energy_impact_mac.h" #include "components/power_metrics/mach_time_mac.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + extern "C" int coalition_info_resource_usage( uint64_t cid, struct coalition_resource_usage* cru,
diff --git a/components/power_metrics/resource_coalition_mac_unittest.mm b/components/power_metrics/resource_coalition_mac_unittest.mm index 57430d5..f5887ad 100644 --- a/components/power_metrics/resource_coalition_mac_unittest.mm +++ b/components/power_metrics/resource_coalition_mac_unittest.mm
@@ -9,6 +9,10 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace power_metrics { namespace {
diff --git a/components/power_metrics/smc_mac.mm b/components/power_metrics/smc_mac.mm index 6d3a762..ff46b74 100644 --- a/components/power_metrics/smc_mac.mm +++ b/components/power_metrics/smc_mac.mm
@@ -9,6 +9,10 @@ #include "base/memory/ptr_util.h" +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace power_metrics { namespace { @@ -113,7 +117,7 @@ connect_.reset(); } - // Even if the close failed, report whether the actual call succeded. + // Even if the close failed, report whether the actual call succeeded. return success; }
diff --git a/components/safe_browsing/core/browser/db/hash_prefix_map.cc b/components/safe_browsing/core/browser/db/hash_prefix_map.cc index 4999ca6..cc039997 100644 --- a/components/safe_browsing/core/browser/db/hash_prefix_map.cc +++ b/components/safe_browsing/core/browser/db/hash_prefix_map.cc
@@ -5,6 +5,8 @@ #include "components/safe_browsing/core/browser/db/hash_prefix_map.h" #include "base/files/file_util.h" +#include "base/memory/ptr_util.h" +#include "base/memory/raw_ref.h" #include "base/strings/strcat.h" #include "components/safe_browsing/core/browser/db/prefix_iterator.h" #include "components/safe_browsing/core/common/features.h" @@ -144,18 +146,59 @@ return APPLY_UPDATE_SUCCESS; } -bool InMemoryHashPrefixMap::WriteToDisk(V4StoreFileFormat* file_format) { - ListUpdateResponse* lur = file_format->mutable_list_update_response(); - for (const auto& entry : map_) { +namespace { + +class InMemoryHashPrefixMapWriteSession : public HashPrefixMap::WriteSession { + public: + InMemoryHashPrefixMapWriteSession( + std::unordered_map<PrefixSize, HashPrefixes>& map, + ListUpdateResponse* lur) + : map_(map), lur_(*lur) {} + InMemoryHashPrefixMapWriteSession(const InMemoryHashPrefixMapWriteSession&) = + delete; + InMemoryHashPrefixMapWriteSession& operator=( + const InMemoryHashPrefixMapWriteSession&) = delete; + ~InMemoryHashPrefixMapWriteSession() override { + auto addition_scanner = lur_->mutable_additions()->begin(); + // Move each raw hash from the `ListUpdateResponse` back into the map. + for (auto& entry : *map_) { + auto raw_hashes = base::WrapUnique( + addition_scanner->mutable_raw_hashes()->release_raw_hashes()); + entry.second = std::move(*raw_hashes); + ++addition_scanner; + } + } + + private: + const base::raw_ref<std::unordered_map<PrefixSize, HashPrefixes>> map_; + const base::raw_ref<ListUpdateResponse> lur_; +}; + +} // namespace + +std::unique_ptr<HashPrefixMap::WriteSession> InMemoryHashPrefixMap::WriteToDisk( + V4StoreFileFormat* file_format) { + ListUpdateResponse* const lur = file_format->mutable_list_update_response(); + // `file_format` is expected to not contain any additions at this point. It + // will during migration from an MmapHashPrefixMap, but the map itself is + // empty in that case so there is no data to move into/out of the session. + CHECK(lur->additions_size() == 0 || map_.empty()); + for (auto& entry : map_) { ThreatEntrySet* additions = lur->add_additions(); // TODO(vakh): Write RICE encoded hash prefixes on disk. Not doing so // currently since it takes a long time to decode them on startup, which // blocks resource load. See: http://crbug.com/654819 additions->set_compression_type(RAW); additions->mutable_raw_hashes()->set_prefix_size(entry.first); - additions->mutable_raw_hashes()->set_raw_hashes(entry.second); + + // Avoid copying the raw hashes by temporarily moving them into + // `file_format`. They will be returned to the map when the caller destroys + // the returned write session. + auto raw_hashes = std::make_unique<std::string>(std::move(entry.second)); + additions->mutable_raw_hashes()->set_allocated_raw_hashes( + raw_hashes.release()); } - return true; + return std::make_unique<InMemoryHashPrefixMapWriteSession>(map_, lur); } ApplyUpdateResult InMemoryHashPrefixMap::IsValid() const { @@ -329,16 +372,30 @@ return APPLY_UPDATE_SUCCESS; } -bool MmapHashPrefixMap::WriteToDisk(V4StoreFileFormat* file_format) { +namespace { + +class MmapHashPrefixMapWriteSession : public HashPrefixMap::WriteSession { + public: + MmapHashPrefixMapWriteSession() = default; + MmapHashPrefixMapWriteSession(const MmapHashPrefixMapWriteSession&) = delete; + MmapHashPrefixMapWriteSession& operator=( + const MmapHashPrefixMapWriteSession&) = delete; + ~MmapHashPrefixMapWriteSession() override = default; +}; + +} // namespace + +std::unique_ptr<HashPrefixMap::WriteSession> MmapHashPrefixMap::WriteToDisk( + V4StoreFileFormat* file_format) { for (auto& [size, file_info] : map_) { auto* hash_file = file_format->add_hash_files(); if (!file_info.Finalize(hash_file)) - return false; + return nullptr; if (!file_info.Initialize(*hash_file)) - return false; + return nullptr; } - return true; + return std::make_unique<MmapHashPrefixMapWriteSession>(); } ApplyUpdateResult MmapHashPrefixMap::IsValid() const {
diff --git a/components/safe_browsing/core/browser/db/hash_prefix_map.h b/components/safe_browsing/core/browser/db/hash_prefix_map.h index 28b3ff6..d7e295de 100644 --- a/components/safe_browsing/core/browser/db/hash_prefix_map.h +++ b/components/safe_browsing/core/browser/db/hash_prefix_map.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_SAFE_BROWSING_CORE_BROWSER_DB_HASH_PREFIX_MAP_H_ #define COMPONENTS_SAFE_BROWSING_CORE_BROWSER_DB_HASH_PREFIX_MAP_H_ +#include <memory> #include <string> #include <unordered_map> @@ -94,10 +95,26 @@ // Reserves space for the prefix list of size |size|. virtual void Reserve(PrefixSize size, size_t capacity) = 0; - // Reads and writes the map from disk. + // Reads the map from disk. virtual ApplyUpdateResult ReadFromDisk( const V4StoreFileFormat& file_format) = 0; - virtual bool WriteToDisk(V4StoreFileFormat* file_format) = 0; + + class WriteSession { + public: + WriteSession(const WriteSession&) = delete; + WriteSession& operator=(const WriteSession&) = delete; + virtual ~WriteSession() = default; + + protected: + WriteSession() = default; + }; + + // Write the map to disk. Returns null in case of error, or a session instance + // that must be kept alive until `file_format` is committed to disk. + // Implementations may lend some internal state to `file_format` so that it + // can be written to disk with minimal overhead. + virtual std::unique_ptr<WriteSession> WriteToDisk( + V4StoreFileFormat* file_format) = 0; // Returns true if the data in this map is valid and can be used. virtual ApplyUpdateResult IsValid() const = 0; @@ -129,7 +146,8 @@ void Append(PrefixSize size, HashPrefixesView prefix) override; void Reserve(PrefixSize size, size_t capacity) override; ApplyUpdateResult ReadFromDisk(const V4StoreFileFormat& file_format) override; - bool WriteToDisk(V4StoreFileFormat* file_format) override; + std::unique_ptr<WriteSession> WriteToDisk( + V4StoreFileFormat* file_format) override; ApplyUpdateResult IsValid() const override; HashPrefixStr GetMatchingHashPrefix(base::StringPiece full_hash) override; MigrateResult MigrateFileFormat(const base::FilePath& store_path, @@ -156,7 +174,8 @@ void Append(PrefixSize size, HashPrefixesView prefix) override; void Reserve(PrefixSize size, size_t capacity) override; ApplyUpdateResult ReadFromDisk(const V4StoreFileFormat& file_format) override; - bool WriteToDisk(V4StoreFileFormat* file_format) override; + std::unique_ptr<WriteSession> WriteToDisk( + V4StoreFileFormat* file_format) override; ApplyUpdateResult IsValid() const override; HashPrefixStr GetMatchingHashPrefix(base::StringPiece full_hash) override; MigrateResult MigrateFileFormat(const base::FilePath& store_path,
diff --git a/components/safe_browsing/core/browser/db/hash_prefix_map_unittest.cc b/components/safe_browsing/core/browser/db/hash_prefix_map_unittest.cc index 3c3e958..00d8745 100644 --- a/components/safe_browsing/core/browser/db/hash_prefix_map_unittest.cc +++ b/components/safe_browsing/core/browser/db/hash_prefix_map_unittest.cc
@@ -4,6 +4,8 @@ #include "components/safe_browsing/core/browser/db/hash_prefix_map.h" +#include <type_traits> + #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/ranges/algorithm.h" @@ -388,5 +390,78 @@ HashPrefixMap::MigrateResult::kNotNeeded); } +// A test fixture for running tests against all supported HashPrefixMap +// implementations. +template <typename T> +class HashPrefixMapTypedTest : public ::testing::Test { + protected: + void SetUp() override { + ASSERT_TRUE(hash_prefix_map_ = CreateHashPrefixMap()); + } + + HashPrefixMap& hash_prefix_map() { return *hash_prefix_map_; } + + private: + // Returns a new HashPrefixMap of the type under test, or nullptr in case of + // error. In the latter case, the test will have a non-fatal failure. + std::unique_ptr<HashPrefixMap> CreateHashPrefixMap(); + + absl::optional<base::ScopedTempDir> temp_dir_; + std::unique_ptr<HashPrefixMap> hash_prefix_map_; +}; + +template <> +std::unique_ptr<HashPrefixMap> +HashPrefixMapTypedTest<InMemoryHashPrefixMap>::CreateHashPrefixMap() { + return std::make_unique<InMemoryHashPrefixMap>(); +} + +template <> +std::unique_ptr<HashPrefixMap> +HashPrefixMapTypedTest<MmapHashPrefixMap>::CreateHashPrefixMap() { + // HashPrefixMap needs to write files to disk, so create a temp directory and + // point the instance at it. + if (!temp_dir_) { + temp_dir_.emplace(); + EXPECT_TRUE(temp_dir_->CreateUniqueTempDir()); + } + return temp_dir_->IsValid() ? std::make_unique<MmapHashPrefixMap>( + temp_dir_->GetPath().AppendASCII("Test")) + : nullptr; +} + +using HashPrefixMapTypes = + ::testing::Types<InMemoryHashPrefixMap, MmapHashPrefixMap>; + +class HashPrefixTypeNames { + public: + template <typename T> + static std::string GetName(int i) { + if (std::is_same<T, InMemoryHashPrefixMap>::value) { + return "InMemoryHashPrefixMap"; + } + if (std::is_same<T, MmapHashPrefixMap>::value) { + return "MmapHashPrefixMap"; + } + } +}; + +TYPED_TEST_SUITE(HashPrefixMapTypedTest, + HashPrefixMapTypes, + HashPrefixTypeNames); + +// Tests that the data in a map is still valid after writing it. +TYPED_TEST(HashPrefixMapTypedTest, ValidAfterWrite) { + auto& hash_prefix_map = this->hash_prefix_map(); + hash_prefix_map.Append(4, "foo"); + + V4StoreFileFormat file_format; + ASSERT_TRUE(hash_prefix_map.WriteToDisk(&file_format)); + + HashPrefixMapView view = hash_prefix_map.view(); + EXPECT_EQ(view.size(), 1u); + EXPECT_EQ(view[4], "foo"); +} + } // namespace } // namespace safe_browsing
diff --git a/components/safe_browsing/core/browser/db/v4_store.cc b/components/safe_browsing/core/browser/db/v4_store.cc index b4df352..0cabf90 100644 --- a/components/safe_browsing/core/browser/db/v4_store.cc +++ b/components/safe_browsing/core/browser/db/v4_store.cc
@@ -953,19 +953,24 @@ }, new_filename, store_path_, base::Unretained(file_format))); - if (!hash_prefix_map_->WriteToDisk(file_format)) - return UNEXPECTED_WRITE_FAILURE; - - file_format->set_magic_number(kFileMagic); - file_format->set_version_number(kFileVersion); int64_t written = 0; - { - BaseFileOutputStream output_stream(new_filename); - if (!file_format->SerializeToZeroCopyStream(&output_stream) || - !output_stream.Flush()) { - return UNEXPECTED_BYTES_WRITTEN_FAILURE; + // `write_session` must remain alive until `file_format` is committed to disk. + // Additionally, note that `hash_prefix_map_` is unusable throughout the + // lifetime of `write_session`. + if (auto write_session = hash_prefix_map_->WriteToDisk(file_format); + write_session) { + file_format->set_magic_number(kFileMagic); + file_format->set_version_number(kFileVersion); + { + BaseFileOutputStream output_stream(new_filename); + if (!file_format->SerializeToZeroCopyStream(&output_stream) || + !output_stream.Flush()) { + return UNEXPECTED_BYTES_WRITTEN_FAILURE; + } + written = output_stream.ByteCount(); } - written = output_stream.ByteCount(); + } else { + return UNEXPECTED_WRITE_FAILURE; } if (!base::Move(new_filename, store_path_))
diff --git a/components/saved_tab_groups/saved_tab_group_model.cc b/components/saved_tab_groups/saved_tab_group_model.cc index 1a4e2d4..4c27d8f1 100644 --- a/components/saved_tab_groups/saved_tab_group_model.cc +++ b/components/saved_tab_groups/saved_tab_group_model.cc
@@ -8,6 +8,7 @@ #include <memory> #include <vector> +#include "base/metrics/histogram_functions.h" #include "base/observer_list.h" #include "base/strings/utf_string_conversions.h" #include "base/uuid.h" @@ -86,6 +87,8 @@ for (auto& observer : observers_) { observer.SavedTabGroupRemovedLocally(removed_group.get()); } + + RecordGroupDeletedMetric(removed_group.get()); } void SavedTabGroupModel::Remove(const base::Uuid& id) { @@ -99,6 +102,8 @@ for (auto& observer : observers_) { observer.SavedTabGroupRemovedLocally(removed_group.get()); } + + RecordGroupDeletedMetric(removed_group.get()); } void SavedTabGroupModel::UpdateVisualData( @@ -364,6 +369,15 @@ } } +void SavedTabGroupModel::RecordGroupDeletedMetric( + const SavedTabGroup* removed_group) { + const base::TimeDelta duration_saved = + base::Time::Now() - removed_group->creation_time_windows_epoch_micros(); + + base::UmaHistogramCounts1M("TabGroups.SavedTabGroupLifespan", + duration_saved.InMinutes()); +} + void SavedTabGroupModel::UpdateGroupPositionsImpl() { for (size_t i = 0; i < saved_tab_groups_.size(); ++i) saved_tab_groups_[i].SetPosition(i);
diff --git a/components/saved_tab_groups/saved_tab_group_model.h b/components/saved_tab_groups/saved_tab_group_model.h index edd5620a..f27f4be 100644 --- a/components/saved_tab_groups/saved_tab_group_model.h +++ b/components/saved_tab_groups/saved_tab_group_model.h
@@ -143,6 +143,8 @@ void RemoveObserver(SavedTabGroupModelObserver* observer); private: + void RecordGroupDeletedMetric(const SavedTabGroup* removed_group); + // Updates all group positions to match the index they are currently stored // at. void UpdateGroupPositionsImpl();
diff --git a/components/services/app_service/public/cpp/icon_info.cc b/components/services/app_service/public/cpp/icon_info.cc index e72a144..618f38b 100644 --- a/components/services/app_service/public/cpp/icon_info.cc +++ b/components/services/app_service/public/cpp/icon_info.cc
@@ -30,12 +30,12 @@ IconInfo& IconInfo::operator=(IconInfo&&) noexcept = default; base::Value IconInfo::AsDebugValue() const { - base::Value root(base::Value::Type::DICT); - root.SetStringKey("url", url.spec()); - root.SetKey("square_size_px", - square_size_px ? base::Value(*square_size_px) : base::Value()); - root.SetStringKey("purpose", kPurposeStrings[static_cast<int>(purpose)]); - return root; + base::Value::Dict root; + root.Set("url", url.spec()); + root.Set("square_size_px", + square_size_px ? base::Value(*square_size_px) : base::Value()); + root.Set("purpose", kPurposeStrings[static_cast<int>(purpose)]); + return base::Value(std::move(root)); } bool IconInfo::operator==(const IconInfo& other) const {
diff --git a/components/services/app_service/public/cpp/protocol_handler_info.cc b/components/services/app_service/public/cpp/protocol_handler_info.cc index c3643a7..b5958e33 100644 --- a/components/services/app_service/public/cpp/protocol_handler_info.cc +++ b/components/services/app_service/public/cpp/protocol_handler_info.cc
@@ -24,10 +24,10 @@ } base::Value ProtocolHandlerInfo::AsDebugValue() const { - base::Value root(base::Value::Type::DICT); - root.SetStringKey("protocol", protocol); - root.SetStringKey("url", url.spec()); - return root; + base::Value::Dict root; + root.Set("protocol", protocol); + root.Set("url", url.spec()); + return base::Value(std::move(root)); } } // namespace apps
diff --git a/components/services/app_service/public/cpp/share_target.cc b/components/services/app_service/public/cpp/share_target.cc index 8a1f313..ee1f1f9 100644 --- a/components/services/app_service/public/cpp/share_target.cc +++ b/components/services/app_service/public/cpp/share_target.cc
@@ -91,12 +91,12 @@ } base::Value ShareTarget::AsDebugValue() const { - base::Value root(base::Value::Type::DICT); - root.SetStringKey("action", action.spec()); - root.SetStringKey("method", ShareTarget::MethodToString(method)); - root.SetStringKey("enctype", ShareTarget::EnctypeToString(enctype)); - root.SetKey("params", params.AsDebugValue()); - return root; + base::Value::Dict root; + root.Set("action", action.spec()); + root.Set("method", ShareTarget::MethodToString(method)); + root.Set("enctype", ShareTarget::EnctypeToString(enctype)); + root.Set("params", params.AsDebugValue()); + return base::Value(std::move(root)); } bool operator==(const ShareTarget& share_target1,
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h index e1da889..2c6f601 100644 --- a/components/sync/driver/sync_service.h +++ b/components/sync/driver/sync_service.h
@@ -224,7 +224,9 @@ // early in the Sync setup flow, after the user has pressed "turn on Sync" but // before they have actually confirmed the settings. // TODO(crbug.com/1219990): Remove this API once the internal sync-requested - // bit is fully removed and rollback/killswitch safe. + // bit is fully removed and rollback/killswitch safe. Note that it also + // requires finding an alternative solution to resolving + // IsSyncFeatureDisabledViaDashboard(), tracked in crbug.com/1443446. virtual void SetSyncFeatureRequested() = 0; // Returns the SyncUserSettings, which encapsulate all the user-configurable @@ -295,6 +297,14 @@ // instead. virtual bool RequiresClientUpgrade() const = 0; + // Returns true only on ChromeOS (Ash), if sync-the-feature is disabled + // because the user cleared data from the Sync dashboard. It can be re-enabled + // by invoking SetSyncFeatureRequested(). + // TODO(crbug.com/1443446): Consider removing this API, for example by + // reporting IsFirstSetupComplete()==false which is otherwise unreachable on + // ChromeOS Ash. + virtual bool IsSyncFeatureDisabledViaDashboard() const = 0; + ////////////////////////////////////////////////////////////////////////////// // DERIVED STATE ACCESS ////////////////////////////////////////////////////////////////////////////// @@ -321,6 +331,8 @@ // after the engine has started. // Note: This refers to Sync-the-feature. Sync-the-transport may be running // even if this is false. + // TODO(crbug.com/1444344): Remove this API, in favor of + // IsSyncFeatureEnabled(). bool CanSyncFeatureStart() const; // Returns whether Sync-the-feature is active, which means
diff --git a/components/sync/driver/sync_service_impl.cc b/components/sync/driver/sync_service_impl.cc index 7d12d7f..6664b238 100644 --- a/components/sync/driver/sync_service_impl.cc +++ b/components/sync/driver/sync_service_impl.cc
@@ -128,14 +128,15 @@ user_agent, std::move(pending_url_loader_factory)); } -// Returns whether SyncService should list DISABLE_REASON_USER_CHOICE, given -// two alternative ways to determine it (except on Ash where both are relevant). -bool ShouldExposeDisableReasonUserChoice(bool has_sync_consent, - const SyncPrefs& sync_prefs) { +// Returns whether SyncService should consider the user opted into enabling +// sync-the-feature, given two alternative ways to determine it (except on +// Ash where both are relevant). +bool IsSyncFeatureConsideredRequested(bool has_sync_consent, + const SyncPrefs& sync_prefs) { CHECK(!sync_prefs.IsLocalSyncEnabled()); if (sync_prefs.IsSyncClientDisabledByPolicy()) { - return true; + return false; } const bool is_sync_requested = sync_prefs.IsSyncRequested(); @@ -143,22 +144,22 @@ // In most cases, the two values are identical. In this case there is no // reason to evaluate the feature toggle or reconcile the two values. if (has_sync_consent == is_sync_requested) { - return !has_sync_consent; + return has_sync_consent; } #if BUILDFLAG(IS_CHROMEOS_ASH) // On Ash, `has_sync_consent` should always be true, and what actually matters // is `is_sync_requested`, which is set to false if the server reports // DISABLE_SYNC_ON_CLIENT (e.g. reset via dashboard). - return !is_sync_requested; + return is_sync_requested; #else // On all platforms except Chrome Ash, `has_sync_consent` is the new way to // determine whether DISABLE_REASON_USER_CHOICE should be reported. Use it // if the feature toggle is enabled and otherwise fall back to the legacy // `is_sync_requested`. return base::FeatureList::IsEnabled(kSyncIgnoreSyncRequestedPreference) - ? !has_sync_consent - : !is_sync_requested; + ? has_sync_consent + : is_sync_requested; #endif // BUILDFLAG(IS_CHROMEOS_ASH) } @@ -292,7 +293,7 @@ // will set it, we need to set it here. // Local Sync bypasses the IsSyncRequested() check, so no need to set it in // that case. - // TODO(crbug.com/920158): Get rid of AUTO_START and remove this workaround. + // TODO(crbug.com/1443438): Get rid of AUTO_START and remove this workaround. if (start_behavior_ == AUTO_START && !IsLocalSyncEnabled() && !sync_prefs_.IsSyncRequestedSetExplicitly()) { SetSyncFeatureRequested(); @@ -680,7 +681,7 @@ if (!IsSignedIn()) { result.Put(DISABLE_REASON_NOT_SIGNED_IN); } - if (ShouldExposeDisableReasonUserChoice(HasSyncConsent(), sync_prefs_)) { + if (!IsSyncFeatureConsideredRequested(HasSyncConsent(), sync_prefs_)) { result.Put(DISABLE_REASON_USER_CHOICE); } } @@ -1175,6 +1176,14 @@ return last_actionable_error_.action == UPGRADE_CLIENT; } +bool SyncServiceImpl::IsSyncFeatureDisabledViaDashboard() const { + // This can return true only on ChromeOS Ash, upon DISABLE_SYNC_ON_CLIENT. + // TODO(crbug.com/1443446): A simpler and more robust implementation for this + // state would be to use a dedicated pref. + return user_settings_->IsFirstSetupComplete() && !IsLocalSyncEnabled() && + !IsSyncFeatureConsideredRequested(HasSyncConsent(), sync_prefs_); +} + bool SyncServiceImpl::CanConfigureDataTypes( bool bypass_setup_in_progress_check) const { // TODO(crbug.com/856179): Arguably, IsSetupInProgress() shouldn't prevent
diff --git a/components/sync/driver/sync_service_impl.h b/components/sync/driver/sync_service_impl.h index 71f104b..5072e0f 100644 --- a/components/sync/driver/sync_service_impl.h +++ b/components/sync/driver/sync_service_impl.h
@@ -63,6 +63,7 @@ public: // If AUTO_START, sync will set IsFirstSetupComplete() automatically and sync // will begin syncing without the user needing to confirm sync settings. + // TODO(crbug.com/1443438): Remove StartBehavior altogether. enum StartBehavior { AUTO_START, MANUAL_START, @@ -119,6 +120,7 @@ GoogleServiceAuthError GetAuthError() const override; base::Time GetAuthErrorTime() const override; bool RequiresClientUpgrade() const override; + bool IsSyncFeatureDisabledViaDashboard() const override; std::unique_ptr<SyncSetupInProgressHandle> GetSetupInProgressHandle() override; bool IsSetupInProgress() const override;
diff --git a/components/sync/driver/sync_service_impl_unittest.cc b/components/sync/driver/sync_service_impl_unittest.cc index 78e80e3..6c830a3c 100644 --- a/components/sync/driver/sync_service_impl_unittest.cc +++ b/components/sync/driver/sync_service_impl_unittest.cc
@@ -1003,12 +1003,22 @@ // DISABLE_SYNC_ON_CLIENT it disables sync and signs out. TEST_F(SyncServiceImplTest, DisableSyncOnClient) { SignIn(); + + // To make this test more realistic, the StartBehavior is chosen depending on + // the platform, which influences the behavior for + // IsSyncFeatureDisabledViaDashboard(). +#if BUILDFLAG(IS_CHROMEOS_ASH) + CreateService(SyncServiceImpl::AUTO_START); +#else CreateService(SyncServiceImpl::MANUAL_START); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + InitializeForNthSync(); ASSERT_EQ(SyncService::TransportState::ACTIVE, service()->GetTransportState()); ASSERT_EQ(0, get_controller(BOOKMARKS)->model()->clear_metadata_call_count()); + ASSERT_FALSE(service()->IsSyncFeatureDisabledViaDashboard()); EXPECT_CALL( *trusted_vault_client(), @@ -1031,6 +1041,7 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(SyncService::TransportState::ACTIVE, service()->GetTransportState()); + EXPECT_TRUE(service()->IsSyncFeatureDisabledViaDashboard()); #else EXPECT_FALSE( identity_manager()->HasPrimaryAccount(signin::ConsentLevel::kSync));
diff --git a/components/sync/test/fake_sync_service.cc b/components/sync/test/fake_sync_service.cc index 62688ff..27bddef 100644 --- a/components/sync/test/fake_sync_service.cc +++ b/components/sync/test/fake_sync_service.cc
@@ -104,6 +104,10 @@ return false; } +bool FakeSyncService::IsSyncFeatureDisabledViaDashboard() const { + return false; +} + void FakeSyncService::DataTypePreconditionChanged(ModelType type) {} syncer::SyncTokenStatus FakeSyncService::GetSyncTokenStatusForDebugging()
diff --git a/components/sync/test/fake_sync_service.h b/components/sync/test/fake_sync_service.h index b99c8240..cc43703 100644 --- a/components/sync/test/fake_sync_service.h +++ b/components/sync/test/fake_sync_service.h
@@ -49,6 +49,7 @@ GoogleServiceAuthError GetAuthError() const override; base::Time GetAuthErrorTime() const override; bool RequiresClientUpgrade() const override; + bool IsSyncFeatureDisabledViaDashboard() const override; void DataTypePreconditionChanged(syncer::ModelType type) override; SyncTokenStatus GetSyncTokenStatusForDebugging() const override; bool QueryDetailedSyncStatusForDebugging(SyncStatus* result) const override;
diff --git a/components/sync/test/mock_sync_service.h b/components/sync/test/mock_sync_service.h index aecb315..1c5dc60a 100644 --- a/components/sync/test/mock_sync_service.h +++ b/components/sync/test/mock_sync_service.h
@@ -47,6 +47,7 @@ MOCK_METHOD(GoogleServiceAuthError, GetAuthError, (), (const override)); MOCK_METHOD(base::Time, GetAuthErrorTime, (), (const override)); MOCK_METHOD(bool, RequiresClientUpgrade, (), (const override)); + MOCK_METHOD(bool, IsSyncFeatureDisabledViaDashboard, (), (const override)); MOCK_METHOD(std::unique_ptr<SyncSetupInProgressHandle>, GetSetupInProgressHandle, (),
diff --git a/components/sync/test/test_sync_service.cc b/components/sync/test/test_sync_service.cc index d1f71c5..d73c21b5 100644 --- a/components/sync/test/test_sync_service.cc +++ b/components/sync/test/test_sync_service.cc
@@ -61,6 +61,11 @@ has_sync_consent_ = has_sync_consent; } +void TestSyncService::SetSyncFeatureDisabledViaDashboard( + bool disabled_via_dashboard) { + sync_feature_disabled_via_dashboard_ = disabled_via_dashboard; +} + void TestSyncService::SetPersistentAuthError() { transport_state_ = TransportState::PAUSED; } @@ -138,6 +143,7 @@ void TestSyncService::SetSyncFeatureRequested() { disable_reasons_.Remove(SyncService::DISABLE_REASON_USER_CHOICE); + sync_feature_disabled_via_dashboard_ = false; } TestSyncUserSettings* TestSyncService::GetUserSettings() { @@ -192,6 +198,10 @@ syncer::UPGRADE_CLIENT; } +bool TestSyncService::IsSyncFeatureDisabledViaDashboard() const { + return sync_feature_disabled_via_dashboard_; +} + std::unique_ptr<SyncSetupInProgressHandle> TestSyncService::GetSetupInProgressHandle() { return nullptr;
diff --git a/components/sync/test/test_sync_service.h b/components/sync/test/test_sync_service.h index fac4e03..a0f51115 100644 --- a/components/sync/test/test_sync_service.h +++ b/components/sync/test/test_sync_service.h
@@ -37,6 +37,7 @@ void SetAccountInfo(const CoreAccountInfo& account_info); void SetHasSyncConsent(bool has_consent); void SetSetupInProgress(bool in_progress); + void SetSyncFeatureDisabledViaDashboard(bool disabled_via_dashboard); // Setters to mimic common auth error scenarios. Note that these functions // may change the transport state, as returned by GetTransportState(). @@ -75,6 +76,7 @@ GoogleServiceAuthError GetAuthError() const override; base::Time GetAuthErrorTime() const override; bool RequiresClientUpgrade() const override; + bool IsSyncFeatureDisabledViaDashboard() const override; std::unique_ptr<SyncSetupInProgressHandle> GetSetupInProgressHandle() override; @@ -130,6 +132,7 @@ CoreAccountInfo account_info_; bool has_sync_consent_ = true; bool setup_in_progress_ = false; + bool sync_feature_disabled_via_dashboard_ = false; ModelTypeSet failed_data_types_;
diff --git a/components/test/data/web_database/version_102.sql b/components/test/data/web_database/version_102.sql index 1ee33579..5bcc8df 100644 --- a/components/test/data/web_database/version_102.sql +++ b/components/test/data/web_database/version_102.sql
@@ -2,7 +2,7 @@ BEGIN TRANSACTION; CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); INSERT INTO meta VALUES('mmap_status','-1'); -INSERT INTO meta VALUES('version','101'); +INSERT INTO meta VALUES('version','102'); INSERT INTO meta VALUES('last_compatible_version','99'); INSERT INTO meta VALUES('Builtin Keyword Version','127'); CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); @@ -14,6 +14,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
diff --git a/components/test/data/web_database/version_103.sql b/components/test/data/web_database/version_103.sql index 1663fb9..4dda38e 100644 --- a/components/test/data/web_database/version_103.sql +++ b/components/test/data/web_database/version_103.sql
@@ -14,6 +14,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
diff --git a/components/test/data/web_database/version_104.sql b/components/test/data/web_database/version_104.sql index 3bd301b..b7c30e5 100644 --- a/components/test/data/web_database/version_104.sql +++ b/components/test/data/web_database/version_104.sql
@@ -14,6 +14,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR, product_description VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
diff --git a/components/test/data/web_database/version_105.sql b/components/test/data/web_database/version_105.sql index 2f824ad..67695c63 100644 --- a/components/test/data/web_database/version_105.sql +++ b/components/test/data/web_database/version_105.sql
@@ -15,6 +15,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR, product_description VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
diff --git a/components/test/data/web_database/version_106.sql b/components/test/data/web_database/version_106.sql index b8fa076..bd085169 100644 --- a/components/test/data/web_database/version_106.sql +++ b/components/test/data/web_database/version_106.sql
@@ -15,6 +15,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR, product_description VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
diff --git a/components/test/data/web_database/version_107.sql b/components/test/data/web_database/version_107.sql index b1d80b76..c91dc3dc 100644 --- a/components/test/data/web_database/version_107.sql +++ b/components/test/data/web_database/version_107.sql
@@ -15,6 +15,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR, product_description VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
diff --git a/components/test/data/web_database/version_108.sql b/components/test/data/web_database/version_108.sql index a2cf7e3..8ca35f0 100644 --- a/components/test/data/web_database/version_108.sql +++ b/components/test/data/web_database/version_108.sql
@@ -15,6 +15,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR, product_description VARCHAR, card_issuer_id VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR);
diff --git a/components/test/data/web_database/version_109.sql b/components/test/data/web_database/version_109.sql index e10183a1..ba3a27c6 100644 --- a/components/test/data/web_database/version_109.sql +++ b/components/test/data/web_database/version_109.sql
@@ -15,6 +15,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR, product_description VARCHAR, card_issuer_id VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE virtual_card_usage_data (id VARCHAR PRIMARY KEY, instrument_id INTEGER DEFAULT 0, merchant_domain VARCHAR, last_four VARCHAR);
diff --git a/components/test/data/web_database/version_110.sql b/components/test/data/web_database/version_110.sql index b71f290..394cf17 100644 --- a/components/test/data/web_database/version_110.sql +++ b/components/test/data/web_database/version_110.sql
@@ -15,6 +15,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR, product_description VARCHAR, card_issuer_id VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE virtual_card_usage_data (id VARCHAR PRIMARY KEY, instrument_id INTEGER DEFAULT 0, merchant_domain VARCHAR, last_four VARCHAR);
diff --git a/components/test/data/web_database/version_111.sql b/components/test/data/web_database/version_111.sql index 5353ef0..1f7b24c5 100644 --- a/components/test/data/web_database/version_111.sql +++ b/components/test/data/web_database/version_111.sql
@@ -15,6 +15,7 @@ CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); +CREATE TABLE autofill_profile_birthdates ( guid VARCHAR, day INTEGER DEFAULT 0, month INTEGER DEFAULT 0, year INTEGER DEFAULT 0); CREATE TABLE masked_credit_cards (id VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR, product_description VARCHAR, card_issuer_id VARCHAR, virtual_card_enrollment_type INTEGER DEFAULT 0); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE virtual_card_usage_data (id VARCHAR PRIMARY KEY, instrument_id INTEGER DEFAULT 0, merchant_domain VARCHAR, last_four VARCHAR);
diff --git a/components/test/data/web_database/version_87.sql b/components/test/data/web_database/version_87.sql index a2434b7..ae5b5acc2 100644 --- a/components/test/data/web_database/version_87.sql +++ b/components/test/data/web_database/version_87.sql
@@ -2,13 +2,13 @@ BEGIN TRANSACTION; CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); INSERT INTO meta VALUES('mmap_status','-1'); -INSERT INTO meta VALUES('version','86'); +INSERT INTO meta VALUES('version','87'); INSERT INTO meta VALUES('last_compatible_version','83'); INSERT INTO meta VALUES('Builtin Keyword Version','117'); CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR,last_visited INTEGER DEFAULT 0, created_from_play_api INTEGER DEFAULT 0); CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value)); -CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); +CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); @@ -26,4 +26,4 @@ CREATE TABLE server_card_cloud_token_data ( id VARCHAR, suffix VARCHAR, exp_month INTEGER DEFAULT 0, exp_year INTEGER DEFAULT 0, card_art_url VARCHAR, instrument_token VARCHAR); CREATE INDEX autofill_name ON autofill (name); CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -COMMIT; \ No newline at end of file +COMMIT;
diff --git a/components/test/data/web_database/version_88.sql b/components/test/data/web_database/version_88.sql index 99f4e25..90091fd 100644 --- a/components/test/data/web_database/version_88.sql +++ b/components/test/data/web_database/version_88.sql
@@ -11,7 +11,6 @@ CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); CREATE TABLE autofill_profiles_trash ( guid VARCHAR); @@ -27,4 +26,4 @@ CREATE TABLE server_card_cloud_token_data ( id VARCHAR, suffix VARCHAR, exp_month INTEGER DEFAULT 0, exp_year INTEGER DEFAULT 0, card_art_url VARCHAR, instrument_token VARCHAR); CREATE INDEX autofill_name ON autofill (name); CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -COMMIT; \ No newline at end of file +COMMIT;
diff --git a/components/test/data/web_database/version_89.sql b/components/test/data/web_database/version_89.sql index 99f4e25..4e71b37e 100644 --- a/components/test/data/web_database/version_89.sql +++ b/components/test/data/web_database/version_89.sql
@@ -2,7 +2,7 @@ BEGIN TRANSACTION; CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); INSERT INTO meta VALUES('mmap_status','-1'); -INSERT INTO meta VALUES('version','88'); +INSERT INTO meta VALUES('version','89'); INSERT INTO meta VALUES('last_compatible_version','83'); INSERT INTO meta VALUES('Builtin Keyword Version','117'); CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); @@ -11,11 +11,10 @@ CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0); +CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR); @@ -27,4 +26,4 @@ CREATE TABLE server_card_cloud_token_data ( id VARCHAR, suffix VARCHAR, exp_month INTEGER DEFAULT 0, exp_year INTEGER DEFAULT 0, card_art_url VARCHAR, instrument_token VARCHAR); CREATE INDEX autofill_name ON autofill (name); CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower); -COMMIT; \ No newline at end of file +COMMIT;
diff --git a/components/test/data/web_database/version_90.sql b/components/test/data/web_database/version_90.sql index e04e527..d8d39098 100644 --- a/components/test/data/web_database/version_90.sql +++ b/components/test/data/web_database/version_90.sql
@@ -2,7 +2,7 @@ BEGIN TRANSACTION; CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); INSERT INTO meta VALUES('mmap_status','-1'); -INSERT INTO meta VALUES('version','88'); +INSERT INTO meta VALUES('version','90'); INSERT INTO meta VALUES('last_compatible_version','83'); INSERT INTO meta VALUES('Builtin Keyword Version','117'); CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); @@ -11,12 +11,11 @@ CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0); CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0); +CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR);
diff --git a/components/test/data/web_database/version_91.sql b/components/test/data/web_database/version_91.sql index e04e527..5043ceb 100644 --- a/components/test/data/web_database/version_91.sql +++ b/components/test/data/web_database/version_91.sql
@@ -2,7 +2,7 @@ BEGIN TRANSACTION; CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); INSERT INTO meta VALUES('mmap_status','-1'); -INSERT INTO meta VALUES('version','88'); +INSERT INTO meta VALUES('version','91'); INSERT INTO meta VALUES('last_compatible_version','83'); INSERT INTO meta VALUES('Builtin Keyword Version','117'); CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); @@ -11,12 +11,11 @@ CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0); -CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0); +CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0, apartment_number VARCHAR, floor VARCHAR, apartment_number_status INTEGER DEFAULT 0, floor_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0); +CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR);
diff --git a/components/test/data/web_database/version_92.sql b/components/test/data/web_database/version_92.sql index e04e527..db6e2a7 100644 --- a/components/test/data/web_database/version_92.sql +++ b/components/test/data/web_database/version_92.sql
@@ -2,7 +2,7 @@ BEGIN TRANSACTION; CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); INSERT INTO meta VALUES('mmap_status','-1'); -INSERT INTO meta VALUES('version','88'); +INSERT INTO meta VALUES('version','92'); INSERT INTO meta VALUES('last_compatible_version','83'); INSERT INTO meta VALUES('Builtin Keyword Version','117'); CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); @@ -10,13 +10,12 @@ CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value)); CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE); -CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0); -CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0); +CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); +CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0, apartment_number VARCHAR, floor VARCHAR, apartment_number_status INTEGER DEFAULT 0, floor_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0); +CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR);
diff --git a/components/test/data/web_database/version_93.sql b/components/test/data/web_database/version_93.sql index 4f5b8b06..6865767e 100644 --- a/components/test/data/web_database/version_93.sql +++ b/components/test/data/web_database/version_93.sql
@@ -11,7 +11,6 @@ CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE, label VARCHAR); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0, 'Sir Jon Smith', 0); CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0, apartment_number VARCHAR, floor VARCHAR, apartment_number_status INTEGER DEFAULT 0, floor_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR);
diff --git a/components/test/data/web_database/version_94.sql b/components/test/data/web_database/version_94.sql index f24ffe2..0802d567 100644 --- a/components/test/data/web_database/version_94.sql +++ b/components/test/data/web_database/version_94.sql
@@ -11,7 +11,6 @@ CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE, label VARCHAR); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0, 'Sir Jon Smith', 0); CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0, apartment_number VARCHAR, floor VARCHAR, apartment_number_status INTEGER DEFAULT 0, floor_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR);
diff --git a/components/test/data/web_database/version_95.sql b/components/test/data/web_database/version_95.sql index 73c8bcc..65b0cc6 100644 --- a/components/test/data/web_database/version_95.sql +++ b/components/test/data/web_database/version_95.sql
@@ -2,7 +2,7 @@ BEGIN TRANSACTION; CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); INSERT INTO meta VALUES('mmap_status','-1'); -INSERT INTO meta VALUES('version','93'); +INSERT INTO meta VALUES('version','95'); INSERT INTO meta VALUES('last_compatible_version','83'); INSERT INTO meta VALUES('Builtin Keyword Version','117'); CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); @@ -11,12 +11,11 @@ CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE, label VARCHAR); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0, 'Sir Jon Smith', 0); CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0, apartment_number VARCHAR, floor VARCHAR, apartment_number_status INTEGER DEFAULT 0, floor_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0); +CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR);
diff --git a/components/test/data/web_database/version_96.sql b/components/test/data/web_database/version_96.sql index 73c8bcc..530a1ff1 100644 --- a/components/test/data/web_database/version_96.sql +++ b/components/test/data/web_database/version_96.sql
@@ -2,21 +2,20 @@ BEGIN TRANSACTION; CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); INSERT INTO meta VALUES('mmap_status','-1'); -INSERT INTO meta VALUES('version','93'); +INSERT INTO meta VALUES('version','96'); INSERT INTO meta VALUES('last_compatible_version','83'); INSERT INTO meta VALUES('Builtin Keyword Version','117'); CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB); CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR,last_visited INTEGER DEFAULT 0, created_from_play_api INTEGER DEFAULT 0); CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value)); CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); -CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE, label VARCHAR); +CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE, label VARCHAR, disallow_settings_visible_updates INTEGER NOT NULL DEFAULT 0); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0, 'Sir Jon Smith', 0); CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0, apartment_number VARCHAR, floor VARCHAR, apartment_number_status INTEGER DEFAULT 0, floor_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR); CREATE TABLE autofill_profiles_trash ( guid VARCHAR); -CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0); +CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, bank_name VARCHAR, nickname VARCHAR, card_issuer INTEGER DEFAULT 0, instrument_id INTEGER DEFAULT 0, virtual_card_enrollment_state INTEGER DEFAULT 0, card_art_url VARCHAR); CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR,unmask_date INTEGER NOT NULL DEFAULT 0); CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR); CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR, recipient_name VARCHAR, phone_number VARCHAR);
diff --git a/components/test/data/web_database/version_97.sql b/components/test/data/web_database/version_97.sql index a23bbcd4..7d54675 100644 --- a/components/test/data/web_database/version_97.sql +++ b/components/test/data/web_database/version_97.sql
@@ -11,7 +11,6 @@ CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id VARCHAR, nickname VARCHAR); CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0, is_client_validity_states_updated BOOL NOT NULL DEFAULT FALSE, label VARCHAR, disallow_settings_visible_updates INTEGER NOT NULL DEFAULT 0); CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR, honorific_prefix VARCHAR, first_last_name VARCHAR, conjunction_last_name VARCHAR, second_last_name VARCHAR, honorific_prefix_status INTEGER DEFAULT 0, first_name_status INTEGER DEFAULT 0, middle_name_status INTEGER DEFAULT 0, last_name_status INTEGER DEFAULT 0, first_last_name_status INTEGER DEFAULT 0, conjunction_last_name_status INTEGER DEFAULT 0, second_last_name_status INTEGER DEFAULT 0, full_name_status INTEGER DEFAULT 0, full_name_with_honorific_prefix VARCHAR, full_name_with_honorific_prefix_status INTEGER DEFAULT 0); -INSERT INTO "autofill_profile_names" VALUES('B41FE6E0-B13E-2A2A-BF0B-29FCE2C3ADBD','Jon','','Smith', 'Jon Smith', 'Sir', 'Smith', 'Notsmith', 'Moresmith', 0, 0, 0, 0, 0, 0, 0, 0, 'Sir Jon Smith', 0); CREATE TABLE autofill_profile_addresses ( guid VARCHAR, street_address VARCHAR, street_name VARCHAR, dependent_street_name VARCHAR, house_number VARCHAR, subpremise VARCHAR, premise_name VARCHAR, street_address_status INTEGER DEFAULT 0, street_name_status INTEGER DEFAULT 0, dependent_street_name_status INTEGER DEFAULT 0, house_number_status INTEGER DEFAULT 0, subpremise_status INTEGER DEFAULT 0, premise_name_status INTEGER DEFAULT 0, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zip_code VARCHAR, sorting_code VARCHAR, country_code VARCHAR, dependent_locality_status INTEGER DEFAULT 0, city_status INTEGER DEFAULT 0, state_status INTEGER DEFAULT 0, zip_code_status INTEGER DEFAULT 0, sorting_code_status INTEGER DEFAULT 0, country_code_status INTEGER DEFAULT 0, apartment_number VARCHAR, floor VARCHAR, apartment_number_status INTEGER DEFAULT 0, floor_status INTEGER DEFAULT 0); CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR); CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR);
diff --git a/components/update_client/BUILD.gn b/components/update_client/BUILD.gn index 2530b02..a9bf728 100644 --- a/components/update_client/BUILD.gn +++ b/components/update_client/BUILD.gn
@@ -253,6 +253,10 @@ "//components/test/data/update_client/ihfokbkgjpifnbbojhneepfflplebdkc_1to2.puff", "//components/test/data/update_client/ihfokbkgjpifnbbojhneepfflplebdkc_2.crx", "//components/test/data/update_client/jebgalgnebhfojomionfpkfelancnnkf.crx", + "//components/test/data/update_client/puffin_patch_test/puffin_app_v1.crx3", + "//components/test/data/update_client/puffin_patch_test/puffin_app_v1_to_v2.puff", + "//components/test/data/update_client/puffin_patch_test/puffin_app_v2.crx3", + "//components/test/data/update_client/puffin_patch_test/puffin_app_v2_to_v1.puff", "//components/test/data/update_client/runaction_test_win.crx3", "//components/test/data/update_client/updatecheck_reply_1.json", "//components/test/data/update_client/updatecheck_reply_4.json",
diff --git a/components/update_client/buildflags.gni b/components/update_client/buildflags.gni index d8a96f09..7287963 100644 --- a/components/update_client/buildflags.gni +++ b/components/update_client/buildflags.gni
@@ -5,5 +5,7 @@ declare_args() { # Whether to enable the Puffin PuffPatch feature which is currently still # in development. + # TODO(crbug.com/1349060) once Puffin patches are fully implemented, + # we should remove this flag. enable_puffin_patches = false }
diff --git a/components/update_client/component.cc b/components/update_client/component.cc index d5d7829a..834f979 100644 --- a/components/update_client/component.cc +++ b/components/update_client/component.cc
@@ -985,6 +985,9 @@ bool Component::StateCanUpdate::CanTryDiffUpdate() const { const auto& component = Component::State::component(); return HasDiffUpdate(component) && !component.diff_error_code_ && +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) + component.update_context_->crx_cache_.has_value() && +#endif component.update_context_->config->EnabledDeltas(); }
diff --git a/components/update_client/crx_cache_unittest.cc b/components/update_client/crx_cache_unittest.cc index 076069d..c74b93d3 100644 --- a/components/update_client/crx_cache_unittest.cc +++ b/components/update_client/crx_cache_unittest.cc
@@ -33,19 +33,6 @@ .AppendASCII(base::JoinString({id, fp}, "_")); } -base::FilePath DuplicateTestFile(const char* file) { - base::FilePath dest_path; - base::PathService::Get(base::DIR_GEN_TEST_DATA_ROOT, &dest_path); - dest_path = dest_path.AppendASCII("test_dir") - .AppendASCII("test") - .AddExtensionASCII("crx3"); - if (!base::PathExists(dest_path.DirName())) { - base::CreateDirectory(dest_path.DirName()); - } - EXPECT_TRUE(base::CopyFile(GetTestFilePath(file), dest_path)); - return dest_path; -} - } // namespace class CrxCacheTest : public testing::Test { @@ -125,7 +112,9 @@ CrxCache::Options options(expected_crx_path.DirName()); scoped_refptr<CrxCache> cache = base::MakeRefCounted<CrxCache>(options); cache->Put( - DuplicateTestFile("jebgalgnebhfojomionfpkfelancnnkf.crx"), id, fp, + DuplicateTestFile(temp_dir.GetPath(), + "jebgalgnebhfojomionfpkfelancnnkf.crx"), + id, fp, base::BindLambdaForTesting([&loop](const CrxCache::Result& result) { EXPECT_EQ(result.error, UnpackerError::kNone); base::FilePath crx_cache_path = result.crx_cache_path; @@ -147,7 +136,9 @@ CrxCache::Options options(expected_crx_path.DirName()); scoped_refptr<CrxCache> cache = base::MakeRefCounted<CrxCache>(options); cache->Put( - DuplicateTestFile("jebgalgnebhfojomionfpkfelancnnkf.crx"), id, fp, + DuplicateTestFile(temp_dir.GetPath(), + "jebgalgnebhfojomionfpkfelancnnkf.crx"), + id, fp, base::BindLambdaForTesting([&loop](const CrxCache::Result& result) { EXPECT_EQ(result.error, UnpackerError::kNone); base::FilePath crx_cache_path = result.crx_cache_path; @@ -165,8 +156,8 @@ ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); base::FilePath expected_crx_path = BuildCrxFilePathForTest(temp_dir.GetPath(), id, fp); - base::FilePath jebg_duplicate_path = - DuplicateTestFile("jebgalgnebhfojomionfpkfelancnnkf.crx"); + base::FilePath jebg_duplicate_path = DuplicateTestFile( + temp_dir.GetPath(), "jebgalgnebhfojomionfpkfelancnnkf.crx"); { base::RunLoop loop; // Put jebg successfully. @@ -177,13 +168,15 @@ base::BindLambdaForTesting([&loop](const CrxCache::Result& result) { EXPECT_EQ(result.error, UnpackerError::kNone); EXPECT_TRUE(base::ContentsEqual( - DuplicateTestFile("jebgalgnebhfojomionfpkfelancnnkf.crx"), + GetTestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), result.crx_cache_path)); EXPECT_TRUE(base::DeleteFile(result.crx_cache_path)); + // Corrupt the file for the next test, so we can verify it was + // actually replaced. std::string corrupted_data("c0rrupt3d d4t4"); EXPECT_TRUE(base::WriteFile(result.crx_cache_path, corrupted_data)); EXPECT_FALSE(base::ContentsEqual( - DuplicateTestFile("jebgalgnebhfojomionfpkfelancnnkf.crx"), + GetTestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), result.crx_cache_path)); loop.Quit(); })); @@ -195,13 +188,17 @@ // Put replaces existing jebg to avoid error path. CrxCache::Options options(expected_crx_path.DirName()); scoped_refptr<CrxCache> cache = base::MakeRefCounted<CrxCache>(options); + // Duplicate the input file (again) since the old file was moved to the + // cache. cache->Put( - jebg_duplicate_path, id, fp, + DuplicateTestFile(temp_dir.GetPath(), + "jebgalgnebhfojomionfpkfelancnnkf.crx"), + id, fp, base::BindLambdaForTesting([&loop](const CrxCache::Result& result) { EXPECT_EQ(result.error, UnpackerError::kNone); EXPECT_TRUE(base::PathExists(result.crx_cache_path)); EXPECT_TRUE(base::ContentsEqual( - DuplicateTestFile("jebgalgnebhfojomionfpkfelancnnkf.crx"), + GetTestFilePath("jebgalgnebhfojomionfpkfelancnnkf.crx"), result.crx_cache_path)); loop.Quit(); }));
diff --git a/components/update_client/puffin_patcher_unittest.cc b/components/update_client/puffin_patcher_unittest.cc index 5380bfea..ace200b0e 100644 --- a/components/update_client/puffin_patcher_unittest.cc +++ b/components/update_client/puffin_patcher_unittest.cc
@@ -18,6 +18,7 @@ #include "components/services/patch/in_process_file_patcher.h" #include "components/update_client/patch/patch_impl.h" #include "components/update_client/test_installer.h" +#include "components/update_client/test_utils.h" #include "components/update_client/update_client_errors.h" #include "courgette/courgette.h" #include "courgette/third_party/bsdiff/bsdiff.h" @@ -25,16 +26,6 @@ namespace update_client { -namespace { - -base::FilePath OutTestFile(const char* file) { - base::FilePath path; - base::PathService::Get(base::DIR_GEN_TEST_DATA_ROOT, &path); - return path.AppendASCII(file); -} - -} // namespace - class PuffinPatcherTest : public testing::Test { public: PuffinPatcherTest() = default; @@ -50,18 +41,21 @@ base::MakeRefCounted<PatchChromiumFactory>( base::BindRepeating(&patch::LaunchInProcessFilePatcher)) ->Create(); - - base::FilePath out_file = OutTestFile("puffin_app_v1_to_v2.crx3"); - EXPECT_TRUE(base::DeleteFile(out_file)); + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + base::FilePath v1_to_v2_out_file = + temp_dir.GetPath().AppendASCII("puffin_app_v1_to_v2.crx3"); SEQUENCE_CHECKER(sequence_checker); { - base::File input_file(OutTestFile("puffin_app_v1.crx3"), - base::File::FLAG_OPEN | base::File::FLAG_READ); - base::File patch_file(OutTestFile("puffin_app_v1_to_v2.puff"), - base::File::FLAG_OPEN | base::File::FLAG_READ); - base::File output_file(out_file, base::File::FLAG_CREATE | - base::File::FLAG_WRITE | - base::File::FLAG_WIN_EXCLUSIVE_WRITE); + base::File input_file( + GetTestFilePath("puffin_patch_test/puffin_app_v1.crx3"), + base::File::FLAG_OPEN | base::File::FLAG_READ); + base::File patch_file( + GetTestFilePath("puffin_patch_test/puffin_app_v1_to_v2.puff"), + base::File::FLAG_OPEN | base::File::FLAG_READ); + base::File output_file(v1_to_v2_out_file, + base::File::FLAG_CREATE | base::File::FLAG_WRITE | + base::File::FLAG_WIN_EXCLUSIVE_WRITE); base::RunLoop loop; PuffinPatcher::Patch( std::move(input_file), std::move(patch_file), std::move(output_file), @@ -75,18 +69,22 @@ loop.Run(); } - EXPECT_TRUE(base::ContentsEqual(OutTestFile("puffin_app_v2.crx3"), out_file)); + EXPECT_TRUE(base::ContentsEqual( + GetTestFilePath("puffin_patch_test/puffin_app_v2.crx3"), + v1_to_v2_out_file)); - out_file = OutTestFile("puffin_app_v2_to_v1.crx3"); - EXPECT_TRUE(base::DeleteFile(out_file)); + base::FilePath v2_to_v1_out_file = + temp_dir.GetPath().AppendASCII("puffin_app_v2_to_v1.crx3"); { - base::File input_file(OutTestFile("puffin_app_v2.crx3"), - base::File::FLAG_OPEN | base::File::FLAG_READ); - base::File patch_file(OutTestFile("puffin_app_v2_to_v1.puff"), - base::File::FLAG_OPEN | base::File::FLAG_READ); - base::File output_file(out_file, base::File::FLAG_CREATE | - base::File::FLAG_WRITE | - base::File::FLAG_WIN_EXCLUSIVE_WRITE); + base::File input_file( + GetTestFilePath("puffin_patch_test/puffin_app_v2.crx3"), + base::File::FLAG_OPEN | base::File::FLAG_READ); + base::File patch_file( + GetTestFilePath("puffin_patch_test/puffin_app_v2_to_v1.puff"), + base::File::FLAG_OPEN | base::File::FLAG_READ); + base::File output_file(v2_to_v1_out_file, + base::File::FLAG_CREATE | base::File::FLAG_WRITE | + base::File::FLAG_WIN_EXCLUSIVE_WRITE); base::RunLoop loop; PuffinPatcher::Patch( std::move(input_file), std::move(patch_file), std::move(output_file), @@ -101,7 +99,10 @@ } DETACH_FROM_SEQUENCE(sequence_checker); - EXPECT_TRUE(base::ContentsEqual(OutTestFile("puffin_app_v1.crx3"), out_file)); + EXPECT_TRUE(base::ContentsEqual( + GetTestFilePath("puffin_patch_test/puffin_app_v1.crx3"), + v2_to_v1_out_file)); + EXPECT_TRUE(base::DeletePathRecursively(temp_dir.GetPath())); } } // namespace update_client
diff --git a/components/update_client/test_utils.cc b/components/update_client/test_utils.cc index e6b6f64..37b171c57 100644 --- a/components/update_client/test_utils.cc +++ b/components/update_client/test_utils.cc
@@ -6,7 +6,9 @@ #include "base/base_paths.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/path_service.h" +#include "testing/gtest/include/gtest/gtest.h" namespace update_client { @@ -20,4 +22,13 @@ .AppendASCII(file_name); } +base::FilePath DuplicateTestFile(const base::FilePath& temp_path, + const char* file) { + base::FilePath dest_path = temp_path.AppendASCII(file); + EXPECT_TRUE(base::CreateDirectory(dest_path.DirName())); + EXPECT_TRUE(base::PathExists(GetTestFilePath(file))); + EXPECT_TRUE(base::CopyFile(GetTestFilePath(file), dest_path)); + return dest_path; +} + } // namespace update_client
diff --git a/components/update_client/test_utils.h b/components/update_client/test_utils.h index 12f5e4a..b7ae46e1 100644 --- a/components/update_client/test_utils.h +++ b/components/update_client/test_utils.h
@@ -17,6 +17,12 @@ // the file in that directory. [[nodiscard]] base::FilePath GetTestFilePath(const char* file_name); +// Duplicates a file from path GetTestFilePath(file) into the provided +// temp_path. This should be provided by a base::ScopedTempDir. Deletion +// should be handled by the caller. +[[nodiscard]] base::FilePath DuplicateTestFile(const base::FilePath& temp_path, + const char* file); + } // namespace update_client #endif // COMPONENTS_UPDATE_CLIENT_TEST_UTILS_H_
diff --git a/components/user_education/common/feature_promo_snooze_service.h b/components/user_education/common/feature_promo_snooze_service.h index f4339054..160f03b 100644 --- a/components/user_education/common/feature_promo_snooze_service.h +++ b/components/user_education/common/feature_promo_snooze_service.h
@@ -36,9 +36,9 @@ // Snooze counts that are equal or larger than this value will be conflated. static constexpr int kUmaMaxSnoozeCount = 10; - // The snooze duration defaults to 1 day plus 2 additional hours in hope to - // stagger busy hours in the days. - static constexpr base::TimeDelta kDefaultSnoozeDuration = base::Hours(26); + // The snooze duration defaults to 7 days. This was determined by + // thoroughly testing for a helpful, yet non-intrusive time span. + static constexpr base::TimeDelta kDefaultSnoozeDuration = base::Hours(168); FeaturePromoSnoozeService(); virtual ~FeaturePromoSnoozeService();
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc index c64f87ed..416df84 100644 --- a/components/viz/common/features.cc +++ b/components/viz/common/features.cc
@@ -262,6 +262,17 @@ BASE_FEATURE(kSharedBitmapToSharedImage, "SharedBitmapToSharedImage", base::FEATURE_DISABLED_BY_DEFAULT); +// Used to enable the HintSession::Mode::BOOST mode. BOOST mode try to force +// the ADPF(Android Dynamic Performance Framework) to give Chrome more CPU +// resources during a scroll. +BASE_FEATURE(kEnableADPFScrollBoost, + "EnableADPFScrollBoost", + base::FEATURE_DISABLED_BY_DEFAULT); + +// Specifies how long after the boost mode is set, it will expire. +const base::FeatureParam<base::TimeDelta> kADPFBoostTimeout{ + &kEnableADPFScrollBoost, "adpf_boost_mode_timeout", + base::Milliseconds(200)}; bool IsDelegatedCompositingEnabled() { return base::FeatureList::IsEnabled(kDelegatedCompositing);
diff --git a/components/viz/common/features.h b/components/viz/common/features.h index 1f66005..663ae73 100644 --- a/components/viz/common/features.h +++ b/components/viz/common/features.h
@@ -67,6 +67,9 @@ VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kOnBeginFrameAcks); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kOnBeginFrameAllowLateAcks); VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kSharedBitmapToSharedImage); +VIZ_COMMON_EXPORT BASE_DECLARE_FEATURE(kEnableADPFScrollBoost); +VIZ_COMMON_EXPORT extern const base::FeatureParam<base::TimeDelta> + kADPFBoostTimeout; VIZ_COMMON_EXPORT extern const char kDraw1Point12Ms[]; VIZ_COMMON_EXPORT extern const char kDraw2Points6Ms[];
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn index f2fe76f..8e944b5 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn
@@ -57,6 +57,8 @@ "display/display_scheduler.h", "display/display_scheduler_base.cc", "display/display_scheduler_base.h", + "display/display_utils.cc", + "display/display_utils.h", "display/draw_polygon.cc", "display/draw_polygon.h", "display/external_use_client.cc", @@ -193,6 +195,8 @@ "hit_test/hit_test_manager.h", "layers/layer_context_impl.cc", "layers/layer_context_impl.h", + "performance_hint/boost_manager.cc", + "performance_hint/boost_manager.h", "performance_hint/hint_session.cc", "performance_hint/hint_session.h", "performance_hint/utils.cc", @@ -484,6 +488,7 @@ "display/display_resource_provider_software_unittest.cc", "display/display_scheduler_unittest.cc", "display/display_unittest.cc", + "display/display_utils_unittest.cc", "display/draw_polygon_unittest.cc", "display/frame_rate_decider_unittest.cc", "display/overlay_candidate_factory_unittest.cc", @@ -514,6 +519,7 @@ "gl/gpu_service_impl_unittest.cc", "hit_test/hit_test_aggregator_unittest.cc", "main/viz_main_impl_unittest.cc", + "performance_hint/boost_manager_unittest.cc", "surfaces/referenced_surface_tracker_unittest.cc", "surfaces/surface_unittest.cc", "transitions/transferable_resource_tracker_unittest.cc",
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index 53caa88..9807a08 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -44,6 +44,7 @@ #include "components/viz/service/display/display_resource_provider_skia.h" #include "components/viz/service/display/display_resource_provider_software.h" #include "components/viz/service/display/display_scheduler.h" +#include "components/viz/service/display/display_utils.h" #include "components/viz/service/display/null_renderer.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/renderer_utils.h" @@ -276,10 +277,12 @@ void Display::PresentationGroupTiming::OnDraw( base::TimeTicks frame_time, base::TimeTicks draw_start_timestamp, - base::flat_set<base::PlatformThreadId> thread_ids) { + base::flat_set<base::PlatformThreadId> thread_ids, + HintSession::BoostType boost_type) { frame_time_ = frame_time; draw_start_timestamp_ = draw_start_timestamp; thread_ids_ = std::move(thread_ids); + boost_type_ = boost_type; } void Display::PresentationGroupTiming::OnSwap(gfx::SwapTimings timings, @@ -297,7 +300,8 @@ } // Can be nullptr in unittests. if (scheduler) { - scheduler->ReportFrameTime(frame_latency, std::move(thread_ids_)); + scheduler->ReportFrameTime(frame_latency, std::move(thread_ids_), + draw_start_timestamp_, boost_type_); } } @@ -918,8 +922,13 @@ thread_ids.insert(surface_thread_ids.begin(), surface_thread_ids.end()); } } + + HintSession::BoostType boost_type = HintSession::BoostType::kDefault; + if (IsScroll(frame.latency_info)) { + boost_type = HintSession::BoostType::kScrollBoost; + } presentation_group_timing.OnDraw(params.frame_time, draw_timer->Begin(), - std::move(thread_ids)); + std::move(thread_ids), boost_type); for (const auto& surface_id : aggregator_->previous_contained_surfaces()) { surface = surface_manager_->GetSurfaceForId(surface_id);
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h index 0e421d5e..32b7ec9a 100644 --- a/components/viz/service/display/display.h +++ b/components/viz/service/display/display.h
@@ -232,7 +232,8 @@ std::unique_ptr<Surface::PresentationHelper> helper); void OnDraw(base::TimeTicks frame_time, base::TimeTicks draw_start_timestamp, - base::flat_set<base::PlatformThreadId> thread_ids); + base::flat_set<base::PlatformThreadId> thread_ids, + HintSession::BoostType boost_type); void OnSwap(gfx::SwapTimings timings, DisplaySchedulerBase* scheduler); bool HasSwapped() const { return !swap_timings_.is_null(); } void OnPresent(const gfx::PresentationFeedback& feedback); @@ -248,6 +249,7 @@ gfx::SwapTimings swap_timings_; std::vector<std::unique_ptr<Surface::PresentationHelper>> presentation_helpers_; + HintSession::BoostType boost_type_; }; // TODO(cblume, crbug.com/900973): |enable_shared_images| is a temporary
diff --git a/components/viz/service/display/display_scheduler.cc b/components/viz/service/display/display_scheduler.cc index 97edb30..179ec2b 100644 --- a/components/viz/service/display/display_scheduler.cc +++ b/components/viz/service/display/display_scheduler.cc
@@ -183,13 +183,15 @@ void DisplayScheduler::ReportFrameTime( base::TimeDelta frame_time, - base::flat_set<base::PlatformThreadId> thread_ids) { + base::flat_set<base::PlatformThreadId> thread_ids, + base::TimeTicks draw_start, + HintSession::BoostType boost_type) { MaybeCreateHintSession(std::move(thread_ids)); if (hint_session_) { UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES("Compositing.Display.AdpfHintUs", frame_time, base::Microseconds(1), base::Milliseconds(50), 50); - hint_session_->ReportCpuCompletionTime(frame_time); + hint_session_->ReportCpuCompletionTime(frame_time, draw_start, boost_type); } }
diff --git a/components/viz/service/display/display_scheduler.h b/components/viz/service/display/display_scheduler.h index b6e9533..da99cda 100644 --- a/components/viz/service/display/display_scheduler.h +++ b/components/viz/service/display/display_scheduler.h
@@ -50,9 +50,10 @@ void DidSwapBuffers() override; void DidReceiveSwapBuffersAck() override; void OutputSurfaceLost() override; - void ReportFrameTime( - base::TimeDelta frame_time, - base::flat_set<base::PlatformThreadId> thread_ids) override; + void ReportFrameTime(base::TimeDelta frame_time, + base::flat_set<base::PlatformThreadId> thread_ids, + base::TimeTicks draw_start, + HintSession::BoostType boost_type) override; // DisplayDamageTrackerObserver implementation. void OnDisplayDamaged(SurfaceId surface_id) override;
diff --git a/components/viz/service/display/display_scheduler_base.h b/components/viz/service/display/display_scheduler_base.h index a84749c..0218afc 100644 --- a/components/viz/service/display/display_scheduler_base.h +++ b/components/viz/service/display/display_scheduler_base.h
@@ -10,6 +10,7 @@ #include "base/threading/platform_thread.h" #include "base/time/time.h" #include "components/viz/service/display/display_damage_tracker.h" +#include "components/viz/service/performance_hint/hint_session.h" #include "components/viz/service/viz_service_export.h" #include "third_party/abseil-cpp/absl/types/optional.h" @@ -57,9 +58,13 @@ virtual void DidSwapBuffers() = 0; virtual void DidReceiveSwapBuffersAck() = 0; virtual void OutputSurfaceLost() = 0; + // ReportFrameTime can use ADPF hints. If ADPF hints are used they will be run + // with the |boost_type| boost type. virtual void ReportFrameTime( base::TimeDelta frame_time, - base::flat_set<base::PlatformThreadId> thread_ids) = 0; + base::flat_set<base::PlatformThreadId> thread_ids, + base::TimeTicks draw_start, + HintSession::BoostType boost_type) = 0; protected: raw_ptr<DisplaySchedulerClient> client_ = nullptr;
diff --git a/components/viz/service/display/display_utils.cc b/components/viz/service/display/display_utils.cc new file mode 100644 index 0000000..f509a634 --- /dev/null +++ b/components/viz/service/display/display_utils.cc
@@ -0,0 +1,33 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display/display_utils.h" + +#include <vector> + +namespace viz { + +bool IsScroll(const std::vector<ui::LatencyInfo>& latency_infos) { + for (const ui::LatencyInfo& latency_info : latency_infos) { + base::TimeTicks scroll_ts; + latency_info.FindLatency( + ui::LatencyComponentType:: + INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, + &scroll_ts); + if (!scroll_ts.is_null()) { + return true; + } + + latency_info.FindLatency( + ui::LatencyComponentType:: + INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT, + &scroll_ts); + if (!scroll_ts.is_null()) { + return true; + } + } + return false; +} + +} // namespace viz
diff --git a/components/viz/service/display/display_utils.h b/components/viz/service/display/display_utils.h new file mode 100644 index 0000000..2b58ad7 --- /dev/null +++ b/components/viz/service/display/display_utils.h
@@ -0,0 +1,20 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_UTILS_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_UTILS_H_ + +#include <vector> + +#include "components/viz/service/viz_service_export.h" +#include "ui/latency/latency_info.h" + +namespace viz { + +VIZ_SERVICE_EXPORT bool IsScroll( + const std::vector<ui::LatencyInfo>& latency_infos); + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_UTILS_H_
diff --git a/components/viz/service/display/display_utils_unittest.cc b/components/viz/service/display/display_utils_unittest.cc new file mode 100644 index 0000000..a6bf47e --- /dev/null +++ b/components/viz/service/display/display_utils_unittest.cc
@@ -0,0 +1,47 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display/display_utils.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace viz { + +TEST(DisplayUtilsTest, IsScrollOneElement) { + ui::LatencyInfo latency_info; + EXPECT_FALSE(IsScroll({latency_info})); + + ui::LatencyInfo latency_info_scroll_update; + latency_info_scroll_update.AddLatencyNumber( + ui::LatencyComponentType:: + INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT); + EXPECT_TRUE(IsScroll({latency_info_scroll_update})); + + ui::LatencyInfo latency_info_first_scroll; + latency_info_first_scroll.AddLatencyNumber( + ui::LatencyComponentType:: + INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT); + EXPECT_TRUE(IsScroll({latency_info_first_scroll})); +} + +TEST(DisplayUtilsTest, IsScroll) { + ui::LatencyInfo latency_info; + + ui::LatencyInfo latency_info_scroll_update; + latency_info_scroll_update.AddLatencyNumber( + ui::LatencyComponentType:: + INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT); + + ui::LatencyInfo latency_info_first_scroll; + latency_info_first_scroll.AddLatencyNumber( + ui::LatencyComponentType:: + INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT); + + EXPECT_TRUE(IsScroll( + {latency_info, latency_info_scroll_update, latency_info_first_scroll})); + EXPECT_TRUE(IsScroll({latency_info, latency_info_first_scroll})); + EXPECT_TRUE(IsScroll({latency_info, latency_info_scroll_update})); +} + +} // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_device_dcomp.cc b/components/viz/service/display_embedder/skia_output_device_dcomp.cc index 7ff17fe17..944533a 100644 --- a/components/viz/service/display_embedder/skia_output_device_dcomp.cc +++ b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
@@ -79,9 +79,11 @@ } absl::optional<gl::DCLayerOverlayImage> BeginOverlayAccess() { - DCHECK(representation_); - access_ = representation_->BeginScopedReadAccess(); - DCHECK(access_); + CHECK(representation_); + if (!access_) { + access_ = representation_->BeginScopedReadAccess(); + CHECK(access_); + } return access_->GetDCLayerOverlayImage(); }
diff --git a/components/viz/service/performance_hint/boost_manager.cc b/components/viz/service/performance_hint/boost_manager.cc new file mode 100644 index 0000000..b6d288e --- /dev/null +++ b/components/viz/service/performance_hint/boost_manager.cc
@@ -0,0 +1,56 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/performance_hint/boost_manager.h" + +namespace viz { +namespace { +using BoostType = HintSession::BoostType; +} + +base::TimeDelta BoostManager::GetFrameDurationAndMaybeUpdateBoostType( + base::TimeDelta target_duration, + base::TimeDelta actual_duration, + base::TimeTicks draw_start, + BoostType preferable_boost_type) { + if (!base::FeatureList::IsEnabled(features::kEnableADPFScrollBoost)) { + switch (preferable_boost_type) { + case BoostType::kDefault: + case BoostType::kScrollBoost: + return actual_duration; + case BoostType::kWakeUpBoost: + return target_duration * 1.5; + } + NOTREACHED(); + } + + MaybeUpdateBoostType(draw_start, preferable_boost_type); + switch (boost_type_) { + case BoostType::kDefault: + return actual_duration; + case BoostType::kScrollBoost: + return target_duration * 3; + case BoostType::kWakeUpBoost: + return target_duration * 1.5; + } +} + +void BoostManager::MaybeUpdateBoostType(base::TimeTicks draw_start, + BoostType boost_type) { + switch (boost_type) { + case BoostType::kDefault: + if (draw_start > boost_end_time_) { + boost_type_ = BoostType::kDefault; + } + return; + case BoostType::kScrollBoost: + case BoostType::kWakeUpBoost: + boost_end_time_ = draw_start + features::kADPFBoostTimeout.Get(); + boost_type_ = boost_type; + return; + } + NOTREACHED(); +} + +} // namespace viz
diff --git a/components/viz/service/performance_hint/boost_manager.h b/components/viz/service/performance_hint/boost_manager.h new file mode 100644 index 0000000..d6a6e5d5 --- /dev/null +++ b/components/viz/service/performance_hint/boost_manager.h
@@ -0,0 +1,56 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_PERFORMANCE_HINT_BOOST_MANAGER_H_ +#define COMPONENTS_VIZ_SERVICE_PERFORMANCE_HINT_BOOST_MANAGER_H_ + +#include "base/metrics/field_trial_params.h" +#include "components/viz/common/features.h" +#include "components/viz/service/performance_hint/hint_session.h" + +namespace viz { + +class VIZ_SERVICE_EXPORT BoostManager { + public: + // Recalculate an actual frame duration based on the current boost type. This + // is useful to speculate with the behavior of ADPF. + // + // This function consists of two steps: + // + // 1) Maybe update a boost type based on |preferable_boost_type| (read the + // description of the |MaybeUpdateBoostType| function). + // + // 2) Recalculate an actual frame duration based on the reasulted boost type + // from the previous step. + // - If the boost type = kDefault, it returns the |actual_duration| + // without any changes. + // - If the boost type = kScrollBoost or kWakeUpBoost, it returns a + // fictitious duration that is greater than |target_duration|, to emulate the + // behavior where a frame was missed. + base::TimeDelta GetFrameDurationAndMaybeUpdateBoostType( + base::TimeDelta target_duration, + base::TimeDelta actual_duration, + base::TimeTicks draw_start, + HintSession::BoostType preferable_boost_type); + + protected: + HintSession::BoostType GetCurrentBoostTypeForTesting() const { + return boost_type_; + } + + private: + // Updates the boost type: + // - kDefault takes effect after kScrollBoost or kWakeUpBoost expires. They + // expire |features::kADPFBoostModeDuration| after it was set. + // - kScrollBoost or kWakeUpBoost takes effect immediately. + void MaybeUpdateBoostType(base::TimeTicks draw_start, + HintSession::BoostType boost_type); + + base::TimeTicks boost_end_time_ = base::TimeTicks::Min(); + HintSession::BoostType boost_type_ = HintSession::BoostType::kDefault; +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_PERFORMANCE_HINT_BOOST_MANAGER_H_
diff --git a/components/viz/service/performance_hint/boost_manager_unittest.cc b/components/viz/service/performance_hint/boost_manager_unittest.cc new file mode 100644 index 0000000..ee2c967 --- /dev/null +++ b/components/viz/service/performance_hint/boost_manager_unittest.cc
@@ -0,0 +1,136 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/performance_hint/boost_manager.h" + +#include "base/test/scoped_feature_list.h" +#include "base/test/simple_test_tick_clock.h" +#include "components/viz/service/performance_hint/hint_session.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace viz { +namespace { +using BoostType = HintSession::BoostType; + +class BoostManagerTestHelper : public BoostManager { + public: + using BoostManager::GetCurrentBoostTypeForTesting; +}; + +} // namespace + +class BoostManagerTest : public testing::Test { + private: + base::test::ScopedFeatureList scoped_list_; + + protected: + base::SimpleTestTickClock test_tick_clock_; + BoostManagerTestHelper manager_; + + static constexpr base::TimeDelta kTargetFrameDuration = + base::Milliseconds(10); + static constexpr base::TimeDelta kActualFrameDuration = base::Milliseconds(7); + + void InitAndEnableBoostFeature() { + scoped_list_.InitAndEnableFeature(features::kEnableADPFScrollBoost); + } + + void InitAndDisableBoostFeature() { + scoped_list_.InitAndDisableFeature(features::kEnableADPFScrollBoost); + } + + base::TimeDelta GetBoostModeTimeout() const { + return features::kADPFBoostTimeout.Get(); + } + + void ExecuteAndAssert(BoostType provided_boost_type, + base::TimeTicks provided_draw_start, + BoostType expected_boost_type, + base::TimeDelta expected_frame_duration) { + base::TimeDelta frame_duration = + manager_.GetFrameDurationAndMaybeUpdateBoostType( + kTargetFrameDuration, kActualFrameDuration, provided_draw_start, + provided_boost_type); + ASSERT_EQ(frame_duration, expected_frame_duration); + BoostType new_boost_type = manager_.GetCurrentBoostTypeForTesting(); + ASSERT_EQ(new_boost_type, expected_boost_type); + } +}; + +TEST_F(BoostManagerTest, ScrollBoostExperimentEnabled) { + InitAndEnableBoostFeature(); + + base::TimeTicks draw_start = test_tick_clock_.NowTicks(); + + // Use BoostType::kDefault. + ExecuteAndAssert(BoostType::kDefault, draw_start, BoostType::kDefault, + kActualFrameDuration); + + // Use BoostType::kScrollBoost, it takes effect immediately. + ExecuteAndAssert(BoostType::kScrollBoost, draw_start, BoostType::kScrollBoost, + 3 * kTargetFrameDuration); + + // Use BoostType::kDefault, but it doesn't take effect, because the previously + // set BoostType::kScrollBoost has not yet been exhausted. + ExecuteAndAssert(BoostType::kDefault, draw_start, BoostType::kScrollBoost, + 3 * kTargetFrameDuration); + + // Use BoostType::kDefault, after BoostType::kScrollBoost has been exhausted. + test_tick_clock_.Advance(GetBoostModeTimeout() + base::Milliseconds(1)); + draw_start = test_tick_clock_.NowTicks(); + ExecuteAndAssert(BoostType::kDefault, draw_start, BoostType::kDefault, + kActualFrameDuration); +} + +TEST_F(BoostManagerTest, ScrollBoostExperimentDisabled) { + InitAndDisableBoostFeature(); + + base::TimeTicks draw_start = test_tick_clock_.NowTicks(); + + // Use BoostType::kDefault. + ExecuteAndAssert(BoostType::kDefault, draw_start, BoostType::kDefault, + kActualFrameDuration); + + // Use BoostType::kScrollBoost, it doesn't take effect because the experiment + // is disabled. + ExecuteAndAssert(BoostType::kScrollBoost, draw_start, BoostType::kDefault, + kActualFrameDuration); +} + +TEST_F(BoostManagerTest, WakeUpBoostExperimentEnabled) { + InitAndEnableBoostFeature(); + + base::TimeTicks draw_start = test_tick_clock_.NowTicks(); + + // Use BoostType::kWakeUpBoost, it takes effect immediately. + ExecuteAndAssert(BoostType::kWakeUpBoost, draw_start, BoostType::kWakeUpBoost, + 1.5 * kTargetFrameDuration); + + // Use BoostType::kDefault, but it doesn't take effect, because the previously + // set BoostType::kWakeUpBoost has not yet been exhausted. + ExecuteAndAssert(BoostType::kDefault, draw_start, BoostType::kWakeUpBoost, + 1.5 * kTargetFrameDuration); + + // Use BoostType::kDefault, after BoostType::kWakeUpBoost has been exhausted. + test_tick_clock_.Advance(GetBoostModeTimeout() + base::Milliseconds(1)); + draw_start = test_tick_clock_.NowTicks(); + ExecuteAndAssert(BoostType::kDefault, draw_start, BoostType::kDefault, + kActualFrameDuration); +} + +TEST_F(BoostManagerTest, WakeUpBoostExperimentDisabled) { + InitAndDisableBoostFeature(); + + base::TimeTicks draw_start = test_tick_clock_.NowTicks(); + + // Use BoostType::kWakeUpBoost, it only increase actual duration(the same + // behaviour as before introducing this experiment) because the experiment is + // disabled. + ExecuteAndAssert(BoostType::kWakeUpBoost, draw_start, BoostType::kDefault, + 1.5 * kTargetFrameDuration); + ExecuteAndAssert(BoostType::kDefault, draw_start, BoostType::kDefault, + kActualFrameDuration); +} + +} // namespace viz
diff --git a/components/viz/service/performance_hint/hint_session.cc b/components/viz/service/performance_hint/hint_session.cc index 9d95322..dbc2cb11 100644 --- a/components/viz/service/performance_hint/hint_session.cc +++ b/components/viz/service/performance_hint/hint_session.cc
@@ -23,6 +23,7 @@ #include "base/threading/thread_checker.h" #include "base/trace_event/trace_event.h" #include "components/viz/common/switches.h" +#include "components/viz/service/performance_hint/boost_manager.h" static_assert(sizeof(base::PlatformThreadId) == sizeof(int32_t), "thread id types incompatible"); @@ -104,7 +105,9 @@ ~AdpfHintSession() override; void UpdateTargetDuration(base::TimeDelta target_duration) override; - void ReportCpuCompletionTime(base::TimeDelta actual_duration) override; + void ReportCpuCompletionTime(base::TimeDelta actual_duration, + base::TimeTicks draw_start, + BoostType preferable_boost_type) override; void WakeUp(); @@ -112,6 +115,7 @@ const raw_ptr<APerformanceHintSession> hint_session_; const raw_ptr<HintSessionFactoryImpl> factory_; base::TimeDelta target_duration_; + BoostManager boost_manager_; }; class HintSessionFactoryImpl : public HintSessionFactory { @@ -161,15 +165,23 @@ hint_session_, target_duration.InNanoseconds()); } -void AdpfHintSession::ReportCpuCompletionTime(base::TimeDelta actual_duration) { +void AdpfHintSession::ReportCpuCompletionTime(base::TimeDelta actual_duration, + base::TimeTicks draw_start, + BoostType preferable_boost_type) { DCHECK_CALLED_ON_VALID_THREAD(factory_->thread_checker_); + + base::TimeDelta frame_duration = + boost_manager_.GetFrameDurationAndMaybeUpdateBoostType( + target_duration_, actual_duration, draw_start, preferable_boost_type); + AdpfMethods::Get().APerformanceHint_reportActualWorkDurationFn( - hint_session_, actual_duration.InNanoseconds()); + hint_session_, frame_duration.InNanoseconds()); } void AdpfHintSession::WakeUp() { DCHECK_CALLED_ON_VALID_THREAD(factory_->thread_checker_); - ReportCpuCompletionTime(target_duration_ * 1.5f); + ReportCpuCompletionTime(target_duration_, base::TimeTicks::Now(), + BoostType::kWakeUpBoost); } HintSessionFactoryImpl::HintSessionFactoryImpl(
diff --git a/components/viz/service/performance_hint/hint_session.h b/components/viz/service/performance_hint/hint_session.h index aa29cb2..08c98729 100644 --- a/components/viz/service/performance_hint/hint_session.h +++ b/components/viz/service/performance_hint/hint_session.h
@@ -20,13 +20,23 @@ class VIZ_SERVICE_EXPORT HintSession { public: + enum class BoostType { + kDefault, + kScrollBoost, + kWakeUpBoost, + }; + virtual ~HintSession() = default; virtual void UpdateTargetDuration(base::TimeDelta target_duration) = 0; // `actual_duration` is compared to `target_duration` in `CreateSession` to // determine the performance of a frame. - virtual void ReportCpuCompletionTime(base::TimeDelta actual_duration) = 0; + // 'preferable_boost_type' is a hint which mode to use. There is no guarantee + // that this mode will be used immediately or will be used at all. + virtual void ReportCpuCompletionTime(base::TimeDelta actual_duration, + base::TimeTicks draw_start, + BoostType preferable_boost_type) = 0; }; class VIZ_SERVICE_EXPORT HintSessionFactory {
diff --git a/components/webapps/browser/banners/app_banner_settings_helper.cc b/components/webapps/browser/banners/app_banner_settings_helper.cc index 2c88d66..0b92a20 100644 --- a/components/webapps/browser/banners/app_banner_settings_helper.cc +++ b/components/webapps/browser/banners/app_banner_settings_helper.cc
@@ -23,6 +23,7 @@ #include "components/permissions/permissions_client.h" #include "components/webapps/browser/banners/app_banner_manager.h" #include "components/webapps/browser/banners/app_banner_metrics.h" +#include "components/webapps/browser/features.h" #include "components/webapps/common/switches.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/web_contents.h" @@ -36,14 +37,6 @@ // site may show a banner for. const size_t kMaxAppsPerSite = 3; -// Default number of days that dismissing or ignoring the banner will prevent it -// being seen again for. -const unsigned int kMinimumBannerBlockedToBannerShown = 90; -const unsigned int kMinimumDaysBetweenBannerShows = 14; - -// Default site engagement required to trigger the banner. -const unsigned int kDefaultTotalEngagementToTrigger = 2; - // Dictionary keys to use for the events. Must be kept in sync with // AppBannerEvent. constexpr const char* kBannerEventKeys[] = { @@ -55,17 +48,12 @@ // clang-format on }; -// Keys to use when querying the variations params. -const char kBannerParamsKey[] = "AppBannerTriggering"; -const char kBannerParamsEngagementTotalKey[] = "site_engagement_total"; -const char kBannerParamsDaysAfterBannerDismissedKey[] = "days_after_dismiss"; -const char kBannerParamsDaysAfterBannerIgnoredKey[] = "days_after_ignore"; - // Total engagement score required before a banner will actually be triggered. -double gTotalEngagementToTrigger = kDefaultTotalEngagementToTrigger; +double gTotalEngagementToTrigger = features::kDefaultTotalEngagementToTrigger; -unsigned int gDaysAfterDismissedToShow = kMinimumBannerBlockedToBannerShown; -unsigned int gDaysAfterIgnoredToShow = kMinimumDaysBetweenBannerShows; +unsigned int gDaysAfterDismissedToShow = + features::kMinimumBannerBlockedToBannerShown; +unsigned int gDaysAfterIgnoredToShow = features::kMinimumDaysBetweenBannerShows; base::Value::Dict GetOriginAppBannerData(HostContentSettingsMap* settings, const GURL& origin_url) { @@ -127,36 +115,18 @@ // Queries variations for the number of days which dismissing and ignoring the // banner should prevent a banner from showing. void UpdateDaysBetweenShowing() { - std::string dismiss_param = base::GetFieldTrialParamValue( - kBannerParamsKey, kBannerParamsDaysAfterBannerDismissedKey); - std::string ignore_param = base::GetFieldTrialParamValue( - kBannerParamsKey, kBannerParamsDaysAfterBannerIgnoredKey); - - if (!dismiss_param.empty() && !ignore_param.empty()) { - unsigned int dismiss_days = 0; - unsigned int ignore_days = 0; - - if (base::StringToUint(dismiss_param, &dismiss_days) && - base::StringToUint(ignore_param, &ignore_days)) { - AppBannerSettingsHelper::SetDaysAfterDismissAndIgnoreToTrigger( - dismiss_days, ignore_days); - } - } + AppBannerSettingsHelper::SetDaysAfterDismissAndIgnoreToTrigger( + features::kBannerParamsDaysAfterBannerDismissedKey.Get(), + features::kBannerParamsDaysAfterBannerIgnoredKey.Get()); } // Queries variations for the maximum site engagement score required to trigger // the banner showing. void UpdateSiteEngagementToTrigger() { - std::string total_param = base::GetFieldTrialParamValue( - kBannerParamsKey, kBannerParamsEngagementTotalKey); + double total_engagement = features::kBannerParamsEngagementTotalKey.Get(); - if (!total_param.empty()) { - double total_engagement = -1; - - if (base::StringToDouble(total_param, &total_engagement) && - total_engagement >= 0) { - AppBannerSettingsHelper::SetTotalEngagementToTrigger(total_engagement); - } + if (total_engagement >= 0) { + AppBannerSettingsHelper::SetTotalEngagementToTrigger(total_engagement); } }
diff --git a/components/webapps/browser/features.cc b/components/webapps/browser/features.cc index 54f4f32..e58b84d 100644 --- a/components/webapps/browser/features.cc +++ b/components/webapps/browser/features.cc
@@ -109,5 +109,18 @@ base::FeatureList::IsEnabled(kSkipServiceWorkerForInstallPrompt); } +// Keys to use when querying the variations params. +BASE_FEATURE(kAppBannerTriggering, + "AppBannerTriggering", + base::FEATURE_DISABLED_BY_DEFAULT); +extern const base::FeatureParam<double> kBannerParamsEngagementTotalKey{ + &kAppBannerTriggering, "site_engagement_total", + kDefaultTotalEngagementToTrigger}; +extern const base::FeatureParam<int> kBannerParamsDaysAfterBannerDismissedKey{ + &kAppBannerTriggering, "days_after_dismiss", + kMinimumBannerBlockedToBannerShown}; +extern const base::FeatureParam<int> kBannerParamsDaysAfterBannerIgnoredKey{ + &kAppBannerTriggering, "days_after_ignore", kMinimumDaysBetweenBannerShows}; + } // namespace features } // namespace webapps
diff --git a/components/webapps/browser/features.h b/components/webapps/browser/features.h index d021bc0..364d6d5 100644 --- a/components/webapps/browser/features.h +++ b/components/webapps/browser/features.h
@@ -13,6 +13,14 @@ namespace webapps { namespace features { +// Default number of days that dismissing or ignoring the banner will prevent it +// being seen again for. +constexpr unsigned int kMinimumBannerBlockedToBannerShown = 90; +constexpr unsigned int kMinimumDaysBetweenBannerShows = 14; + +// Default site engagement required to trigger the banner. +constexpr unsigned int kDefaultTotalEngagementToTrigger = 2; + #if BUILDFLAG(IS_ANDROID) BASE_DECLARE_FEATURE(kAddToHomescreenMessaging); BASE_DECLARE_FEATURE(kAmbientBadgeSuppressFirstVisit); @@ -44,6 +52,11 @@ bool SkipInstallServiceWorkerCheck(); bool SkipServiceWorkerForInstallPromotion(); +BASE_DECLARE_FEATURE(kAppBannerTriggering); +extern const base::FeatureParam<double> kBannerParamsEngagementTotalKey; +extern const base::FeatureParam<int> kBannerParamsDaysAfterBannerDismissedKey; +extern const base::FeatureParam<int> kBannerParamsDaysAfterBannerIgnoredKey; + } // namespace features } // namespace webapps
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn index 253e18b..19f349c 100644 --- a/content/app/BUILD.gn +++ b/content/app/BUILD.gn
@@ -148,6 +148,7 @@ "mac_init.mm", ] + configs += [ "//build/config/compiler:enable_arc" ] frameworks = [ "Foundation.framework" ] } }
diff --git a/content/app/mac_init.mm b/content/app/mac_init.mm index 470f190..cfcdf2c 100644 --- a/content/app/mac_init.mm +++ b/content/app/mac_init.mm
@@ -6,10 +6,14 @@ #import <Cocoa/Cocoa.h> +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + namespace content { void InitializeMac() { - [[NSUserDefaults standardUserDefaults] registerDefaults:@{ + [NSUserDefaults.standardUserDefaults registerDefaults:@{ // Exceptions routed to -[NSApplication reportException:] should crash // immediately, as opposed being swallowed or presenting UI that gives the // user a choice in the matter.
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc index 0078ea75..af7f64f 100644 --- a/content/browser/accessibility/accessibility_win_browsertest.cc +++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -50,6 +50,7 @@ #include "content/test/content_browser_test_utils_internal.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "third_party/blink/public/common/features.h" #include "third_party/iaccessible2/ia2_api_all.h" #include "third_party/isimpledom/ISimpleDOMNode.h" #include "ui/accessibility/accessibility_features.h" @@ -4704,14 +4705,26 @@ IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, TestPageIsAccessibleAfterCancellingReload) { - LoadInitialAccessibilityTreeFromHtml( - "data:text/html," - "<script>" - "window.onbeforeunload = function () {" - " return '';" - "};" - "</script>" - "<input value='Test'>"); + if (base::FeatureList::IsEnabled( + blink::features::kBeforeunloadEventCancelByPreventDefault)) { + LoadInitialAccessibilityTreeFromHtml( + "data:text/html," + "<script>" + "window.onbeforeunload = function (e) {" + " e.preventDefault()" + "};" + "</script>" + "<input value='Test'>"); + } else { + LoadInitialAccessibilityTreeFromHtml( + "data:text/html," + "<script>" + "window.onbeforeunload = function () {" + " return 'Not empty string';" + "};" + "</script>" + "<input value='Test'>"); + } // When the before unload dialog shows, simulate the user clicking // cancel on that dialog. @@ -4973,7 +4986,7 @@ EXPECT_NE(nullptr, accessibility_com_win); base::win::ScopedVariant result; - + accessibility_com_win->GetPropertyValue(UIA_IsOffscreenPropertyId, result.Receive());
diff --git a/content/browser/android/battery_metrics.cc b/content/browser/android/battery_metrics.cc index 8de147b..5467353 100644 --- a/content/browser/android/battery_metrics.cc +++ b/content/browser/android/battery_metrics.cc
@@ -33,14 +33,6 @@ "ForegroundRadioStateCountWakeups", base::FEATURE_DISABLED_BY_DEFAULT); -// Keeps reporting of the battery metrics on the UI thread, where it may cause -// jank. This is used for a holdback experiment to estimate the jank reduction -// won by moving reporting to the thread pool. -// TODO(eseckler): Remove once holdback experiment is complete. -BASE_FEATURE(kAndroidBatteryMetricsReportOnUIThread, - "AndroidBatteryMetricsReportOnUIThread", - base::FEATURE_DISABLED_BY_DEFAULT); - namespace content { namespace { @@ -225,15 +217,11 @@ ->AddCount(capacity_consumed_avg, num_sampling_periods); } - // TODO(eseckler): Remove conditional once - // kAndroidBatteryMetricsReportOnUIThread is gone. - if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT}) - ->PostTask( - FROM_HERE, - base::BindOnce(&ReportDarkModeDrains, capacity_consumed_avg, - is_exclusive_measurement, num_sampling_periods)); - } + GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT}) + ->PostTask( + FROM_HERE, + base::BindOnce(&ReportDarkModeDrains, capacity_consumed_avg, + is_exclusive_measurement, num_sampling_periods)); } } // namespace @@ -252,18 +240,9 @@ {base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) { DETACH_FROM_SEQUENCE(sequence_checker_); - // TODO(eseckler): Remove conditional once - // kAndroidBatteryMetricsReportOnUIThread is gone. - if (base::FeatureList::IsEnabled(kAndroidBatteryMetricsReportOnUIThread)) { - // Initializing on the current (UI) thread registers all observers on the UI - // thread, such that all notifications will be received on the UI thread, - // too. - InitializeOnSequence(); - } else { - task_runner_->PostTask( - FROM_HERE, base::BindOnce(&AndroidBatteryMetrics::InitializeOnSequence, - base::Unretained(this))); - } + task_runner_->PostTask( + FROM_HERE, base::BindOnce(&AndroidBatteryMetrics::InitializeOnSequence, + base::Unretained(this))); } AndroidBatteryMetrics::~AndroidBatteryMetrics() {
diff --git a/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc b/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc index 530c1386..e35bd13 100644 --- a/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc +++ b/content/browser/attribution_reporting/attribution_data_host_manager_impl.cc
@@ -764,7 +764,7 @@ return; } - const auto attribution_header = RegistrarAndHeader::Get(headers); + auto attribution_header = RegistrarAndHeader::Get(headers); if (!attribution_header) { MaybeOnRegistrationsFinished(it); return; @@ -775,7 +775,8 @@ rfh, blink::mojom::WebFeature::kAttributionFencedFrameReportingBeacon); } - ParseSource(it, std::move(*suitable_reporting_origin), *attribution_header); + ParseSource(it, std::move(*suitable_reporting_origin), + std::move(*attribution_header)); } void AttributionDataHostManagerImpl::OnWebSourceParsed(
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.cc b/content/browser/attribution_reporting/attribution_storage_sql.cc index 25614486..87b0470 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql.cc
@@ -487,9 +487,10 @@ struct StoredSourceData { StoredSource source; int num_conversions; + int num_aggregatable_reports; }; -constexpr int kSourceColumnCount = 18; +constexpr int kSourceColumnCount = 19; // Helper to deserialize source rows. See `GetActiveSources()` for the // expected ordering of columns used for the input to this function. @@ -522,12 +523,14 @@ absl::optional<uint64_t> debug_key = ColumnUint64OrNull(statement, col++); int num_conversions = statement.ColumnInt(col++); int64_t aggregatable_budget_consumed = statement.ColumnInt64(col++); + int num_aggregatable_reports = statement.ColumnInt(col++); absl::optional<attribution_reporting::AggregationKeys> aggregation_keys = DeserializeAggregationKeys(statement, col++); if (!source_origin || !reporting_origin || !source_type.has_value() || !attribution_logic.has_value() || num_conversions < 0 || - aggregatable_budget_consumed < 0 || !aggregation_keys.has_value() || + aggregatable_budget_consumed < 0 || num_aggregatable_reports < 0 || + !aggregation_keys.has_value() || !StoredSource::IsExpiryOrReportWindowTimeValid(expiry_time, source_time) || !StoredSource::IsExpiryOrReportWindowTimeValid(event_report_window_time, @@ -584,7 +587,8 @@ aggregatable_report_window_time, priority, std::move(*filter_data), debug_key, std::move(*aggregation_keys), *attribution_logic, *active_state, source_id, aggregatable_budget_consumed), - .num_conversions = num_conversions}; + .num_conversions = num_conversions, + .num_aggregatable_reports = num_aggregatable_reports}; } absl::optional<StoredSourceData> ReadSourceToAttribute( @@ -755,8 +759,9 @@ "expiry_time,event_report_window_time,aggregatable_report_window_time," "source_type,attribution_logic,priority,source_site," "num_attributions,event_level_active,aggregatable_active,debug_key," - "aggregatable_budget_consumed,aggregatable_source,filter_data)" - "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0,?,?)"; + "aggregatable_budget_consumed,num_aggregatable_reports," + "aggregatable_source,filter_data)" + "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0,0,?,?)"; sql::Statement statement( db_.GetCachedStatement(SQL_FROM_HERE, kInsertImpressionSql)); statement.BindInt64(0, SerializeUint64(reg.source_event_id)); @@ -1229,7 +1234,8 @@ store_aggregatable_status = MaybeStoreAggregatableAttributionReportData( *new_aggregatable_report, source_to_attribute->source.aggregatable_budget_consumed(), - aggregatable_dedup_key, limits.aggregatable_budget_per_source); + source_to_attribute->num_aggregatable_reports, aggregatable_dedup_key, + limits.aggregatable_budget_per_source); } if (store_event_level_status == EventLevelResult::kInternalError || @@ -1347,6 +1353,8 @@ int num_attributions = statement.ColumnInt(1); int64_t aggregatable_budget_consumed = statement.ColumnInt64(2); + // aggregatable_budget_consumed > 0 implies num_aggregatable_reports > 0 so + // we don't check it here. if (num_attributions > 0 || aggregatable_budget_consumed > 0) { source_ids_to_deactivate.push_back(source_id); } else { @@ -2268,15 +2276,18 @@ // Origins usually aren't _that_ big compared to a 64 bit integer(8 bytes). // // All of the columns in this table are designed to be "const" except for - // |num_attributions|, |aggregatable_budget_consumed|, |event_level_active| + // |num_attributions|, |aggregatable_budget_consumed|, + // |num_aggregatable_reports|, |event_level_active| // and |aggregatable_active| which are updated when a new trigger is // received. |num_attributions| is the number of times an event-level report // has been created for a given source. |aggregatable_budget_consumed| is the - // aggregatable budget that has been consumed for a given source. |delegate_| - // can choose to enforce a maximum limit on them. |event_level_active| and - // |aggregatable_active| indicate whether a source is able to create new - // associated event-level and aggregatable reports. |event_level_active| and - // |aggregatable_active| can be unset on a number of conditions: + // aggregatable budget that has been consumed for a given source. + // |num_aggregatable_reports| is the number of times an aggregatable report + // has been created for a given source. |delegate_| can choose to enforce a + // maximum limit on them. |event_level_active| and |aggregatable_active| + // indicate whether a source is able to create new associated event-level and + // aggregatable reports. |event_level_active| and |aggregatable_active| can be + // unset on a number of conditions: // - A source converted too many times. // - A new source was stored after a source converted, making it // ineligible for new sources due to the attribution model documented @@ -2313,6 +2324,7 @@ "source_site TEXT NOT NULL," "debug_key INTEGER," "aggregatable_budget_consumed INTEGER NOT NULL," + "num_aggregatable_reports INTEGER NOT NULL," "aggregatable_source BLOB NOT NULL," "filter_data BLOB NOT NULL)"; if (!db_.Execute(kImpressionTableSql)) { @@ -2715,7 +2727,8 @@ static constexpr char kAdjustBudgetConsumedForSourceSql[] = "UPDATE sources " - "SET aggregatable_budget_consumed=aggregatable_budget_consumed+? " + "SET aggregatable_budget_consumed=aggregatable_budget_consumed+?," + "num_aggregatable_reports=num_aggregatable_reports+1 " "WHERE source_id=?"; sql::Statement statement( db_.GetCachedStatement(SQL_FROM_HERE, kAdjustBudgetConsumedForSourceSql)); @@ -2855,6 +2868,7 @@ AttributionStorageSql::MaybeStoreAggregatableAttributionReportData( AttributionReport& report, int64_t aggregatable_budget_consumed, + int num_aggregatable_reports, absl::optional<uint64_t> dedup_key, absl::optional<int64_t>& aggregatable_budget_per_source) { const auto* aggregatable_attribution = @@ -2862,6 +2876,8 @@ &report.data()); DCHECK(aggregatable_attribution); + // TODO(csharrison): Fail here if reports are too high. + switch (AggregatableAttributionAllowedForBudgetLimit( *aggregatable_attribution, aggregatable_budget_consumed)) { case RateLimitResult::kAllowed:
diff --git a/content/browser/attribution_reporting/attribution_storage_sql.h b/content/browser/attribution_reporting/attribution_storage_sql.h index 12c8b67..dae3c01 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql.h +++ b/content/browser/attribution_reporting/attribution_storage_sql.h
@@ -44,11 +44,11 @@ class CONTENT_EXPORT AttributionStorageSql : public AttributionStorage { public: // Version number of the database. - static constexpr int kCurrentVersionNumber = 52; + static constexpr int kCurrentVersionNumber = 53; // Earliest version which can use a `kCurrentVersionNumber` database // without failing. - static constexpr int kCompatibleVersionNumber = 52; + static constexpr int kCompatibleVersionNumber = 53; // Latest version of the database that cannot be upgraded to // `kCurrentVersionNumber` without razing the database. @@ -316,6 +316,7 @@ MaybeStoreAggregatableAttributionReportData( AttributionReport& report, int64_t aggregatable_budget_consumed, + int num_aggregatable_reports, absl::optional<uint64_t> dedup_key, absl::optional<int64_t>& aggregatable_budget_per_source) VALID_CONTEXT_REQUIRED(sequence_checker_);
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc b/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc index 239979f0..0ea591d 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql_migrations.cc
@@ -4,14 +4,140 @@ #include "content/browser/attribution_reporting/attribution_storage_sql_migrations.h" +#include "base/functional/function_ref.h" #include "base/metrics/histogram_functions.h" #include "base/time/time.h" #include "content/browser/attribution_reporting/attribution_storage_sql.h" #include "sql/database.h" #include "sql/meta_table.h" +#include "sql/statement.h" +#include "sql/transaction.h" namespace content { +namespace { + +// Ensure that both version numbers are updated together to prevent crashes on +// downgrades as in crbug.com/1413728. +[[nodiscard]] bool SetVersionNumbers(sql::MetaTable& meta_table, int version) { + return meta_table.SetVersionNumber(version) && + meta_table.SetCompatibleVersionNumber(version); +} + +// Wrap each migration in its own transaction. This results in smaller +// transactions, so it's less likely that a transaction's buffer will need to +// spill to disk. Also, if the database grows a lot and Chrome stops (user +// quit, process kill, etc.) during the migration process, per-migration +// transactions make it more likely that we'll make forward progress each time +// Chrome stops. +[[nodiscard]] bool MaybeMigrate( + sql::Database& db, + sql::MetaTable& meta_table, + int old_version, + base::FunctionRef<bool(sql::Database&)> migrate) { + if (meta_table.GetVersionNumber() != old_version) { + return true; + } + + sql::Transaction transaction(&db); + + return transaction.Begin() && // + migrate(db) && // + SetVersionNumbers(meta_table, old_version + 1) && // + transaction.Commit(); +} + +bool To53(sql::Database& db) { + static constexpr char kNewSourcesTableSql[] = + "CREATE TABLE new_sources(" + "source_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + "source_event_id INTEGER NOT NULL," + "source_origin TEXT NOT NULL," + "reporting_origin TEXT NOT NULL," + "source_time INTEGER NOT NULL," + "expiry_time INTEGER NOT NULL," + "event_report_window_time INTEGER NOT NULL," + "aggregatable_report_window_time INTEGER NOT NULL," + "num_attributions INTEGER NOT NULL," + "event_level_active INTEGER NOT NULL," + "aggregatable_active INTEGER NOT NULL," + "source_type INTEGER NOT NULL," + "attribution_logic INTEGER NOT NULL," + "priority INTEGER NOT NULL," + "source_site TEXT NOT NULL," + "debug_key INTEGER," + "aggregatable_budget_consumed INTEGER NOT NULL," + "num_aggregatable_reports INTEGER NOT NULL," + "aggregatable_source BLOB NOT NULL," + "filter_data BLOB NOT NULL)"; + if (!db.Execute(kNewSourcesTableSql)) { + return false; + } + + // Transfer the existing rows to the new table. Set a value of + // `num_aggregatable_reports` as 1 if the source has a non-zero value of + // `aggregatable_budget_consumed`. + static constexpr char kPopulateNewSourcesTableSql[] = + "INSERT INTO new_sources SELECT " + "source_id,source_event_id,source_origin," + "reporting_origin,source_time," + "expiry_time,event_report_window_time,aggregatable_report_window_time," + "source_type,attribution_logic,priority,source_site," + "num_attributions,event_level_active,aggregatable_active,debug_key," + "aggregatable_budget_consumed," + "IIF(aggregatable_budget_consumed>0,1,0)," + "aggregatable_source,filter_data FROM sources"; + if (!db.Execute(kPopulateNewSourcesTableSql)) { + return false; + } + + static constexpr char kDropOldSourcesTableSql[] = "DROP TABLE sources"; + if (!db.Execute(kDropOldSourcesTableSql)) { + return false; + } + + static constexpr char kRenameSourcesTableSql[] = + "ALTER TABLE new_sources RENAME TO sources"; + if (!db.Execute(kRenameSourcesTableSql)) { + return false; + } + + // Create the sources table indices on the new table. + static constexpr char kSourcesByActiveReportingOriginIndexSql[] = + "CREATE INDEX sources_by_active_reporting_origin " + "ON sources(event_level_active," + "aggregatable_active,reporting_origin)"; + if (!db.Execute(kSourcesByActiveReportingOriginIndexSql)) { + return false; + } + + static constexpr char kImpressionExpiryIndexSql[] = + "CREATE INDEX sources_by_expiry_time " + "ON sources(expiry_time)"; + if (!db.Execute(kImpressionExpiryIndexSql)) { + return false; + } + + static constexpr char kImpressionOriginIndexSql[] = + "CREATE INDEX active_sources_by_source_origin " + "ON sources(source_origin)" + "WHERE event_level_active=1 OR aggregatable_active=1"; + if (!db.Execute(kImpressionOriginIndexSql)) { + return false; + } + + static constexpr char kSourcesSourceTimeIndexSql[] = + "CREATE INDEX sources_by_source_time " + "ON sources(source_time)"; + if (!db.Execute(kSourcesSourceTimeIndexSql)) { + return false; + } + + return true; +} + +} // namespace + bool UpgradeAttributionStorageSqlSchema(sql::Database& db, sql::MetaTable& meta_table) { base::ThreadTicks start_timestamp; @@ -22,7 +148,12 @@ static_assert(AttributionStorageSql::kDeprecatedVersionNumber + 1 == 52, "Remove migration(s) below."); - static_assert(AttributionStorageSql::kCurrentVersionNumber == 52, + bool ok = MaybeMigrate(db, meta_table, 52, &To53); + if (!ok) { + return false; + } + + static_assert(AttributionStorageSql::kCurrentVersionNumber == 53, "Add migration(s) above."); if (base::ThreadTicks::IsSupported()) {
diff --git a/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc b/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc index 15acf14..e8f8e77 100644 --- a/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc +++ b/content/browser/attribution_reporting/attribution_storage_sql_migrations_unittest.cc
@@ -199,4 +199,54 @@ histograms.ExpectTotalCount("Conversions.Storage.MigrationTime", 0); } +TEST_F(AttributionStorageSqlMigrationsTest, MigrateVersion52ToCurrent) { + base::HistogramTester histograms; + LoadDatabase(GetVersionFilePath(52), DbPath()); + + // Verify pre-conditions. + { + sql::Database db; + ASSERT_TRUE(db.Open(DbPath())); + + sql::Statement s(db.GetUniqueStatement( + "SELECT aggregatable_budget_consumed FROM sources")); + ASSERT_TRUE(s.Step()); + ASSERT_EQ(0, s.ColumnInt(0)); + ASSERT_TRUE(s.Step()); + ASSERT_EQ(200, s.ColumnInt(0)); + ASSERT_FALSE(s.Step()); + } + MigrateDatabase(); + + // Verify schema is current. + { + sql::Database db; + ASSERT_TRUE(db.Open(DbPath())); + + CheckVersionNumbers(&db); + + // Compare normalized schemas + EXPECT_EQ(NormalizeSchema(GetCurrentSchema()), + NormalizeSchema(db.GetSchema())); + + // Verify that data is preserved across the migration. + sql::Statement s( + db.GetUniqueStatement("SELECT aggregatable_budget_consumed, " + "num_aggregatable_reports FROM sources")); + ASSERT_TRUE(s.Step()); + // First source has no budget consumed so hasn't made any reports. + ASSERT_EQ(0, s.ColumnInt(0)); + ASSERT_EQ(0, s.ColumnInt(1)); + ASSERT_TRUE(s.Step()); + // Second source has budget consumed so we set their num reports to 1. + ASSERT_EQ(200, s.ColumnInt(0)); + ASSERT_EQ(1, s.ColumnInt(1)); + ASSERT_FALSE(s.Step()); + } + + // DB creation histograms should be recorded. + histograms.ExpectTotalCount("Conversions.Storage.CreationTime", 0); + histograms.ExpectTotalCount("Conversions.Storage.MigrationTime", 1); +} + } // namespace content
diff --git a/content/browser/attribution_reporting/cross_app_web_attribution_browsertest.cc b/content/browser/attribution_reporting/cross_app_web_attribution_browsertest.cc index bc4f5da..77794885 100644 --- a/content/browser/attribution_reporting/cross_app_web_attribution_browsertest.cc +++ b/content/browser/attribution_reporting/cross_app_web_attribution_browsertest.cc
@@ -96,12 +96,12 @@ EXPECT_TRUE(NavigateToURL( shell(), GURL("https://example.test/page_with_cross_app_web_ot.html"))); - ASSERT_TRUE(ExecJs( - shell()->web_contents(), - content::JsReplace( - R"(const img = document.createElement('img'); - img.attributionSrc = $1;)", - GURL("https://example.test/page_without_cross_app_web_ot.html")))); + ASSERT_TRUE( + ExecJs(shell()->web_contents(), + content::JsReplace( + R"(const img = document.createElement('img'); + img.attributionSrc = $1;)", + GURL("https://example.test/register_source_headers.html")))); EXPECT_EQ( last_request_attribution_reporting_eligibility_, @@ -115,18 +115,39 @@ shell(), GURL("https://example.test/page_without_cross_app_web_ot.html"))); - ASSERT_TRUE(ExecJs( - shell()->web_contents(), - content::JsReplace( - R"(const img = document.createElement('img'); - img.src = $1; - img.attributionSrc = '';)", - GURL("https://example.test/page_without_cross_app_web_ot.html")))); + ASSERT_TRUE( + ExecJs(shell()->web_contents(), + content::JsReplace( + R"(const img = document.createElement('img'); + img.src = $1; + img.attributionSrc = '';)", + GURL("https://example.test/register_source_headers.html")))); EXPECT_EQ(last_request_attribution_reporting_eligibility_, network::mojom::AttributionReportingEligibility::kUnset); } +IN_PROC_BROWSER_TEST_F(CrossAppWebAttributionEnabledBrowserTest, + OriginTrialEnabledByThirdPartyToken_EligibilitySet) { + EXPECT_TRUE(NavigateToURL( + shell(), + GURL("https://a.test/page_with_cross_app_web_third_party_ot.html"))); + + EXPECT_EQ(true, EvalJs(shell(), + "document.featurePolicy.features().includes('" + "attribution-reporting')")); + + ASSERT_TRUE(ExecJs(shell()->web_contents(), + content::JsReplace( + R"(const img = document.createElement('img'); + img.attributionSrc = $1;)", + GURL("https://a.test/register_source_headers.html")))); + + EXPECT_EQ( + last_request_attribution_reporting_eligibility_, + network::mojom::AttributionReportingEligibility::kEventSourceOrTrigger); +} + class CrossAppWebAttributionDisabledBrowserTest : public CrossAppWebAttributionBrowserTestBase { public:
diff --git a/content/browser/attribution_reporting/sql_queries.h b/content/browser/attribution_reporting/sql_queries.h index d3ecbc04..8caf7a0 100644 --- a/content/browser/attribution_reporting/sql_queries.h +++ b/content/browser/attribution_reporting/sql_queries.h
@@ -117,6 +117,7 @@ prefix "debug_key," \ prefix "num_attributions," \ prefix "aggregatable_budget_consumed," \ + prefix "num_aggregatable_reports," \ prefix "aggregatable_source," \ prefix "filter_data," \ prefix "event_level_active," \
diff --git a/content/browser/fenced_frame/fenced_frame_browsertest.cc b/content/browser/fenced_frame/fenced_frame_browsertest.cc index 06b62f0..ae49a190 100644 --- a/content/browser/fenced_frame/fenced_frame_browsertest.cc +++ b/content/browser/fenced_frame/fenced_frame_browsertest.cc
@@ -4390,14 +4390,7 @@ true /*G*/}); } -// TODO(https://crbug.com/1335512): Flaky. -#if BUILDFLAG(IS_ANDROID) -#define MAYBE_FencedAdSizes DISABLED_FencedAdSizes -#else -#define MAYBE_FencedAdSizes FencedAdSizes -#endif -IN_PROC_BROWSER_TEST_F(FencedFrameParameterizedBrowserTest, - MAYBE_FencedAdSizes) { +IN_PROC_BROWSER_TEST_F(FencedFrameParameterizedBrowserTest, FencedAdSizes) { // This test exercises restrictions on fenced frame sizes in opaque-ads mode. // See the design document for more details on intended semantics: // https://docs.google.com/document/d/1MVqxc2nzde3cJYIRC8vnXH-a4A6J4GQE-1vBuXhQsPE/edit# @@ -4481,8 +4474,6 @@ EvalJs(nodeA, "getComputedStyle(nested_fenced_frame).height") .ExtractString(); - ASSERT_TRUE(WaitForFencedFrameSizeFreeze(nodeA->current_frame_host())); - // Navigate the fenced frame, which should force its inner size to the // nearest allowed one. TestFrameNavigationObserver observer(nodeB); @@ -4491,20 +4482,17 @@ observer.Wait(); // Check that the outer container size hasn't changed. - EXPECT_EQ(EvalJs(nodeA, "getComputedStyle(nested_fenced_frame).width") - .ExtractString(), - frame_width); - EXPECT_EQ(EvalJs(nodeA, "getComputedStyle(nested_fenced_frame).height") - .ExtractString(), - frame_height); - - ASSERT_TRUE(WaitForFencedFrameSizeFreeze(nodeA->current_frame_host())); + EXPECT_TRUE(PollUntilEvalToTrue( + JsReplace("getComputedStyle(nested_fenced_frame).width == $1 && " + "getComputedStyle(nested_fenced_frame).height == $2", + frame_width, frame_height), + nodeA->current_frame_host())); // Check that the inner size is what we expect. - int inner_width = EvalJs(nodeB, "innerWidth").ExtractInt(); - int inner_height = EvalJs(nodeB, "innerHeight").ExtractInt(); - EXPECT_EQ(inner_width, output_width); - EXPECT_EQ(inner_height, output_height); + EXPECT_TRUE( + PollUntilEvalToTrue(JsReplace("innerWidth == $1 && innerHeight == $2", + output_width, output_height), + nodeB->current_frame_host())); // Attempt to change the size of the fenced frame from the embedder. const int new_width = 970; @@ -4517,13 +4505,11 @@ ASSERT_TRUE(EvalJs(nodeA, "getComputedStyle(nested_fenced_frame).width") .error.empty()); - ASSERT_TRUE(WaitForFencedFrameSizeFreeze(nodeA->current_frame_host())); - // Check that the inner size hasn't changed. - inner_width = EvalJs(nodeB, "innerWidth").ExtractInt(); - inner_height = EvalJs(nodeB, "innerHeight").ExtractInt(); - EXPECT_EQ(inner_width, output_width); - EXPECT_EQ(inner_height, output_height); + EXPECT_TRUE( + PollUntilEvalToTrue(JsReplace("innerWidth == $1 && innerHeight == $2", + output_width, output_height), + nodeB->current_frame_host())); }; // Run all the individual test cases we want.
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc index ff46a9a..6ea1a24d 100644 --- a/content/browser/interest_group/interest_group_browsertest.cc +++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -30,7 +30,6 @@ #include "base/time/time.h" #include "base/values.h" #include "build/build_config.h" -#include "build/chromeos_buildflags.h" #include "components/network_session_configurator/common/network_switches.h" #include "components/web_package/web_bundle_builder.h" #include "content/browser/fenced_frame/fenced_frame.h" @@ -6613,27 +6612,18 @@ .height()); RenderFrameHost* ad_frame = GetFencedFrameRenderFrameHost(shell()); EXPECT_TRUE(WaitForLoadStop(web_contents())); - // Wait for 2 requestAnimationFrame calls to make things deterministic. - // Without this, the fenced frame may end up with its default size 300px * - // 150px. (Width * Height) - ASSERT_TRUE(WaitForFencedFrameSizeFreeze(ad_frame)); // Force layout. EXPECT_TRUE( ExecJs(ad_frame, "getComputedStyle(document.documentElement).width;")); - EXPECT_EQ(EvalJs(ad_frame, "innerWidth").ExtractInt(), screen_width); - EXPECT_EQ(EvalJs(ad_frame, "innerHeight").ExtractInt(), screen_height); + + EXPECT_TRUE( + PollUntilEvalToTrue(JsReplace("innerWidth == $1 && innerHeight == $2", + screen_width, screen_height), + ad_frame)); } -// TODO(crbug.com/1439980): Fix flaky test. -#if BUILDFLAG(IS_CHROMEOS_LACROS) -#define MAYBE_RunAdAuctionWithAdComponentWithSize \ - DISABLED_RunAdAuctionWithAdComponentWithSize -#else -#define MAYBE_RunAdAuctionWithAdComponentWithSize \ - RunAdAuctionWithAdComponentWithSize -#endif IN_PROC_BROWSER_TEST_F(InterestGroupFencedFrameBrowserTest, - MAYBE_RunAdAuctionWithAdComponentWithSize) { + RunAdAuctionWithAdComponentWithSize) { GURL test_url = https_server_->GetURL("a.test", "/fenced_frames/basic.html"); ASSERT_TRUE(NavigateToURL(shell(), test_url)); GURL ad_component_url = https_server_->GetURL( @@ -6687,15 +6677,13 @@ .GetSizeInPixel() .height()); EXPECT_TRUE(WaitForLoadStop(web_contents())); - // Wait for 2 requestAnimationFrame calls to make things deterministic. - // Without this, the fenced frame may end up with its default size 300px * - // 150px. (Width * Height) - ASSERT_TRUE(WaitForFencedFrameSizeFreeze(ad_frame)); // Force layout. EXPECT_TRUE( ExecJs(ad_frame, "getComputedStyle(document.documentElement).width;")); - EXPECT_EQ(EvalJs(ad_frame, "innerWidth").ExtractInt(), screen_width); - EXPECT_EQ(EvalJs(ad_frame, "innerHeight").ExtractInt(), screen_height); + EXPECT_TRUE( + PollUntilEvalToTrue(JsReplace("innerWidth == $1 && innerHeight == $2", + screen_width, screen_height), + ad_frame)); // Get the first component config from the fenced frame. Load it in the // nested fenced frame. The load should succeed. @@ -6712,15 +6700,12 @@ // bid. RenderFrameHost* ad_component_frame = GetFencedFrameRenderFrameHost(ad_frame); EXPECT_TRUE(WaitForLoadStop(web_contents())); - // Wait for 2 requestAnimationFrame calls to make things deterministic. - // Without this, the fenced frame may end up with its default size 300px * - // 150px. (Width * Height) - ASSERT_TRUE(WaitForFencedFrameSizeFreeze(ad_component_frame)); // Force layout. EXPECT_TRUE(ExecJs(ad_component_frame, "getComputedStyle(document.documentElement).width;")); - EXPECT_EQ(EvalJs(ad_component_frame, "innerWidth").ExtractInt(), 50); - EXPECT_EQ(EvalJs(ad_component_frame, "innerHeight").ExtractInt(), 25); + EXPECT_TRUE(PollUntilEvalToTrue( + JsReplace("innerWidth == $1 && innerHeight == $2", 50, 25), + ad_component_frame)); } IN_PROC_BROWSER_TEST_F(InterestGroupFencedFrameBrowserTest,
diff --git a/content/browser/preloading/prefetch/prefetch_container.cc b/content/browser/preloading/prefetch/prefetch_container.cc index 46c50b4..d87dc024 100644 --- a/content/browser/preloading/prefetch/prefetch_container.cc +++ b/content/browser/preloading/prefetch/prefetch_container.cc
@@ -733,12 +733,18 @@ } void PrefetchContainer::OnGetPrefetchToServe(bool blocked_until_head) { + // OnGetPrefetchToServe is called before we start waiting for head, and + // when the prefetch is used from `prefetches_ready_to_serve_`. + // If the prefetch had to wait for head, `blocked_until_head_start_time_` + // will already be set. Only record in the histogram when the + // `blocked_until_head_start_time_` is not set yet. + if (!blocked_until_head_start_time_) { + RecordWasBlockedUntilHeadWhenServingHistogram(prefetch_type_.GetEagerness(), + blocked_until_head); + } if (blocked_until_head) { blocked_until_head_start_time_ = base::TimeTicks::Now(); } - - RecordWasBlockedUntilHeadWhenServingHistogram(prefetch_type_.GetEagerness(), - blocked_until_head); } void PrefetchContainer::OnReturnPrefetchToServe(bool served) {
diff --git a/content/browser/preloading/prefetch/prefetch_document_manager.cc b/content/browser/preloading/prefetch/prefetch_document_manager.cc index 4e6da81..6b135ebe 100644 --- a/content/browser/preloading/prefetch/prefetch_document_manager.cc +++ b/content/browser/preloading/prefetch/prefetch_document_manager.cc
@@ -31,6 +31,29 @@ namespace { static PrefetchService* g_prefetch_service_for_testing = nullptr; + +// Sets ServingPageMetrics for all prefetches that might match under +// No-Vary-Search hint. +void SetMetricsForPossibleNoVarySearchHintMatches( + const std::map<GURL, base::WeakPtr<PrefetchContainer>>& all_prefetches, + const GURL& nav_url, + PrefetchServingPageMetricsContainer& serving_page_metrics_container) { + for (const auto& itr : all_prefetches) { + if (!itr.second) { + continue; + } + if (!itr.second->HasPrefetchBeenConsideredToServe() && + itr.second->GetNoVarySearchHint() && + itr.second->GetNoVarySearchHint()->AreEquivalent( + nav_url, itr.second->GetURL())) { + // In this case we need to set serving page metrics in case we end up + // using the prefetch after No-Vary-Search header is received. + itr.second->SetServingPageMetrics( + serving_page_metrics_container.GetWeakPtr()); + itr.second->UpdateServingPageMetrics(); + } + } +} } // namespace PrefetchDocumentManager::PrefetchDocumentManager(RenderFrameHost* rfh) @@ -105,6 +128,9 @@ DVLOG(1) << "PrefetchDocumentManager::DidStartNavigation() for " << navigation_handle->GetURL() << ": skipped (PrefetchContainer not found)"; + SetMetricsForPossibleNoVarySearchHintMatches( + all_prefetches_, navigation_handle->GetURL(), + *serving_page_metrics_container); return; } @@ -113,6 +139,9 @@ DVLOG(1) << "PrefetchDocumentManager::DidStartNavigation() for " << *prefetch_iter->second << ": skipped (already used for another navigation)"; + SetMetricsForPossibleNoVarySearchHintMatches( + all_prefetches_, navigation_handle->GetURL(), + *serving_page_metrics_container); return; }
diff --git a/content/browser/preloading/prefetch/prefetch_service.cc b/content/browser/preloading/prefetch/prefetch_service.cc index 5df1b2a5..216e29b7 100644 --- a/content/browser/preloading/prefetch/prefetch_service.cc +++ b/content/browser/preloading/prefetch/prefetch_service.cc
@@ -25,6 +25,8 @@ #include "content/browser/preloading/prefetch/prefetch_status.h" #include "content/browser/preloading/prefetch/prefetch_streaming_url_loader.h" #include "content/browser/preloading/prefetch/proxy_lookup_client_impl.h" +#include "content/browser/preloading/preloading_attempt_impl.h" +#include "content/browser/renderer_host/frame_tree_node.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/frame_accept_header.h" @@ -245,7 +247,6 @@ UMA_HISTOGRAM_ENUMERATION( "PrefetchProxy.Redirect.NetworkContextStateTransition", transition); } - } // namespace // static @@ -1343,25 +1344,55 @@ #endif // DCHECK_IS_ON() } +PrefetchContainer* PrefetchService::FindPrefetchContainerToServe( + const PrefetchContainer::Key& key) { + // Search for an exact match first. If one is found and not deleted, produce + // it. + auto it = prefetches_ready_to_serve_.find(key); + if (it != prefetches_ready_to_serve_.end()) { + PrefetchContainer* prefetch = it->second.get(); + prefetches_ready_to_serve_.erase(it); + if (prefetch) { + return prefetch; + } + } + + // Search for an inexact match using the No-Vary-Search hint. + // It must either be servable now or potentially servable soon. + const auto frame_host_id = key.first; + const GURL& nav_url = key.second; + for (const auto& active_prefetch : active_prefetches_) { + if (active_prefetch.first != frame_host_id) { + continue; + } + PrefetchContainer* prefetch = all_prefetches_[active_prefetch].get(); + if (!prefetch || prefetch->HasPrefetchBeenConsideredToServe()) { + continue; + } + const auto& nvs_expected = prefetch->GetNoVarySearchHint(); + if (!nvs_expected || + !nvs_expected->AreEquivalent(nav_url, prefetch->GetURL())) { + continue; + } + if (prefetch->IsPrefetchServable(PrefetchCacheableDuration()) || + prefetch->ShouldBlockUntilHeadReceived()) { + return prefetch; + } + } + return nullptr; +} + void PrefetchService::GetPrefetchToServe( const PrefetchContainer::Key& key, OnPrefetchToServeReady on_prefetch_to_serve_ready) { DumpPrefetchesForDebug(); const GURL& url = key.second; - auto prefetch_iter = prefetches_ready_to_serve_.find(key); - if (prefetch_iter == prefetches_ready_to_serve_.end()) { - DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << url - << "): URL not found"; - std::move(on_prefetch_to_serve_ready).Run(nullptr); - return; - } - - base::WeakPtr<PrefetchContainer> prefetch_container = prefetch_iter->second; - prefetches_ready_to_serve_.erase(prefetch_iter); + PrefetchContainer* prefetch_container = FindPrefetchContainerToServe(key); if (!prefetch_container) { - DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << url - << "): PrefetchContainer is null"; + DVLOG(1) + << "PrefetchService::GetPrefetchToServe(" << url + << "): PrefetchContainer is null or no matching prefetch was found"; std::move(on_prefetch_to_serve_ready).Run(nullptr); return; } @@ -1376,18 +1407,19 @@ DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << url << "): PrefetchContainer is servable"; prefetch_container->OnGetPrefetchToServe(/*blocked_until_head=*/false); - ReturnPrefetchToServe(prefetch_container, - std::move(on_prefetch_to_serve_ready)); + ReturnPrefetchToServe(prefetch_container->GetWeakPtr(), + std::move(on_prefetch_to_serve_ready), url); return; } if (prefetch_container->ShouldBlockUntilHeadReceived()) { DVLOG(1) << "PrefetchService::GetPrefetchToServe(" << url << "): PrefetchContainer is blocked until head"; - prefetch_container->OnGetPrefetchToServe(/*blocked_until_head=*/false); + prefetch_container->OnGetPrefetchToServe(/*blocked_until_head=*/true); prefetch_container->GetStreamingLoader()->SetOnReceivedHeadCallback( - base::BindOnce(&PrefetchService::ReturnPrefetchToServe, - weak_method_factory_.GetWeakPtr(), prefetch_container, + base::BindOnce(&PrefetchService::WaitOnPrefetchToServeHead, + weak_method_factory_.GetWeakPtr(), key, + prefetch_container->GetWeakPtr(), std::move(on_prefetch_to_serve_ready))); return; } @@ -1397,9 +1429,73 @@ std::move(on_prefetch_to_serve_ready).Run(nullptr); } -void PrefetchService::ReturnPrefetchToServe( +void PrefetchService::WaitOnPrefetchToServeHead( + const PrefetchContainer::Key& key, base::WeakPtr<PrefetchContainer> prefetch_container, OnPrefetchToServeReady on_prefetch_to_serve_ready) { + const GURL& nav_url = key.second; + if (!prefetch_container) { + ReturnPrefetchToServe(nullptr, std::move(on_prefetch_to_serve_ready), + nav_url); + return; + } + if (nav_url == prefetch_container->GetURL()) { + PrepareToServe(nav_url, prefetch_container); + GetPrefetchToServe(key, std::move(on_prefetch_to_serve_ready)); + return; + } + + if (const auto* head = prefetch_container->GetHead()) { + if (!head->parsed_headers || + !head->parsed_headers->no_vary_search_with_parse_error || + head->parsed_headers->no_vary_search_with_parse_error + ->is_parse_error()) { + // is_parse_error() == true includes the case where the header is + // not there (kOk) and the case where the header is equivalent + // to default behavior (exactly match URL - kDefaultValue) + prefetch_container->OnReturnPrefetchToServe(/*served=*/false); + prefetch_container->UpdateServingPageMetrics(); + ReturnPrefetchToServe(nullptr, std::move(on_prefetch_to_serve_ready), + nav_url); + return; + } + auto no_vary_search_data = + NoVarySearchHelper::ParseHttpNoVarySearchDataFromMojom( + head->parsed_headers->no_vary_search_with_parse_error + ->get_no_vary_search()); + if (!no_vary_search_data.AreEquivalent(nav_url, + prefetch_container->GetURL())) { + prefetch_container->OnReturnPrefetchToServe(/*served=*/false); + prefetch_container->UpdateServingPageMetrics(); + ReturnPrefetchToServe(nullptr, std::move(on_prefetch_to_serve_ready), + nav_url); + return; + } + DVLOG(1) << "PrefetchService::WaitOnPrefetchToServeHead::" + << "url = " << nav_url << "::" + << "matches by NVS header the prefetch " + << prefetch_container->GetURL(); + if (auto attempt = prefetch_container->preloading_attempt()) { + // Before No-Vary-Search hint, the decision to use a prefetched response + // was made in `DidStartNavigation`. `SetIsAccurateTriggering` is called + // by `PreloadingDataImpl::DidStartNavigation`. With No-Vary-Search + // hint the decision to use an in-flight prefetched response is + // delayed until the headers are received from the server. This + // happens after `DidStartNavigation`. At this point in the code we + // have already decided we are going to use the prefetch, so we can + // safely call `SetIsAccurateTriggering`. + static_cast<PreloadingAttemptImpl*>(attempt.get()) + ->SetIsAccurateTriggering(nav_url); + } + PrepareToServe(nav_url, prefetch_container); + GetPrefetchToServe(key, std::move(on_prefetch_to_serve_ready)); + } +} + +void PrefetchService::ReturnPrefetchToServe( + base::WeakPtr<PrefetchContainer> prefetch_container, + OnPrefetchToServeReady on_prefetch_to_serve_ready, + const GURL& nav_url) { if (prefetch_container) { prefetch_container->UpdateServingPageMetrics(); } @@ -1408,7 +1504,9 @@ !prefetch_container->IsPrefetchServable(PrefetchCacheableDuration()) || prefetch_container->HaveDefaultContextCookiesChanged( prefetch_container->GetURL())) { - prefetch_container->OnReturnPrefetchToServe(/*served=*/false); + if (prefetch_container) { + prefetch_container->OnReturnPrefetchToServe(/*served=*/false); + } std::move(on_prefetch_to_serve_ready).Run(nullptr); return; }
diff --git a/content/browser/preloading/prefetch/prefetch_service.h b/content/browser/preloading/prefetch/prefetch_service.h index f9d8e722..f834b6bd 100644 --- a/content/browser/preloading/prefetch/prefetch_service.h +++ b/content/browser/preloading/prefetch/prefetch_service.h
@@ -260,8 +260,25 @@ // prefetch if needed, and updates its state. void ReturnPrefetchToServe( base::WeakPtr<PrefetchContainer> prefetch_container, + OnPrefetchToServeReady on_prefetch_to_serve_ready, + const GURL& nav_url); + + // Helper function for |GetPrefetchToServe| to wait for head of a + // potentially matching CL in order to decide if we can use it or not for + // the current navigation. + // Once we make the decision to use a prefetch, call |PrepareToServe| and + // |GetPrefetchToServe| again in order to enforce that prefetches that are + // served are served from |prefetches_ready_to_serve_|. + void WaitOnPrefetchToServeHead( + const PrefetchContainer::Key& key, + base::WeakPtr<PrefetchContainer> prefetch_container, OnPrefetchToServeReady on_prefetch_to_serve_ready); + // Helper function for |GetPrefetchToServe| which identifies the + // |prefetch_container| that could potentially be served. + PrefetchContainer* FindPrefetchContainerToServe( + const PrefetchContainer::Key& key); + // Checks if there is a prefetch in |all_prefetches_| with the same URL as // |prefetch_container| but from a different referring RenderFrameHost. // Records the result to a UMA histogram.
diff --git a/content/browser/preloading/prefetch/prefetch_service_unittest.cc b/content/browser/preloading/prefetch/prefetch_service_unittest.cc index ba74145..90db95d 100644 --- a/content/browser/preloading/prefetch/prefetch_service_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_service_unittest.cc
@@ -282,7 +282,9 @@ const GURL& prefetch_url, const PrefetchType& prefetch_type, const absl::optional<GURL>& referrer_url = absl::nullopt, - bool enable_no_vary_search_header = false) { + bool enable_no_vary_search_header = false, + network::mojom::NoVarySearchPtr&& no_vary_search_hint = + network::mojom::NoVarySearchPtr()) { PrefetchDocumentManager* prefetch_document_manager = PrefetchDocumentManager::GetOrCreateForCurrentDocument(main_rfh()); if (enable_no_vary_search_header) @@ -293,9 +295,8 @@ referrer.url = referrer_url.value(); } - network::mojom::NoVarySearchPtr no_vary_search_expected; prefetch_document_manager->PrefetchUrl( - prefetch_url, prefetch_type, referrer, no_vary_search_expected, + prefetch_url, prefetch_type, referrer, no_vary_search_hint, blink::mojom::SpeculationInjectionWorld::kNone, nullptr); } @@ -604,7 +605,8 @@ void ExpectCorrectUkmLogs(PreloadingEligibility eligibility, PreloadingHoldbackStatus holdback, PreloadingTriggeringOutcome outcome, - PreloadingFailureReason failure) { + PreloadingFailureReason failure, + bool is_accurate = false) { const auto source_id = ForceLogsUploadAndGetUkmId(); auto actual_attempts = test_ukm_recorder()->GetEntries( ukm::builders::Preloading_Attempt::kEntryName, @@ -619,8 +621,7 @@ const auto expected_attempts = {attempt_entry_builder()->BuildEntry( source_id, PreloadingType::kPrefetch, eligibility, holdback, outcome, - failure, - /*accurate=*/false, ready_time)}; + failure, is_accurate, ready_time)}; EXPECT_THAT(actual_attempts, testing::UnorderedElementsAreArray(expected_attempts)) @@ -4308,6 +4309,340 @@ PreloadingFailureReason::kUnspecified); } +// TODO(crbug.com/1396460): Test flaky on lacros trybots. +#if BUILDFLAG(IS_CHROMEOS) +#define MAYBE_NVSBlockUntilHeadReceived DISABLED_NVSBlockUntilHeadReceived +#else +#define MAYBE_NVSBlockUntilHeadReceived NVSBlockUntilHeadReceived +#endif +TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, + MAYBE_NVSBlockUntilHeadReceived) { + // For this test we need to enable kPrefetchNoVarySearch. + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures({network::features::kPrefetchNoVarySearch}, {}); + base::HistogramTester histogram_tester; + + MakePrefetchService( + std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); + + network::mojom::NoVarySearchPtr no_vary_search_hint = + network::mojom::NoVarySearch::New(); + no_vary_search_hint->vary_on_key_order = true; + no_vary_search_hint->search_variance = + network::mojom::SearchParamsVariance::NewNoVaryParams( + std::vector<std::string>({"a"})); + MakePrefetchOnMainFrame( + GURL("https://example.com/index.html?a=5"), + PrefetchType(/*use_isolated_network_context=*/true, + /*use_prefetch_proxy=*/true, GetParam()), + /* referrer_url */ absl::nullopt, + /* no_vary_search_support */ true, + /* no_vary_search_hint */ std::move(no_vary_search_hint)); + base::RunLoop().RunUntilIdle(); + + VerifyCommonRequestState(GURL("https://example.com/index.html?a=5"), + /*use_prefetch_proxy=*/true); + + // Navigate to the URL before the head of the prefetch response is received + Navigate(GURL("https://example.com/index.html"), main_rfh()->GetGlobalId()); + + // Request the prefetch from the PrefetchService. The given callback shouldn't + // be called until after the head is received. + base::RunLoop get_prefetch_run_loop; + base::WeakPtr<PrefetchContainer> serveable_prefetch_container; + prefetch_service_->GetPrefetchToServe( + PrefetchContainer::Key(main_rfh()->GetGlobalId(), + GURL("https://example.com/index.html")), + base::BindOnce( + [](base::WeakPtr<PrefetchContainer>* serveable_prefetch_container, + base::RunLoop* get_prefetch_run_loop, + base::WeakPtr<PrefetchContainer> prefetch_to_serve) { + *serveable_prefetch_container = prefetch_to_serve; + get_prefetch_run_loop->Quit(); + }, + &serveable_prefetch_container, &get_prefetch_run_loop)); + EXPECT_FALSE(serveable_prefetch_container); + + // Sends the head of the prefetch response. This should trigger the above + // callback. + SendHeadOfResponseAndWait( + net::HTTP_OK, kHTMLMimeType, + /*use_prefetch_proxy=*/true, + {{"X-Testing", "Hello World"}, {"No-Vary-Search", "params=(\"a\")"}}, + std::size(kHTMLBody)); + get_prefetch_run_loop.Run(); + ASSERT_TRUE(serveable_prefetch_container); + + // Send the body and completion status of the request, + SendBodyContentOfResponseAndWait(kHTMLBody); + CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); + + // Check the metrics now that the prefetch is complete. + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); + + absl::optional<PrefetchReferringPageMetrics> referring_page_metrics = + PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); + EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 1); + EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 1); + EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 1); + + absl::optional<PrefetchServingPageMetrics> serving_page_metrics = + GetMetricsForMostRecentNavigation(); + ASSERT_TRUE(serving_page_metrics); + EXPECT_TRUE(serving_page_metrics->prefetch_status); + EXPECT_EQ(serving_page_metrics->prefetch_status.value(), + static_cast<int>(PrefetchStatus::kPrefetchSuccessful)); + EXPECT_TRUE(serving_page_metrics->required_private_prefetch_proxy); + EXPECT_TRUE(serving_page_metrics->same_tab_as_prefetching_tab); + EXPECT_TRUE(serving_page_metrics->prefetch_header_latency); + EXPECT_EQ(serving_page_metrics->prefetch_header_latency.value(), + base::Milliseconds(kHeaderLatency)); + + EXPECT_TRUE(serveable_prefetch_container->HasPrefetchStatus()); + EXPECT_EQ(serveable_prefetch_container->GetPrefetchStatus(), + PrefetchStatus::kPrefetchSuccessful); + EXPECT_TRUE( + serveable_prefetch_container->IsPrefetchServable(base::TimeDelta::Max())); + ASSERT_TRUE(serveable_prefetch_container->GetHead()); + EXPECT_TRUE(serveable_prefetch_container->GetHead()->was_in_prefetch_cache); + + ExpectCorrectUkmLogs(PreloadingEligibility::kEligible, + PreloadingHoldbackStatus::kAllowed, + PreloadingTriggeringOutcome::kReady, + PreloadingFailureReason::kUnspecified, + /*accurate*/ true); +} + +// TODO(crbug.com/1396460): Test flaky on lacros trybots. +#if BUILDFLAG(IS_CHROMEOS) +#define MAYBE_NVSBlockUntilHeadReceivedNoMatchNoNVSHeader \ + DISABLED_NVSBlockUntilHeadReceivedNoMatchNoNVSHeader +#else +#define MAYBE_NVSBlockUntilHeadReceivedNoMatchNoNVSHeader \ + NVSBlockUntilHeadReceivedNoMatchNoMatchNoNVSHeader +#endif +TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, + MAYBE_NVSBlockUntilHeadReceivedNoMatchNoNVSHeader) { + // For this test we need to enable kPrefetchNoVarySearch. + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures({network::features::kPrefetchNoVarySearch}, {}); + base::HistogramTester histogram_tester; + + MakePrefetchService( + std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); + + network::mojom::NoVarySearchPtr no_vary_search_hint = + network::mojom::NoVarySearch::New(); + no_vary_search_hint->vary_on_key_order = true; + no_vary_search_hint->search_variance = + network::mojom::SearchParamsVariance::NewNoVaryParams( + std::vector<std::string>({"a"})); + MakePrefetchOnMainFrame( + GURL("https://example.com/index.html?a=5"), + PrefetchType(/*use_isolated_network_context=*/true, + /*use_prefetch_proxy=*/true, GetParam()), + /* referrer_url */ absl::nullopt, + /* no_vary_search_support */ true, + /* no_vary_search_hint */ std::move(no_vary_search_hint)); + base::RunLoop().RunUntilIdle(); + + VerifyCommonRequestState(GURL("https://example.com/index.html?a=5"), + /*use_prefetch_proxy=*/true); + + // Navigate to the URL before the head of the prefetch response is received + Navigate(GURL("https://example.com/index.html"), main_rfh()->GetGlobalId()); + + // Request the prefetch from the PrefetchService. The given callback shouldn't + // be called until after the head is received. + base::RunLoop get_prefetch_run_loop; + bool is_nav_unblocked = false; + prefetch_service_->GetPrefetchToServe( + PrefetchContainer::Key(main_rfh()->GetGlobalId(), + GURL("https://example.com/index.html")), + base::BindOnce( + [](bool* is_nav_unblocked, base::RunLoop* get_prefetch_run_loop, + base::WeakPtr<PrefetchContainer> prefetch_to_serve) { + *is_nav_unblocked = !prefetch_to_serve; + get_prefetch_run_loop->Quit(); + }, + &is_nav_unblocked, &get_prefetch_run_loop)); + EXPECT_FALSE(is_nav_unblocked); + + // Sends the head of the prefetch response. This should trigger the above + // callback with a nullptr argument. + SendHeadOfResponseAndWait(net::HTTP_OK, kHTMLMimeType, + /*use_prefetch_proxy=*/true, + {{"X-Testing", "Hello World"}}, + std::size(kHTMLBody)); + get_prefetch_run_loop.Run(); + ASSERT_TRUE(is_nav_unblocked); + + // Send the body and completion status of the request, + SendBodyContentOfResponseAndWait(kHTMLBody); + CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); + + // Check the metrics now that the prefetch is complete. + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); + + absl::optional<PrefetchReferringPageMetrics> referring_page_metrics = + PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); + EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 1); + EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 1); + EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 1); + + absl::optional<PrefetchServingPageMetrics> serving_page_metrics = + GetMetricsForMostRecentNavigation(); + ASSERT_TRUE(serving_page_metrics); + + EXPECT_TRUE(serving_page_metrics->prefetch_status); + + EXPECT_EQ(serving_page_metrics->prefetch_status.value(), + static_cast<int>(PrefetchStatus::kPrefetchSuccessful)); + EXPECT_TRUE(serving_page_metrics->required_private_prefetch_proxy); + EXPECT_TRUE(serving_page_metrics->same_tab_as_prefetching_tab); + EXPECT_TRUE(serving_page_metrics->prefetch_header_latency); + EXPECT_EQ(serving_page_metrics->prefetch_header_latency.value(), + base::Milliseconds(kHeaderLatency)); + + ExpectCorrectUkmLogs(PreloadingEligibility::kEligible, + PreloadingHoldbackStatus::kAllowed, + PreloadingTriggeringOutcome::kReady, + PreloadingFailureReason::kUnspecified, + /*accurate*/ false); +} + +// TODO(crbug.com/1396460): Test flaky on lacros trybots. +#if BUILDFLAG(IS_CHROMEOS) +#define MAYBE_NVSBlockUntilHeadReceivedNoMatchByNVSHeader \ + DISABLED_NVSBlockUntilHeadReceivedNoMatchByNVSHeader +#else +#define MAYBE_NVSBlockUntilHeadReceivedNoMatchByNVSHeader \ + NVSBlockUntilHeadReceivedNoMatchNoMatchByNVSHeader +#endif +TEST_P(PrefetchServiceAlwaysBlockUntilHeadTest, + MAYBE_NVSBlockUntilHeadReceivedNoMatchByNVSHeader) { + // For this test we need to enable kPrefetchNoVarySearch. + base::test::ScopedFeatureList feature_list; + feature_list.InitWithFeatures({network::features::kPrefetchNoVarySearch}, {}); + base::HistogramTester histogram_tester; + + MakePrefetchService( + std::make_unique<testing::NiceMock<MockPrefetchServiceDelegate>>()); + + network::mojom::NoVarySearchPtr no_vary_search_hint = + network::mojom::NoVarySearch::New(); + no_vary_search_hint->vary_on_key_order = true; + no_vary_search_hint->search_variance = + network::mojom::SearchParamsVariance::NewNoVaryParams( + std::vector<std::string>({"a"})); + MakePrefetchOnMainFrame( + GURL("https://example.com/index.html?a=5"), + PrefetchType(/*use_isolated_network_context=*/true, + /*use_prefetch_proxy=*/true, GetParam()), + /* referrer_url */ absl::nullopt, + /* no_vary_search_support */ true, + /* no_vary_search_hint */ std::move(no_vary_search_hint)); + base::RunLoop().RunUntilIdle(); + + VerifyCommonRequestState(GURL("https://example.com/index.html?a=5"), + /*use_prefetch_proxy=*/true); + + // Navigate to the URL before the head of the prefetch response is received + Navigate(GURL("https://example.com/index.html"), main_rfh()->GetGlobalId()); + + // Request the prefetch from the PrefetchService. The given callback shouldn't + // be called until after the head is received. + base::RunLoop get_prefetch_run_loop; + bool is_nav_unblocked = false; + prefetch_service_->GetPrefetchToServe( + PrefetchContainer::Key(main_rfh()->GetGlobalId(), + GURL("https://example.com/index.html")), + base::BindOnce( + [](bool* is_nav_unblocked, base::RunLoop* get_prefetch_run_loop, + base::WeakPtr<PrefetchContainer> prefetch_to_serve) { + *is_nav_unblocked = !prefetch_to_serve; + get_prefetch_run_loop->Quit(); + }, + &is_nav_unblocked, &get_prefetch_run_loop)); + EXPECT_FALSE(is_nav_unblocked); + + // Sends the head of the prefetch response. This should trigger the above + // callback with a nullptr argument. + SendHeadOfResponseAndWait( + net::HTTP_OK, kHTMLMimeType, + /*use_prefetch_proxy=*/true, + {{"X-Testing", "Hello World"}, {"No-Vary-Search", "params=(\"b\")"}}, + std::size(kHTMLBody)); + get_prefetch_run_loop.Run(); + ASSERT_TRUE(is_nav_unblocked); + + // Send the body and completion status of the request, + SendBodyContentOfResponseAndWait(kHTMLBody); + CompleteResponseAndWait(net::OK, std::size(kHTMLBody)); + + // Check the metrics now that the prefetch is complete. + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.ExistingPrefetchWithMatchingURL", false, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.RespCode", net::HTTP_OK, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.NetError", net::OK, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.BodyLength", std::size(kHTMLBody), 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.TotalTime", kTotalTimeDuration, 1); + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.Mainframe.ConnectTime", kConnectTimeDuration, 1); + + absl::optional<PrefetchReferringPageMetrics> referring_page_metrics = + PrefetchReferringPageMetrics::GetForCurrentDocument(main_rfh()); + EXPECT_EQ(referring_page_metrics->prefetch_attempted_count, 1); + EXPECT_EQ(referring_page_metrics->prefetch_eligible_count, 1); + EXPECT_EQ(referring_page_metrics->prefetch_successful_count, 1); + + absl::optional<PrefetchServingPageMetrics> serving_page_metrics = + GetMetricsForMostRecentNavigation(); + ASSERT_TRUE(serving_page_metrics); + + EXPECT_TRUE(serving_page_metrics->prefetch_status); + + EXPECT_EQ(serving_page_metrics->prefetch_status.value(), + static_cast<int>(PrefetchStatus::kPrefetchSuccessful)); + EXPECT_TRUE(serving_page_metrics->required_private_prefetch_proxy); + EXPECT_TRUE(serving_page_metrics->same_tab_as_prefetching_tab); + EXPECT_TRUE(serving_page_metrics->prefetch_header_latency); + EXPECT_EQ(serving_page_metrics->prefetch_header_latency.value(), + base::Milliseconds(kHeaderLatency)); + + ExpectCorrectUkmLogs(PreloadingEligibility::kEligible, + PreloadingHoldbackStatus::kAllowed, + PreloadingTriggeringOutcome::kReady, + PreloadingFailureReason::kUnspecified, + /*accurate*/ false); +} + INSTANTIATE_TEST_SUITE_P( ParametrizedTests, PrefetchServiceAlwaysBlockUntilHeadTest,
diff --git a/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc b/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc index f4e1032..c5f9093 100644 --- a/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc +++ b/content/browser/renderer_host/input/main_thread_event_queue_browsertest.cc
@@ -113,7 +113,7 @@ void DoMouseMove() { // Send a click event to cause some jankiness. This is done via a click - // event as ExecuteScript is synchronous. + // event as ExecJs is synchronous. SimulateMouseClick(shell()->web_contents(), 0, blink::WebPointerProperties::Button::kLeft); auto input_msg_watcher = std::make_unique<InputMsgWatcher>( @@ -155,7 +155,7 @@ events[3].MovePoint(0, 35, 40); // Send a click event to cause some jankiness. This is done via a click - // event as ExecuteScript is synchronous. + // event as ExecJs is synchronous. SimulateMouseClick(shell()->web_contents(), 0, blink::WebPointerProperties::Button::kLeft); auto input_msg_watcher = std::make_unique<InputMsgWatcher>(
diff --git a/content/browser/renderer_host/render_frame_host_manager.cc b/content/browser/renderer_host/render_frame_host_manager.cc index cb16df6..6b930ba6 100644 --- a/content/browser/renderer_host/render_frame_host_manager.cc +++ b/content/browser/renderer_host/render_frame_host_manager.cc
@@ -2719,9 +2719,9 @@ if (browsing_context_group_swap.type() == BrowsingContextGroupSwapType::kRelatedCoopSwap) { // We typically expect `source_instance` to be in the same BrowsingInstance - // as `current_instance`. However when an extension uses the - // chrome.tabs.update API to navigate to about:blank, `source_instance` is - // set to the extension's SiteInstance, which should be in a different + // as `current_instance`. However when extensions use the chrome.tabs.update + // API to navigate to about:blank, `source_instance` is set to the + // extension's SiteInstance, which should be in a different // BrowsingInstance. In that case, `source_instance` should not be in a // different BrowsingInstance in the same CoopRelatedGroup as // `current_instance`, but use its own extension's CoopRelatedGroup. Note
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index e92d6d1..24da20fe 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -258,8 +258,6 @@ {wf::EnableLazyInitializeMediaControls, raw_ref(features::kLazyInitializeMediaControls)}, {wf::EnableLazyFrameLoading, raw_ref(features::kLazyFrameLoading)}, - {wf::EnableLazyImageVisibleLoadTimeMetrics, - raw_ref(features::kLazyImageVisibleLoadTimeMetrics)}, {wf::EnableMediaCastOverlayButton, raw_ref(media::kMediaCastOverlayButton)}, {wf::EnableMediaEngagementBypassAutoplayPolicies, raw_ref(media::kMediaEngagementBypassAutoplayPolicies)},
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 6aff4bff..570835d7 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -624,10 +624,6 @@ "LazyFrameLoading", base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kLazyImageVisibleLoadTimeMetrics, - "LazyImageVisibleLoadTimeMetrics", - base::FEATURE_ENABLED_BY_DEFAULT); - // Enable lazy initialization of the media controls. BASE_FEATURE(kLazyInitializeMediaControls, "LazyInitializeMediaControls",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 0dfd2107..4aa23518 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -131,7 +131,6 @@ CONTENT_EXPORT BASE_DECLARE_FEATURE(kJavaScriptExperimentalSharedMemory); CONTENT_EXPORT BASE_DECLARE_FEATURE(kIwaControlledFrame); CONTENT_EXPORT BASE_DECLARE_FEATURE(kLazyFrameLoading); -CONTENT_EXPORT BASE_DECLARE_FEATURE(kLazyImageVisibleLoadTimeMetrics); CONTENT_EXPORT BASE_DECLARE_FEATURE(kLazyInitializeMediaControls); CONTENT_EXPORT BASE_DECLARE_FEATURE(kLegacyWindowsDWriteFontFallback); CONTENT_EXPORT BASE_DECLARE_FEATURE(kLogJsConsoleMessages);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 5b0e23a..2dafc4c 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -3320,6 +3320,7 @@ data = [ "//content/test/gpu/run_pytype.py", + "//content/test/gpu/unexpected_pass_finder.py", "//content/test/gpu/validate_tag_consistency.py", "//content/test/gpu/gold_inexact_matching/",
diff --git a/content/test/content_test_bundle_data.filelist b/content/test/content_test_bundle_data.filelist index d5b1b38..350f7cdf 100644 --- a/content/test/content_test_bundle_data.filelist +++ b/content/test/content_test_bundle_data.filelist
@@ -5101,6 +5101,8 @@ data/attribution_reporting/aggregatable_report_goldens/version_/report_6_cleartext_payloads.json data/attribution_reporting/databases/version_51.sql data/attribution_reporting/databases/version_52.sql +data/attribution_reporting/databases/version_53.sql +data/attribution_reporting/inject_cross_app_web_third_party_ot.js data/attribution_reporting/interop/aggregatable_budget.json data/attribution_reporting/interop/aggregatable_contributions_creation.json data/attribution_reporting/interop/aggregatable_dedup_key.json @@ -5138,6 +5140,7 @@ data/attribution_reporting/page_with_conversion_measurement_disabled.html.mock-http-headers data/attribution_reporting/page_with_conversion_redirect.html data/attribution_reporting/page_with_cross_app_web_ot.html +data/attribution_reporting/page_with_cross_app_web_third_party_ot.html data/attribution_reporting/page_with_disallowed_iframe.html data/attribution_reporting/page_with_impression_creator.html data/attribution_reporting/page_with_impression_creator.html.mock-http-headers
diff --git a/content/test/data/attribution_reporting/databases/version_52.sql b/content/test/data/attribution_reporting/databases/version_52.sql index 35a219cfd..2575b64 100644 --- a/content/test/data/attribution_reporting/databases/version_52.sql +++ b/content/test/data/attribution_reporting/databases/version_52.sql
@@ -44,4 +44,8 @@ CREATE INDEX rate_limit_source_id_idx ON rate_limits(source_id); +INSERT INTO sources VALUES +(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 0,17,18), +(2,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 200,17,18); + COMMIT;
diff --git a/content/test/data/attribution_reporting/databases/version_53.sql b/content/test/data/attribution_reporting/databases/version_53.sql new file mode 100644 index 0000000..c527e4b --- /dev/null +++ b/content/test/data/attribution_reporting/databases/version_53.sql
@@ -0,0 +1,47 @@ +PRAGMA foreign_keys=OFF; + +BEGIN TRANSACTION; + +CREATE TABLE sources(source_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,source_event_id INTEGER NOT NULL,source_origin TEXT NOT NULL,reporting_origin TEXT NOT NULL,source_time INTEGER NOT NULL,expiry_time INTEGER NOT NULL,event_report_window_time INTEGER NOT NULL,aggregatable_report_window_time INTEGER NOT NULL,num_attributions INTEGER NOT NULL,event_level_active INTEGER NOT NULL,aggregatable_active INTEGER NOT NULL,source_type INTEGER NOT NULL,attribution_logic INTEGER NOT NULL,priority INTEGER NOT NULL,source_site TEXT NOT NULL,debug_key INTEGER,aggregatable_budget_consumed INTEGER NOT NULL,num_aggregatable_reports INTEGER NOT NULL,aggregatable_source BLOB NOT NULL,filter_data BLOB NOT NULL); + +CREATE TABLE reports(report_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,source_id INTEGER NOT NULL,trigger_time INTEGER NOT NULL,report_time INTEGER NOT NULL,initial_report_time INTEGER NOT NULL,failed_send_attempts INTEGER NOT NULL,external_report_id TEXT NOT NULL,debug_key INTEGER,context_origin TEXT NOT NULL,reporting_origin TEXT NOT NULL,report_type INTEGER NOT NULL,metadata BLOB NOT NULL); + +CREATE TABLE rate_limits(id INTEGER PRIMARY KEY NOT NULL,scope INTEGER NOT NULL,source_id INTEGER NOT NULL,source_site TEXT NOT NULL,destination_site TEXT NOT NULL,context_origin TEXT NOT NULL,reporting_origin TEXT NOT NULL,time INTEGER NOT NULL,source_expiry_or_attribution_time INTEGER NOT NULL); + +CREATE TABLE dedup_keys(source_id INTEGER NOT NULL,report_type INTEGER NOT NULL,dedup_key INTEGER NOT NULL,PRIMARY KEY(source_id,report_type,dedup_key))WITHOUT ROWID; + +CREATE TABLE source_destinations(source_id INTEGER NOT NULL,destination_site TEXT NOT NULL,PRIMARY KEY(source_id,destination_site))WITHOUT ROWID; + +CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR); + +INSERT INTO meta VALUES('mmap_status','-1'); +INSERT INTO meta VALUES('version','53'); +INSERT INTO meta VALUES('last_compatible_version','53'); + +CREATE INDEX sources_by_active_reporting_origin ON sources(event_level_active,aggregatable_active,reporting_origin); + +CREATE INDEX sources_by_expiry_time ON sources(expiry_time); + +CREATE INDEX active_sources_by_source_origin ON sources(source_origin)WHERE event_level_active=1 OR aggregatable_active=1; + +CREATE INDEX sources_by_source_time ON sources(source_time); + +CREATE INDEX sources_by_destination_site ON source_destinations(destination_site); + +CREATE INDEX reports_by_report_time ON reports(report_time); + +CREATE INDEX reports_by_source_id_report_type ON reports(source_id,report_type); + +CREATE INDEX reports_by_trigger_time ON reports(trigger_time); + +CREATE INDEX reports_by_reporting_origin ON reports(reporting_origin)WHERE report_type=2; + +CREATE INDEX rate_limit_source_site_reporting_origin_idx ON rate_limits(scope,source_site,reporting_origin); + +CREATE INDEX rate_limit_reporting_origin_idx ON rate_limits(scope,destination_site,source_site); + +CREATE INDEX rate_limit_time_idx ON rate_limits(time); + +CREATE INDEX rate_limit_source_id_idx ON rate_limits(source_id); + +COMMIT;
diff --git a/content/test/data/attribution_reporting/inject_cross_app_web_third_party_ot.js b/content/test/data/attribution_reporting/inject_cross_app_web_third_party_ot.js new file mode 100644 index 0000000..45a1ac3 --- /dev/null +++ b/content/test/data/attribution_reporting/inject_cross_app_web_third_party_ot.js
@@ -0,0 +1,12 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Generate this token with the command: +// generate_token.py https://example.test AttributionReportingCrossAppWeb --version 3 --is-third-party --expire-timestamp=2000000000 +const THIRD_PARTY_TOKEN = 'A+cJoNlsxau5JGnEnXUU0f7TmKP8mI3UpBw12FRx4uphGMl2K4BCx4wVNV7t6nHtb2LsiCyTXWMM+Lg8ub2hzQIAAACAeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLnRlc3Q6NDQzIiwgImZlYXR1cmUiOiAiQXR0cmlidXRpb25SZXBvcnRpbmdDcm9zc0FwcFdlYiIsICJleHBpcnkiOiAyMDAwMDAwMDAwLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZX0='; + +const tokenElement = document.createElement('meta'); +tokenElement.httpEquiv = 'origin-trial'; +tokenElement.content = THIRD_PARTY_TOKEN; +document.head.appendChild(tokenElement);
diff --git a/content/test/data/attribution_reporting/page_with_cross_app_web_third_party_ot.html b/content/test/data/attribution_reporting/page_with_cross_app_web_third_party_ot.html new file mode 100644 index 0000000..aeca85b0 --- /dev/null +++ b/content/test/data/attribution_reporting/page_with_cross_app_web_third_party_ot.html
@@ -0,0 +1,5 @@ +<html> +<head> + <script src="https://example.test/inject_cross_app_web_third_party_ot.js"></script> +</head> +</html> \ No newline at end of file
diff --git a/content/test/fenced_frame_test_utils.cc b/content/test/fenced_frame_test_utils.cc index 6e1f9c6..d358fdd 100644 --- a/content/test/fenced_frame_test_utils.cc +++ b/content/test/fenced_frame_test_utils.cc
@@ -4,11 +4,16 @@ #include "content/test/fenced_frame_test_utils.h" +#include "base/location.h" #include "base/memory/ref_counted.h" +#include "base/run_loop.h" +#include "base/test/test_timeouts.h" +#include "base/time/time.h" #include "content/browser/fenced_frame/fenced_frame.h" #include "content/browser/fenced_frame/fenced_frame_reporter.h" #include "content/browser/renderer_host/frame_tree_node.h" #include "content/browser/renderer_host/render_frame_host_impl.h" +#include "content/public/test/browser_test_utils.h" #include "content/public/test/test_frame_navigation_observer.h" #include "third_party/blink/public/common/features.h" @@ -92,12 +97,27 @@ DCHECK(fenced_frame_url_mapping_->IsFull()); } -bool WaitForFencedFrameSizeFreeze(RenderFrameHost* rfh) { - // Currently we observed that the size freezing requires two - // `requestAnimationFrame` calls to make sure it is completed. If only calling - // `requestAnimationFrame` once, the test can still be flaky. - return EvalJsAfterLifecycleUpdate(rfh, "", "").error.empty() && - EvalJsAfterLifecycleUpdate(rfh, "", "").error.empty(); +bool PollUntilEvalToTrue(const std::string& script, RenderFrameHost* rfh) { + base::Time start_time = base::Time::Now(); + base::TimeDelta timeout = TestTimeouts::action_max_timeout(); + + while (base::Time::Now() - start_time < timeout) { + EvalJsResult result = EvalJs(rfh, script); + + if (!result.error.empty()) { + return false; + } else if (result.ExtractBool()) { + return true; + } + + // Wait for a bit here to keep this loop from spinlocking too badly. + base::RunLoop run_loop; + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); + run_loop.Run(); + } + + return false; } } // namespace content
diff --git a/content/test/fenced_frame_test_utils.h b/content/test/fenced_frame_test_utils.h index 2caec6d..38ffdfc 100644 --- a/content/test/fenced_frame_test_utils.h +++ b/content/test/fenced_frame_test_utils.h
@@ -121,9 +121,11 @@ // TODO(xiaochenzh): Once fenced frame size freezing has no time gap, remove // this. -// This function is needed because the freezing only takes effect after layout -// has happened. -bool WaitForFencedFrameSizeFreeze(RenderFrameHost* rfh); +// This function keeps polling the evaluation result of the given script until +// it returns true or times out. +// Currently this is only used to check the fenced frame size freezing behavior. +// The size freezing only takes effect after layout has happened. +bool PollUntilEvalToTrue(const std::string& script, RenderFrameHost* rfh); } // namespace content
diff --git a/content/test/gpu/run_pytype.py b/content/test/gpu/run_pytype.py index 9de2dcf..c7902bf 100755 --- a/content/test/gpu/run_pytype.py +++ b/content/test/gpu/run_pytype.py
@@ -34,10 +34,13 @@ EXTRA_PATHS.append(GPU_DIR) FILES_AND_DIRECTORIES_TO_CHECK = [ + # Directories. 'flake_suppressor', 'gold_inexact_matching', 'gpu_tests', 'unexpected_passes', + # Files. + 'unexpected_pass_finder.py', ] FILES_AND_DIRECTORIES_TO_CHECK = [ os.path.join(GPU_DIR, f) for f in FILES_AND_DIRECTORIES_TO_CHECK
diff --git a/content/test/gpu/unexpected_pass_finder.py b/content/test/gpu/unexpected_pass_finder.py index 341b9909..faac81d 100755 --- a/content/test/gpu/unexpected_pass_finder.py +++ b/content/test/gpu/unexpected_pass_finder.py
@@ -35,10 +35,19 @@ """ import argparse +import importlib +import inspect +import logging import os +import pkgutil +from typing import Dict, Type +import gpu_path_util +from gpu_path_util import setup_telemetry_paths # pylint: disable=unused-import from gpu_path_util import setup_testing_paths # pylint: disable=unused-import +from gpu_tests import gpu_integration_test + from unexpected_passes import gpu_builders from unexpected_passes import gpu_expectations from unexpected_passes import gpu_queries @@ -47,13 +56,43 @@ from unexpected_passes_common import expectations from unexpected_passes_common import result_output -SUITE_TO_EXPECTATIONS_MAP = { - 'power': 'power_measurement', - 'webgl1_conformance': 'webgl_conformance', -} + +def _GenerateTestNameMapping( +) -> Dict[str, Type[gpu_integration_test.GpuIntegrationTest]]: + """Generates a mapping from suite name to class. + + Returns: + A dict mapping a suite's human-readable name to the class that implements + it. + """ + mapping = {} + for p in pkgutil.iter_modules( + [os.path.join(gpu_path_util.GPU_DIR, 'gpu_tests')]): + if p.ispkg: + continue + module_name = 'gpu_tests.' + p.name + try: + module = importlib.import_module(module_name) + except ImportError: + logging.warning( + 'Unable to import module %s. This is likely due to stale .pyc files ' + 'existing on disk.', module_name) + continue + for name, obj in inspect.getmembers(module): + # Look for cases of GpuIntegrationTest that have Name() overridden. The + # name check filters out base classes. + if (inspect.isclass(obj) + and issubclass(obj, gpu_integration_test.GpuIntegrationTest) + and obj.Name() != name): + mapping[obj.Name()] = obj + return mapping -def ParseArgs(): +def ParseArgs() -> argparse.Namespace: + name_mapping = _GenerateTestNameMapping() + test_suites = list(name_mapping.keys()) + test_suites.sort() + parser = argparse.ArgumentParser( description=('Script for finding cases of stale expectations that can ' 'be removed/modified.')) @@ -73,47 +112,35 @@ help='The name of a test to check for unexpected passes. Can be passed ' 'multiple times to specify multiple tests. Will be treated as if it was ' 'expected to be flaky on all configurations.') - parser.add_argument( - '--suite', - required=True, - # Could probably autogenerate this list using the same - # method as Telemetry's run_browser_tests.py now that WebGL 1 and 2 are - # properly split. - choices=[ - 'context_lost', - 'hardware_accelerated_feature', - 'gpu_process', - 'info_collection', - 'maps', - 'mediapipe', - 'pixel', - 'power', - 'screenshot_sync', - 'trace_test', - 'webcodecs', - 'webgl1_conformance', - 'webgl2_conformance', - ], - help='The test suite being checked.') + parser.add_argument('--suite', + required=True, + choices=test_suites, + help='The test suite being checked.') args = parser.parse_args() argument_parsing.PerformCommonPostParseSetup(args) if not (args.tests or args.expectation_file): - args.expectation_file = os.path.join( - os.path.dirname(__file__), 'gpu_tests', 'test_expectations', - '%s_expectations.txt' % - SUITE_TO_EXPECTATIONS_MAP.get(args.suite, args.suite)) + expectation_files = name_mapping[args.suite].ExpectationsFiles() + if not expectation_files: + raise RuntimeError( + 'Suite %s does not specify an expectation file and is thus not ' + 'compatible with this script.' % args.suite) + if len(expectation_files) > 1: + raise RuntimeError( + 'Suite %s specifies %d expectation files when only 1 is supported.' % + len(expectation_files)) + args.expectation_file = expectation_files[0] if args.remove_stale_expectations and not args.expectation_file: - raise argparse.ArgumentError('--remove-stale-expectations', - 'Can only be used with expectation files') + parser.error( + '--remove-stale-expectations can only be used with expectation files') return args # pylint: disable=too-many-locals -def main(): +def main() -> None: args = ParseArgs() builders_instance = gpu_builders.GpuBuilders(args.suite,
diff --git a/device/bluetooth/floss/bluetooth_remote_gatt_characteristic_floss.cc b/device/bluetooth/floss/bluetooth_remote_gatt_characteristic_floss.cc index c8f847d1..aa6d862 100644 --- a/device/bluetooth/floss/bluetooth_remote_gatt_characteristic_floss.cc +++ b/device/bluetooth/floss/bluetooth_remote_gatt_characteristic_floss.cc
@@ -180,6 +180,10 @@ return; } + if (num_of_reads_in_progress_ == 0 || !pending_read_callback_) { + return; + } + --num_of_reads_in_progress_; DCHECK_GE(num_of_reads_in_progress_, 0);
diff --git a/docs/android_build_instructions.md b/docs/android_build_instructions.md index 515fae9..d219ea3 100644 --- a/docs/android_build_instructions.md +++ b/docs/android_build_instructions.md
@@ -179,22 +179,21 @@ ### Multiple Chrome Targets -The Google Play Store allows apps to send customized `.apk` or `.aab` files +The Google Play Store allows apps to send customized bundles (`.aab` files) depending on the version of Android running on a device. Chrome uses this feature to package optimized versions for different OS versions. -1. `monochrome_public_bundle` (MonochromePublic.aab) +1. `monochrome_public_bundle` (`MonochromePublic.aab`) * `minSdkVersion=24` (Nougat). * Contains both Chrome and WebView (to save disk space). -2. `trichrome_chrome_bundle` (TrichromeChrome.aab) +2. `trichrome_chrome_bundle` (`TrichromeChrome.aab`) * `minSdkVersion=29` (Android 10). * Native code shared with WebView through a "Static Shared Library APK": `trichrome_library_apk` * Corresponding WebView target: `trichrome_webview_bundle` -3. `chrome_public_apk` (ChromePublic.apk) +3. `chrome_public_bundle` & `chrome_public_apk` (`ChromePublic.aab`, `ChromePublic.apk`) * `minSdkVersion=24` (Nougat). - * WebView packaged independently (`system_webview_apk`). - * Used for only local development and tests (simpler than using bundle - targets). + * Used for local development (to avoid building WebView). + * WebView packaged independently (`system_webview_bundle` / `system_webview_apk`). *** note **Notes:**
diff --git a/docs/security/rules.md b/docs/security/rules.md index 4022e920..050f1f1 100644 --- a/docs/security/rules.md +++ b/docs/security/rules.md
@@ -14,6 +14,7 @@ * [Controlling access to powerful web platform features](permissions-for-powerful-web-platform-features.md) * [Security considerations for browser UI](security-considerations-for-browser-ui.md) +* [Guidelines for URL display](url_display_guidelines/url_display_guidelines.md) You can also find our position on various matters in the [security FAQ](faq.md): for example, on local attackers or on the privilege accorded to enterprise
diff --git a/docs/ui/learn/bestpractices/colors.md b/docs/ui/learn/bestpractices/colors.md index d3349a7..2866be3 100644 --- a/docs/ui/learn/bestpractices/colors.md +++ b/docs/ui/learn/bestpractices/colors.md
@@ -117,7 +117,7 @@ **Best practice** -The [current version](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/file_system_access/file_system_access_usage_bubble_view.cc;l=196;drc=532834e1da3874a57dde3ed76511f53b8eb8ecdf) +The [current version](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/views/file_system_access/file_system_access_usage_bubble_view.cc?q=symbol%3A%5CbCollapsibleListView%3A%3AOnThemeChanged%5Cb%20case%3Ayes) moves this to `OnThemeChanged()` and thus handles theme changes correctly: |||---||| @@ -132,6 +132,7 @@ ... auto button = views::CreateVectorToggleImageButton(this); + ... @@ -170,16 +171,21 @@ void CollapsibleListView::OnThemeChanged() { views::View::OnThemeChanged(); - const SkColor icon_color = - GetColorProvider()->GetColor(ui::kColorIcon); - - + const auto* color_provider = GetColorProvider(); + const SkColor icon_color = + color_provider->GetColor(ui::kColorIcon); + const SkColor disabled_icon_color = + color_provider->GetColor(ui::kColorIconDisabled); views::SetImageFromVectorIconWithColor( - expand_collapse_button_, kCaretDownIcon, - ui::TableModel::kIconSize, icon_color); + expand_collapse_button_, + vector_icons::kCaretDownIcon, + ui::TableModel::kIconSize, icon_color, + disabled_icon_color); views::SetToggledImageFromVectorIconWithColor( - expand_collapse_button_, kCaretUpIcon, - ui::TableModel::kIconSize, icon_color); + expand_collapse_button_, + vector_icons::kCaretUpIcon, + ui::TableModel::kIconSize, icon_color, + disabled_icon_color); } ``` @@ -331,7 +337,7 @@ **Best practice** -[Current version](https://source.chromium.org/chromium/chromium/src/+/main:ui/views/controls/menu/submenu_view.cc;l=229;drc=7910ceae672184033abc44a287e309f14e664b5e) +[Current version](https://source.chromium.org/chromium/chromium/src/+/main:ui/views/controls/menu/submenu_view.cc;drc=69982e42da25a60eba54c7c88e97577f7cf67fd2;l=233) defines these as distinct logical colors with the same default physical color, better accommodating platforms where menu text and menu icons may differ: @@ -389,11 +395,11 @@ const PaintInfo& paint_info) { ... const SkColor drop_indicator_color = - GetNativeTheme()->GetSystemColor( - ui::NativeTheme:: - kColorId_MenuDropIndicator); + GetColorProvider()->GetColor( + ui::kColorMenuDropmarker); recorder.canvas()->FillRect( bounds, drop_indicator_color); + ... } ``` @@ -574,7 +580,7 @@ ##### ``` -class [TabStripPageHandler](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.h;drc=beeec6c4e2ef41bca3182279155079a1c4dcb06d;l=29) : public tab_strip::mojom::PageHandler, +class TabStripPageHandler : public tab_strip::mojom::PageHandler, public TabStripModelObserver, public content::WebContentsDelegate, public ThemeServiceObserver, @@ -585,7 +591,7 @@ ... } -void [TabStripPageHandler::GetThemeColors](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/webui/tab_strip/tab_strip_page_handler.cc;drc=bf9500afcb08e7dfaec3cf4f52e00618ab663ec9;l=594)( +void TabStripPageHandler::GetThemeColors( GetThemeColorsCallback callback) { // This should return an object of CSS variables to rgba values so that // the WebUI can use the CSS variables to color the tab strip @@ -641,7 +647,7 @@ ... -bool [HistoryMenuBridge::AddGroupEntryToMenu](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/cocoa/history_menu_bridge.mm;drc=eb8341716b8bf349823849aae4dac3d9a7f83f13;l=320)( +bool HistoryMenuBridge::AddGroupEntryToMenu( sessions::TabRestoreService::Group* group, NSMenu* menu, NSInteger tag, @@ -682,7 +688,7 @@ } // namespace webui -void [NTPResourceCache::CreateNewTabIncognitoCSS](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/webui/ntp/ntp_resource_cache.cc;drc=29361d558ea9ffc6053f437de14cb20fd8c9e3c6;l=421)( +void NTPResourceCache::CreateNewTabIncognitoCSS( const content::WebContents::Getter& wc_getter) { auto* web_contents = wc_getter.Run(); const ui::NativeTheme* native_theme = webui::GetNativeTheme(web_contents);
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc index 837136c..c1b6a25b 100644 --- a/extensions/browser/extension_function_dispatcher.cc +++ b/extensions/browser/extension_function_dispatcher.cc
@@ -19,8 +19,6 @@ #include "base/metrics/histogram_macros.h" #include "base/process/process.h" #include "base/scoped_observation.h" -#include "base/trace_event/typed_macros.h" -#include "base/tracing/protos/chrome_track_event.pbzero.h" #include "base/values.h" #include "build/build_config.h" #include "content/public/browser/browser_thread.h" @@ -49,14 +47,12 @@ #include "extensions/common/extension_messages.h" #include "extensions/common/extension_set.h" #include "extensions/common/extension_urls.h" -#include "extensions/common/trace_util.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_macros.h" #include "mojo/public/cpp/bindings/message.h" #include "third_party/abseil-cpp/absl/types/optional.h" using content::BrowserThread; -using perfetto::protos::pbzero::ChromeTrackEvent; namespace extensions { namespace { @@ -398,17 +394,12 @@ mojom::RequestParamsPtr params, content::RenderFrameHost& frame, mojom::LocalFrameHost::RequestCallback callback) { - content::RenderProcessHost& process = *frame.GetProcess(); - TRACE_EVENT("extensions", "ExtensionFunctionDispatcher::Dispatch", - ChromeTrackEvent::kRenderProcessHost, process, - ChromeTrackEvent::kChromeExtensionId, - ExtensionIdForTracing(params->extension_id)); - ScopedRequestParamsCrashKeys request_params_crash_keys(*params); SCOPED_CRASH_KEY_STRING256( "extensions", "frame.GetSiteInstance()", frame.GetSiteInstance()->GetSiteURL().possibly_invalid_spec()); + content::RenderProcessHost& process = *frame.GetProcess(); if (auto bad_message_code = ValidateRequest(*params, &frame, process)) { // Kill the renderer if it's an invalid request. bad_message::ReceivedBadMessage(&process, *bad_message_code); @@ -448,11 +439,6 @@ if (!rph) return; - TRACE_EVENT("extensions", - "ExtensionFunctionDispatcher::DispatchForServiceWorker", - ChromeTrackEvent::kRenderProcessHost, *rph, - ChromeTrackEvent::kChromeExtensionId, - ExtensionIdForTracing(params->extension_id)); if (auto bad_message_code = ValidateRequest(*params, nullptr, *rph)) { // Kill the renderer if it's an invalid request. bad_message::ReceivedBadMessage(render_process_id, *bad_message_code);
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index e3693ce..3c9c30d7 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1847,6 +1847,7 @@ ENTERPRISE_REMOTEAPPS_SETPINNEDAPPS = 1784, SMARTCARDPROVIDERPRIVATE_REPORTDATARESULT = 1785, FILEMANAGERPRIVATE_CALCULATEBULKPINREQUIREDSPACE = 1786, + AUTOFILLPRIVATE_AUTHENTICATEUSERANDFLIPMANDATORYAUTHTOGGLE = 1787, // Last entry: Add new entries above, then run: // tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/common/api/offscreen.idl b/extensions/common/api/offscreen.idl index f9ae4672..b797a99b 100644 --- a/extensions/common/api/offscreen.idl +++ b/extensions/common/api/offscreen.idl
@@ -25,7 +25,7 @@ // media (e.g. <code>getUserMedia()</code>). USER_MEDIA, // The offscreen document needs to interact with media streams from display - // media (e.g. <code>getDisplayMedia()</code). + // media (e.g. <code>getDisplayMedia()</code>). DISPLAY_MEDIA, // The offscreen document needs to use WebRTC APIs. WEB_RTC,
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc index cda54873..5c04c65 100644 --- a/extensions/renderer/native_extension_bindings_system.cc +++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -11,11 +11,8 @@ #include "base/functional/callback.h" #include "base/strings/string_piece.h" #include "base/strings/stringprintf.h" -#include "base/trace_event/typed_macros.h" -#include "base/tracing/protos/chrome_track_event.pbzero.h" #include "components/crx_file/id_util.h" #include "content/public/common/content_switches.h" -#include "content/public/renderer/render_thread.h" #include "extensions/common/constants.h" #include "extensions/common/context_type_adapter.h" #include "extensions/common/extension_api.h" @@ -27,7 +24,6 @@ #include "extensions/common/manifest_handlers/externally_connectable.h" #include "extensions/common/mojom/event_dispatcher.mojom.h" #include "extensions/common/mojom/frame.mojom.h" -#include "extensions/common/trace_util.h" #include "extensions/renderer/api/declarative_content_hooks_delegate.h" #include "extensions/renderer/api/dom_hooks_delegate.h" #include "extensions/renderer/api/feedback_private_hooks_delegate.h" @@ -68,8 +64,6 @@ #include "v8/include/v8-primitive.h" #include "v8/include/v8-template.h" -using perfetto::protos::pbzero::ChromeTrackEvent; - namespace extensions { namespace { @@ -851,11 +845,6 @@ << "Attempting to send a request from an unspecified context type. " << "Request: " << request->method_name << ", Context: " << script_context->GetDebugString(); - TRACE_EVENT("extensions", "NativeExtensionBindingsSystem::SendRequest", - ChromeTrackEvent::kRenderProcessHost, - *content::RenderThread::Get(), - ChromeTrackEvent::kChromeExtensionId, - ExtensionIdForTracing(script_context->GetExtensionID())); GURL url; blink::WebLocalFrame* frame = script_context->web_frame();
diff --git a/google_apis/classroom/BUILD.gn b/google_apis/classroom/BUILD.gn index 1ee6d73..dc1bb2e 100644 --- a/google_apis/classroom/BUILD.gn +++ b/google_apis/classroom/BUILD.gn
@@ -18,6 +18,10 @@ "classroom_api_list_course_work_request.h", "classroom_api_list_courses_request.cc", "classroom_api_list_courses_request.h", + "classroom_api_list_student_submissions_request.cc", + "classroom_api_list_student_submissions_request.h", + "classroom_api_student_submissions_response_types.cc", + "classroom_api_student_submissions_response_types.h", ] deps = [ @@ -37,6 +41,8 @@ "classroom_api_courses_response_types_unittest.cc", "classroom_api_list_course_work_request_unittest.cc", "classroom_api_list_courses_request_unittest.cc", + "classroom_api_list_student_submissions_request_unittest.cc", + "classroom_api_student_submissions_response_types_unittest.cc", ] deps = [
diff --git a/google_apis/classroom/classroom_api_list_student_submissions_request.cc b/google_apis/classroom/classroom_api_list_student_submissions_request.cc new file mode 100644 index 0000000..bb8e537a --- /dev/null +++ b/google_apis/classroom/classroom_api_list_student_submissions_request.cc
@@ -0,0 +1,113 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "google_apis/classroom/classroom_api_list_student_submissions_request.h" + +#include "base/check.h" +#include "base/files/file_path.h" +#include "base/functional/bind.h" +#include "base/strings/string_util.h" +#include "base/types/expected.h" +#include "base/values.h" +#include "google_apis/classroom/classroom_api_student_submissions_response_types.h" +#include "google_apis/common/api_error_codes.h" +#include "google_apis/common/base_requests.h" +#include "google_apis/gaia/gaia_urls.h" +#include "net/base/url_util.h" + +namespace google_apis::classroom { +namespace { + +constexpr char kListStudentSubmissionsUrlTemplate[] = + "/v1/courses/$1/courseWork/$2/studentSubmissions"; + +constexpr char kFieldsParameterName[] = "fields"; +constexpr char kRequestedFields[] = + "studentSubmissions(id,courseWorkId,state,assignedGrade),nextPageToken"; + +constexpr char kPageTokenParameterName[] = "pageToken"; + +std::unique_ptr<StudentSubmissions> ParseResponse(std::string json) { + std::unique_ptr<base::Value> raw_value = ParseJson(json); + return raw_value ? StudentSubmissions::CreateFrom(*raw_value) : nullptr; +} + +} // namespace + +ListStudentSubmissionsRequest::ListStudentSubmissionsRequest( + RequestSender* sender, + const std::string& course_id, + const std::string& course_work_id, + const std::string& page_token, + Callback callback) + : UrlFetchRequestBase(sender, ProgressCallback(), ProgressCallback()), + course_id_(course_id), + course_work_id_(course_work_id), + page_token_(page_token), + callback_(std::move(callback)) { + CHECK(!course_id.empty()); + CHECK(!course_work_id.empty()); + CHECK(!callback_.is_null()); +} + +ListStudentSubmissionsRequest::~ListStudentSubmissionsRequest() = default; + +GURL ListStudentSubmissionsRequest::GetURL() const { + auto url = GaiaUrls::GetInstance()->classroom_api_origin_url().Resolve( + base::ReplaceStringPlaceholders(kListStudentSubmissionsUrlTemplate, + {course_id_, course_work_id_}, nullptr)); + url = net::AppendOrReplaceQueryParameter(url, kFieldsParameterName, + kRequestedFields); + if (!page_token_.empty()) { + url = net::AppendOrReplaceQueryParameter(url, kPageTokenParameterName, + page_token_); + } + return url; +} + +ApiErrorCode ListStudentSubmissionsRequest::MapReasonToError( + ApiErrorCode code, + const std::string& reason) { + return code; +} + +bool ListStudentSubmissionsRequest::IsSuccessfulErrorCode(ApiErrorCode error) { + return error == HTTP_SUCCESS; +} + +void ListStudentSubmissionsRequest::ProcessURLFetchResults( + const network::mojom::URLResponseHead* response_head, + base::FilePath response_file, + std::string response_body) { + ApiErrorCode error = GetErrorCode(); + switch (error) { + case HTTP_SUCCESS: + blocking_task_runner()->PostTaskAndReplyWithResult( + FROM_HERE, base::BindOnce(&ParseResponse, std::move(response_body)), + base::BindOnce(&ListStudentSubmissionsRequest::OnDataParsed, + weak_ptr_factory_.GetWeakPtr())); + break; + default: + RunCallbackOnPrematureFailure(error); + OnProcessURLFetchResultsComplete(); + break; + } +} + +void ListStudentSubmissionsRequest::RunCallbackOnPrematureFailure( + ApiErrorCode error) { + std::move(callback_).Run(base::unexpected(error)); +} + +void ListStudentSubmissionsRequest::OnDataParsed( + std::unique_ptr<StudentSubmissions> submissions) { + if (!submissions) { + std::move(callback_).Run(base::unexpected(PARSE_ERROR)); + } else { + std::move(callback_).Run(std::move(submissions)); + } + OnProcessURLFetchResultsComplete(); +} + +} // namespace google_apis::classroom
diff --git a/google_apis/classroom/classroom_api_list_student_submissions_request.h b/google_apis/classroom/classroom_api_list_student_submissions_request.h new file mode 100644 index 0000000..e77ec5b8 --- /dev/null +++ b/google_apis/classroom/classroom_api_list_student_submissions_request.h
@@ -0,0 +1,84 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GOOGLE_APIS_CLASSROOM_CLASSROOM_API_LIST_STUDENT_SUBMISSIONS_REQUEST_H_ +#define GOOGLE_APIS_CLASSROOM_CLASSROOM_API_LIST_STUDENT_SUBMISSIONS_REQUEST_H_ + +#include <memory> +#include <string> + +#include "base/functional/callback_forward.h" +#include "base/memory/weak_ptr.h" +#include "base/types/expected.h" +#include "google_apis/common/base_requests.h" + +class GURL; + +namespace base { +class FilePath; +} // namespace base + +namespace network::mojom { +class URLResponseHead; +} // namespace network::mojom + +namespace google_apis { + +enum ApiErrorCode; +class RequestSender; + +namespace classroom { + +class StudentSubmissions; + +// Returns a list of student submissions for the corresponding course work. +// `course_id` - identifier of the course. +// `course_work_id` - identifier of the student work to request. +// `page_token` - token specifying the result page to return. +// Use an empty string to fetch the first page. +// `callback` - done callback. +// https://developers.google.com/classroom/reference/rest/v1/courses.courseWork.studentSubmissions/list +class ListStudentSubmissionsRequest : public UrlFetchRequestBase { + public: + using Callback = base::OnceCallback<void( + base::expected<std::unique_ptr<StudentSubmissions>, ApiErrorCode> + result)>; + + ListStudentSubmissionsRequest(RequestSender* sender, + const std::string& course_id, + const std::string& course_work_id, + const std::string& page_token, + Callback callback); + ListStudentSubmissionsRequest(const ListStudentSubmissionsRequest&) = delete; + ListStudentSubmissionsRequest& operator=( + const ListStudentSubmissionsRequest&) = delete; + ~ListStudentSubmissionsRequest() override; + + protected: + // UrlFetchRequestBase: + GURL GetURL() const override; + ApiErrorCode MapReasonToError(ApiErrorCode code, + const std::string& reason) override; + bool IsSuccessfulErrorCode(ApiErrorCode error) override; + void ProcessURLFetchResults( + const network::mojom::URLResponseHead* response_head, + const base::FilePath response_file, + std::string response_body) override; + void RunCallbackOnPrematureFailure(ApiErrorCode code) override; + + private: + void OnDataParsed(std::unique_ptr<StudentSubmissions> submissions); + + const std::string course_id_; + const std::string course_work_id_; + const std::string page_token_; + Callback callback_; + + base::WeakPtrFactory<ListStudentSubmissionsRequest> weak_ptr_factory_{this}; +}; + +} // namespace classroom +} // namespace google_apis + +#endif // GOOGLE_APIS_CLASSROOM_CLASSROOM_API_LIST_STUDENT_SUBMISSIONS_REQUEST_H_
diff --git a/google_apis/classroom/classroom_api_list_student_submissions_request_unittest.cc b/google_apis/classroom/classroom_api_list_student_submissions_request_unittest.cc new file mode 100644 index 0000000..002a82c8 --- /dev/null +++ b/google_apis/classroom/classroom_api_list_student_submissions_request_unittest.cc
@@ -0,0 +1,207 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "google_apis/classroom/classroom_api_list_student_submissions_request.h" + +#include <memory> + +#include "base/command_line.h" +#include "base/memory/scoped_refptr.h" +#include "base/test/task_environment.h" +#include "base/test/test_future.h" +#include "base/types/expected.h" +#include "google_apis/classroom/classroom_api_student_submissions_response_types.h" +#include "google_apis/common/api_error_codes.h" +#include "google_apis/common/dummy_auth_service.h" +#include "google_apis/common/request_sender.h" +#include "google_apis/common/test_util.h" +#include "google_apis/gaia/gaia_urls.h" +#include "google_apis/gaia/gaia_urls_overrider_for_testing.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_request.h" +#include "net/traffic_annotation/network_traffic_annotation_test_helper.h" +#include "services/network/test/test_shared_url_loader_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace google_apis::classroom { +namespace { + +using ::net::test_server::BasicHttpResponse; +using ::net::test_server::HttpMethod; +using ::net::test_server::HttpRequest; +using ::net::test_server::HttpResponse; +using ::testing::AllOf; +using ::testing::ByMove; +using ::testing::Eq; +using ::testing::Field; +using ::testing::Invoke; +using ::testing::Return; + +class TestRequestHandler { + public: + static std::unique_ptr<HttpResponse> CreateSuccessfulResponse() { + auto response = std::make_unique<BasicHttpResponse>(); + response->set_code(net::HTTP_OK); + response->set_content(R"( + { + "studentSubmissions": [ + { + "id": "student-submission-item-1", + "courseWorkId": "course-work-1", + "state": "TURNED_IN", + "assignedGrade": 1.0 + }, + { + "id": "student-submission-item-2", + "courseWorkId": "course-work-1", + "state": "RETURNED" + }, + { + "id": "student-submission-item-3", + "courseWorkId": "course-work-1", + "state": "NEW", + "assignedGrade": 3.3 + } + ] + })"); + response->set_content_type("application/json"); + return response; + } + + static std::unique_ptr<HttpResponse> CreateFailedResponse() { + auto response = std::make_unique<BasicHttpResponse>(); + response->set_code(net::HTTP_INTERNAL_SERVER_ERROR); + return response; + } + + MOCK_METHOD(std::unique_ptr<HttpResponse>, + HandleRequest, + (const HttpRequest&)); +}; + +} // namespace + +class ClassroomApiListStudentSubmissionRequestsTest : public testing::Test { + public: + ClassroomApiListStudentSubmissionRequestsTest() + : test_shared_loader_factory_( + base::MakeRefCounted<network::TestSharedURLLoaderFactory>( + /*network_service=*/nullptr, + /*is_trusted=*/true)) {} + + void SetUp() override { + request_sender_ = std::make_unique<RequestSender>( + std::make_unique<DummyAuthService>(), test_shared_loader_factory_, + task_environment_.GetMainThreadTaskRunner(), "test-user-agent", + TRAFFIC_ANNOTATION_FOR_TESTS); + + test_server_.RegisterRequestHandler( + base::BindRepeating(&TestRequestHandler::HandleRequest, + base::Unretained(&request_handler_))); + ASSERT_TRUE(test_server_.Start()); + + gaia_urls_overrider_ = std::make_unique<GaiaUrlsOverriderForTesting>( + base::CommandLine::ForCurrentProcess(), "classroom_api_origin_url", + test_server_.base_url().spec()); + ASSERT_EQ(GaiaUrls::GetInstance()->classroom_api_origin_url(), + test_server_.base_url().spec()); + } + + TestRequestHandler& request_handler() { return request_handler_; } + RequestSender* request_sender() { return request_sender_.get(); } + + private: + base::test::TaskEnvironment task_environment_{ + base::test::TaskEnvironment::MainThreadType::IO}; + net::EmbeddedTestServer test_server_; + std::unique_ptr<RequestSender> request_sender_; + scoped_refptr<network::TestSharedURLLoaderFactory> + test_shared_loader_factory_; + std::unique_ptr<GaiaUrlsOverriderForTesting> gaia_urls_overrider_; + testing::StrictMock<TestRequestHandler> request_handler_; +}; + +TEST_F(ClassroomApiListStudentSubmissionRequestsTest, + ListStudentSubmissionsRequest) { + EXPECT_CALL( + request_handler(), + HandleRequest(AllOf( + Field(&HttpRequest::method, Eq(HttpMethod::METHOD_GET)), + Field(&HttpRequest::relative_url, + Eq("/v1/courses/course-1/courseWork/course-work-1/" + "studentSubmissions?fields=studentSubmissions(id%2C" + "courseWorkId%2Cstate%2CassignedGrade)%2CnextPageToken"))))) + .WillOnce(Return(ByMove(TestRequestHandler::CreateSuccessfulResponse()))); + + base::test::TestFuture< + base::expected<std::unique_ptr<StudentSubmissions>, ApiErrorCode>> + future; + auto request = std::make_unique<ListStudentSubmissionsRequest>( + request_sender(), /*course_id=*/"course-1", + /*course_work_id=*/"course-work-1", + /*page_token=*/"", future.GetCallback()); + request_sender()->StartRequestWithAuthRetry(std::move(request)); + ASSERT_TRUE(future.Wait()); + + ASSERT_TRUE(future.Get().has_value()); + ASSERT_TRUE(future.Get().value()); + EXPECT_EQ(future.Get().value()->items().size(), 3u); +} + +TEST_F(ClassroomApiListStudentSubmissionRequestsTest, + ListStudentSubmissionsRequestWithAdditionalQueryParamaters) { + EXPECT_CALL( + request_handler(), + HandleRequest( + AllOf(Field(&HttpRequest::method, Eq(HttpMethod::METHOD_GET)), + Field(&HttpRequest::relative_url, + Eq("/v1/courses/course-1/courseWork/course-work-1/" + "studentSubmissions?fields=studentSubmissions(id%2C" + "courseWorkId%2Cstate%2CassignedGrade)%2CnextPageToken" + "&pageToken=qwerty"))))) + .WillOnce(Return(ByMove(TestRequestHandler::CreateSuccessfulResponse()))); + + base::test::TestFuture< + base::expected<std::unique_ptr<StudentSubmissions>, ApiErrorCode>> + future; + auto request = std::make_unique<ListStudentSubmissionsRequest>( + request_sender(), /*course_id=*/"course-1", + /*course_work_id=*/"course-work-1", + /*page_token=*/"qwerty", future.GetCallback()); + request_sender()->StartRequestWithAuthRetry(std::move(request)); + ASSERT_TRUE(future.Wait()); + + ASSERT_TRUE(future.Get().has_value()); + ASSERT_TRUE(future.Get().value()); + EXPECT_EQ(future.Get().value()->items().size(), 3u); +} + +TEST_F(ClassroomApiListStudentSubmissionRequestsTest, + ListStudentSubmissionsRequestHandlesError) { + EXPECT_CALL( + request_handler(), + HandleRequest(AllOf( + Field(&HttpRequest::method, Eq(HttpMethod::METHOD_GET)), + Field(&HttpRequest::relative_url, + Eq("/v1/courses/course-1/courseWork/course-work-1/" + "studentSubmissions?fields=studentSubmissions(id%2C" + "courseWorkId%2Cstate%2CassignedGrade)%2CnextPageToken"))))) + .WillOnce(Return(ByMove(TestRequestHandler::CreateFailedResponse()))); + + base::test::TestFuture< + base::expected<std::unique_ptr<StudentSubmissions>, ApiErrorCode>> + future; + auto request = std::make_unique<ListStudentSubmissionsRequest>( + request_sender(), /*course_id=*/"course-1", + /*course_work_id=*/"course-work-1", + /*page_token=*/"", future.GetCallback()); + request_sender()->StartRequestWithAuthRetry(std::move(request)); + ASSERT_TRUE(future.Wait()); + + ASSERT_FALSE(future.Get().has_value()); + EXPECT_EQ(future.Get().error(), HTTP_INTERNAL_SERVER_ERROR); +} + +} // namespace google_apis::classroom
diff --git a/google_apis/classroom/classroom_api_student_submissions_response_types.cc b/google_apis/classroom/classroom_api_student_submissions_response_types.cc new file mode 100644 index 0000000..4abe246 --- /dev/null +++ b/google_apis/classroom/classroom_api_student_submissions_response_types.cc
@@ -0,0 +1,93 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "google_apis/classroom/classroom_api_student_submissions_response_types.h" + +#include "base/json/json_value_converter.h" +#include "google_apis/common/parser_util.h" + +namespace google_apis::classroom { +namespace { + +constexpr char kApiResponseStudentSubmissionsItemsKey[] = "studentSubmissions"; +constexpr char kApiResponseStudentSubmissionCourseWorkIdKey[] = "courseWorkId"; +constexpr char kApiResponseStudentSubmissionStateKey[] = "state"; +constexpr char kApiResponseStudentSubmissionAssignedGradeKey[] = + "assignedGrade"; + +constexpr char kNewStudentSubmissionState[] = "NEW"; +constexpr char kCreatedStudentSubmissionState[] = "CREATED"; +constexpr char kTurnedInStudentSubmissionState[] = "TURNED_IN"; +constexpr char kReturnedStudentSubmissionState[] = "RETURNED"; +constexpr char kReclaimedStudentSubmissionState[] = "RECLAIMED_BY_STUDENT"; + +bool ConvertStudentSubmissionState(base::StringPiece input, + StudentSubmission::State* output) { + if (input == kNewStudentSubmissionState) { + *output = StudentSubmission::State::kNew; + } else if (input == kCreatedStudentSubmissionState) { + *output = StudentSubmission::State::kCreated; + } else if (input == kTurnedInStudentSubmissionState) { + *output = StudentSubmission::State::kTurnedIn; + } else if (input == kReturnedStudentSubmissionState) { + *output = StudentSubmission::State::kReturned; + } else if (input == kReclaimedStudentSubmissionState) { + *output = StudentSubmission::State::kReclaimedByStudent; + } else { + *output = StudentSubmission::State::kOther; + } + return true; +} + +bool ConvertAssignedGrade(const base::Value* input, + absl::optional<double>* assigned_grade) { + *assigned_grade = input->GetIfDouble(); + return true; +} + +} // namespace + +// ----- StudentSubmission ----- + +// static +void StudentSubmission::RegisterJSONConverter( + base::JSONValueConverter<StudentSubmission>* converter) { + converter->RegisterStringField(kApiResponseIdKey, &StudentSubmission::id_); + converter->RegisterStringField(kApiResponseStudentSubmissionCourseWorkIdKey, + &StudentSubmission::course_work_id_); + converter->RegisterCustomField<StudentSubmission::State>( + kApiResponseStudentSubmissionStateKey, &StudentSubmission::state_, + &ConvertStudentSubmissionState); + converter->RegisterCustomValueField<absl::optional<double>>( + kApiResponseStudentSubmissionAssignedGradeKey, + &StudentSubmission::assigned_grade_, &ConvertAssignedGrade); +} + +// ----- StudentSubmissions ----- + +StudentSubmissions::StudentSubmissions() = default; + +StudentSubmissions::~StudentSubmissions() = default; + +// static +void StudentSubmissions::RegisterJSONConverter( + base::JSONValueConverter<StudentSubmissions>* converter) { + converter->RegisterRepeatedMessage<StudentSubmission>( + kApiResponseStudentSubmissionsItemsKey, &StudentSubmissions::items_); + converter->RegisterStringField(kApiResponseNextPageTokenKey, + &StudentSubmissions::next_page_token_); +} + +// static +std::unique_ptr<StudentSubmissions> StudentSubmissions::CreateFrom( + const base::Value& value) { + auto submissions = std::make_unique<StudentSubmissions>(); + base::JSONValueConverter<StudentSubmissions> converter; + if (!converter.Convert(value, submissions.get())) { + return nullptr; + } + return submissions; +} + +} // namespace google_apis::classroom
diff --git a/google_apis/classroom/classroom_api_student_submissions_response_types.h b/google_apis/classroom/classroom_api_student_submissions_response_types.h new file mode 100644 index 0000000..00574de --- /dev/null +++ b/google_apis/classroom/classroom_api_student_submissions_response_types.h
@@ -0,0 +1,96 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef GOOGLE_APIS_CLASSROOM_CLASSROOM_API_STUDENT_SUBMISSIONS_RESPONSE_TYPES_H_ +#define GOOGLE_APIS_CLASSROOM_CLASSROOM_API_STUDENT_SUBMISSIONS_RESPONSE_TYPES_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "third_party/abseil-cpp/absl/types/optional.h" + +namespace base { +template <class StructType> +class JSONValueConverter; +class Value; +} // namespace base + +namespace google_apis::classroom { + +// https://developers.google.com/classroom/reference/rest/v1/courses.courseWork.studentSubmissions +class StudentSubmission { + public: + // State of the student submission. + enum class State { + kNew, + kCreated, + kTurnedIn, + kReturned, + kReclaimedByStudent, + kOther, + }; + + StudentSubmission() = default; + StudentSubmission(const StudentSubmission&) = delete; + StudentSubmission& operator=(const StudentSubmission&) = delete; + ~StudentSubmission() = default; + + // Registers the mapping between JSON field names and the members in this + // class. + static void RegisterJSONConverter( + base::JSONValueConverter<StudentSubmission>* converter); + + const std::string& course_work_id() const { return course_work_id_; } + const std::string& id() const { return id_; } + absl::optional<double> assigned_grade() const { return assigned_grade_; } + State state() const { return state_; } + + private: + // Identifier for the course work which this submission belongs to. + std::string course_work_id_; + + // Identifier for this student submission assigned by Classroom. + std::string id_; + + // Optional grade. If unset, no grade was set. This value is a + // non-negative decimal rounded to two decimal places. + absl::optional<double> assigned_grade_ = absl::nullopt; + + // State of the student submission. + State state_ = State::kOther; +}; + +class StudentSubmissions { + public: + StudentSubmissions(); + StudentSubmissions(const StudentSubmissions&) = delete; + StudentSubmissions& operator=(const StudentSubmissions&) = delete; + ~StudentSubmissions(); + + // Registers the mapping between JSON field names and the members in this + // class. + static void RegisterJSONConverter( + base::JSONValueConverter<StudentSubmissions>* converter); + + // Creates a `StudentSubmissions` from parsed JSON. + static std::unique_ptr<StudentSubmissions> CreateFrom( + const base::Value& value); + + const std::string& next_page_token() const { return next_page_token_; } + const std::vector<std::unique_ptr<StudentSubmission>>& items() const { + return items_; + } + + private: + // `StudentSubmission` items stored in this container. + std::vector<std::unique_ptr<StudentSubmission>> items_; + + // Token that can be used to request the next page of this result. + std::string next_page_token_; +}; + +} // namespace google_apis::classroom + +#endif // GOOGLE_APIS_CLASSROOM_CLASSROOM_API_STUDENT_SUBMISSIONS_RESPONSE_TYPES_H_
diff --git a/google_apis/classroom/classroom_api_student_submissions_response_types_unittest.cc b/google_apis/classroom/classroom_api_student_submissions_response_types_unittest.cc new file mode 100644 index 0000000..2bac1f0 --- /dev/null +++ b/google_apis/classroom/classroom_api_student_submissions_response_types_unittest.cc
@@ -0,0 +1,128 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "google_apis/classroom/classroom_api_student_submissions_response_types.h" + +#include <memory> + +#include "base/json/json_reader.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace google_apis::classroom { + +using ::base::JSONReader; + +TEST(ClassroomApiStudentSubmissionsResponseTypesTest, ConvertsEmptyResponse) { + auto raw_student_submissions = JSONReader::Read("{}"); + ASSERT_TRUE(raw_student_submissions); + + auto submissions = + StudentSubmissions::CreateFrom(raw_student_submissions.value()); + ASSERT_TRUE(submissions); + EXPECT_TRUE(submissions->items().empty()); + EXPECT_TRUE(submissions->next_page_token().empty()); +} + +TEST(ClassroomApiStudentSubmissionsResponseTypesTest, ConvertsSubmissions) { + const auto raw_student_submissions = JSONReader::Read(R"( + { + "studentSubmissions": [ + { + "id": "student-submission-item-1", + "courseWorkId": "course-work-id", + "state": "NEW" + }, + { + "id": "student-submission-item-2", + "courseWorkId": "course-work-id", + "state": "CREATED" + }, + { + "id": "student-submission-item-3", + "courseWorkId": "course-work-id", + "state": "TURNED_IN", + "assignedGrade": 3.3 + }, + { + "id": "student-submission-item-4", + "courseWorkId": "course-work-id", + "state": "RETURNED", + "assignedGrade": 99.0 + }, + { + "id": "student-submission-item-5", + "courseWorkId": "course-work-id", + "state": "RECLAIMED_BY_STUDENT", + "assignedGrade": 99.99 + } + ] + })"); + ASSERT_TRUE(raw_student_submissions); + + const auto submissions = + StudentSubmissions::CreateFrom(raw_student_submissions.value()); + ASSERT_TRUE(submissions); + EXPECT_EQ(submissions->items().size(), 5u); + EXPECT_TRUE(submissions->next_page_token().empty()); + + EXPECT_EQ(submissions->items().at(0)->id(), "student-submission-item-1"); + EXPECT_EQ(submissions->items().at(0)->course_work_id(), "course-work-id"); + EXPECT_EQ(submissions->items().at(0)->state(), + StudentSubmission::State::kNew); + EXPECT_FALSE(submissions->items().at(0)->assigned_grade()); + + EXPECT_EQ(submissions->items().at(1)->id(), "student-submission-item-2"); + EXPECT_EQ(submissions->items().at(1)->course_work_id(), "course-work-id"); + EXPECT_EQ(submissions->items().at(1)->state(), + StudentSubmission::State::kCreated); + EXPECT_FALSE(submissions->items().at(1)->assigned_grade()); + + EXPECT_EQ(submissions->items().at(2)->id(), "student-submission-item-3"); + EXPECT_EQ(submissions->items().at(2)->course_work_id(), "course-work-id"); + EXPECT_EQ(submissions->items().at(2)->state(), + StudentSubmission::State::kTurnedIn); + EXPECT_DOUBLE_EQ(submissions->items().at(2)->assigned_grade().value(), 3.3); + + EXPECT_EQ(submissions->items().at(3)->id(), "student-submission-item-4"); + EXPECT_EQ(submissions->items().at(3)->course_work_id(), "course-work-id"); + EXPECT_EQ(submissions->items().at(3)->state(), + StudentSubmission::State::kReturned); + EXPECT_DOUBLE_EQ(submissions->items().at(3)->assigned_grade().value(), 99); + + EXPECT_EQ(submissions->items().at(4)->id(), "student-submission-item-5"); + EXPECT_EQ(submissions->items().at(4)->course_work_id(), "course-work-id"); + EXPECT_EQ(submissions->items().at(4)->state(), + StudentSubmission::State::kReclaimedByStudent); + EXPECT_DOUBLE_EQ(submissions->items().at(4)->assigned_grade().value(), 99.99); +} + +TEST(ClassroomApiStudentSubmissionsResponseTypesTest, ConvertsNextPageToken) { + const auto raw_submissions = JSONReader::Read(R"( + { + "studentSubmissions": [], + "nextPageToken": "qwerty" + })"); + ASSERT_TRUE(raw_submissions); + + const auto submissions = + StudentSubmissions::CreateFrom(raw_submissions.value()); + ASSERT_TRUE(submissions); + EXPECT_EQ(submissions->next_page_token(), "qwerty"); +} + +TEST(ClassroomApiStudentSubmissionsResponseTypesTest, + DoesNotCrashOnUnexpectedResponse) { + const auto raw_submissions = JSONReader::Read(R"( + { + "studentSubmissions": [{"id": []}], + "nextPageToken": true + })"); + ASSERT_TRUE(raw_submissions); + + const auto submissions = + StudentSubmissions::CreateFrom(raw_submissions.value()); + ASSERT_FALSE(submissions); +} + +} // namespace google_apis::classroom
diff --git a/google_apis/gaia/fake_oauth2_access_token_manager.cc b/google_apis/gaia/fake_oauth2_access_token_manager.cc index a6938b4..2833702 100644 --- a/google_apis/gaia/fake_oauth2_access_token_manager.cc +++ b/google_apis/gaia/fake_oauth2_access_token_manager.cc
@@ -124,23 +124,25 @@ GetPendingRequests(); // Walk the requests and notify the callbacks. - for (auto it = requests.begin(); it != requests.end(); ++it) { + for (const PendingRequest& request : requests) { // Consumers can drop requests in response to callbacks on other requests // (e.g., OAuthMultiloginFetcher clears all of its requests when it gets an // error on any of them). - if (!it->request) + if (!request.request) { continue; + } - bool scope_matches = all_scopes || it->scopes == scope; - bool account_matches = account_id.empty() || account_id == it->account_id; + bool scope_matches = all_scopes || request.scopes == scope; + bool account_matches = + account_id.empty() || account_id == request.account_id; if (account_matches && scope_matches) { for (auto& diagnostic_observer : GetDiagnosticsObserversForTesting()) { diagnostic_observer.OnFetchAccessTokenComplete( - account_id, it->request->GetConsumerId(), scope, error, + account_id, request.request->GetConsumerId(), scope, error, base::Time()); } - it->request->InformConsumer(error, token_response); + request.request->InformConsumer(error, token_response); } } } @@ -148,10 +150,10 @@ std::vector<FakeOAuth2AccessTokenManager::PendingRequest> FakeOAuth2AccessTokenManager::GetPendingRequests() { std::vector<PendingRequest> valid_requests; - for (auto it = pending_requests_.begin(); it != pending_requests_.end(); - ++it) { - if (it->request) - valid_requests.push_back(*it); + for (const PendingRequest& pending_request : pending_requests_) { + if (pending_request.request) { + valid_requests.push_back(pending_request); + } } return valid_requests; } @@ -207,7 +209,8 @@ const std::string& client_id, const FakeOAuth2AccessTokenManager::ScopeSet& scopes, const std::string& access_token) { - for (auto& observer : GetDiagnosticsObserversForTesting()) + for (DiagnosticsObserver& observer : GetDiagnosticsObserversForTesting()) { observer.OnAccessTokenRemoved(account_id, scopes); + } // Do nothing else, as we don't have a cache from which to remove the token. }
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc index 70d11e2..648d542 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.cc
@@ -176,19 +176,13 @@ } // static -bool D3DImageBackingFactory::ClearBackBufferToOpaque( - Microsoft::WRL::ComPtr<IDXGISwapChain1>& swap_chain, - Microsoft::WRL::ComPtr<ID3D11Device>& d3d11_device) { - Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture; - HRESULT hr = swap_chain->GetBuffer(0, IID_PPV_ARGS(&d3d11_texture)); - if (FAILED(hr)) { - LOG(ERROR) << "GetBuffer failed: " << logging::SystemErrorCodeToString(hr); - return false; - } - DCHECK(d3d11_texture); +bool D3DImageBackingFactory::ClearTextureToColor(ID3D11Device* d3d11_device, + ID3D11Texture2D* d3d11_texture, + const SkColor4f& color) { + HRESULT hr = S_OK; Microsoft::WRL::ComPtr<ID3D11RenderTargetView> render_target; - hr = d3d11_device->CreateRenderTargetView(d3d11_texture.Get(), nullptr, + hr = d3d11_device->CreateRenderTargetView(d3d11_texture, nullptr, &render_target); if (FAILED(hr)) { LOG(ERROR) << "CreateRenderTargetView failed: " @@ -201,11 +195,26 @@ d3d11_device->GetImmediateContext(&d3d11_device_context); DCHECK(d3d11_device_context); - d3d11_device_context->ClearRenderTargetView(render_target.Get(), - SkColors::kBlack.vec()); + d3d11_device_context->ClearRenderTargetView(render_target.Get(), color.vec()); + return true; } +// static +bool D3DImageBackingFactory::ClearBackBufferToColor(ID3D11Device* d3d11_device, + IDXGISwapChain1* swap_chain, + const SkColor4f& color) { + Microsoft::WRL::ComPtr<ID3D11Texture2D> d3d11_texture; + HRESULT hr = swap_chain->GetBuffer(0, IID_PPV_ARGS(&d3d11_texture)); + if (FAILED(hr)) { + LOG(ERROR) << "GetBuffer failed: " << logging::SystemErrorCodeToString(hr); + return false; + } + DCHECK(d3d11_texture); + + return ClearTextureToColor(d3d11_device, d3d11_texture.Get(), color); +} + D3DImageBackingFactory::SwapChainBackings D3DImageBackingFactory::CreateSwapChain(const Mailbox& front_buffer_mailbox, const Mailbox& back_buffer_mailbox, @@ -282,7 +291,8 @@ // Explicitly clear front and back buffers to ensure that there are no // uninitialized pixels. - if (!ClearBackBufferToOpaque(swap_chain, d3d11_device_)) { + if (!ClearBackBufferToColor(d3d11_device_.Get(), swap_chain.Get(), + SkColors::kBlack)) { return {nullptr, nullptr}; } @@ -295,7 +305,8 @@ return {nullptr, nullptr}; } - if (!ClearBackBufferToOpaque(swap_chain, d3d11_device_)) { + if (!ClearBackBufferToColor(d3d11_device_.Get(), swap_chain.Get(), + SkColors::kBlack)) { return {nullptr, nullptr}; }
diff --git a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h index 649c2eb..5dad8c9 100644 --- a/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h +++ b/gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h
@@ -16,6 +16,7 @@ #include "gpu/command_buffer/service/shared_image/shared_image_backing_factory.h" #include "gpu/gpu_gles2_export.h" #include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/skia/include/core/SkColor.h" namespace gfx { class Size; @@ -46,10 +47,15 @@ // Returns true if DXGI swap chain shared images for overlays are supported. static bool IsSwapChainSupported(); - // Clears the current back buffer to opaque black on the immediate context. - static bool ClearBackBufferToOpaque( - Microsoft::WRL::ComPtr<IDXGISwapChain1>& swap_chain, - Microsoft::WRL::ComPtr<ID3D11Device>& d3d11_device); + // Clears |d3d11_texture| to |color| on the immediate context. + static bool ClearTextureToColor(ID3D11Device* d3d11_device, + ID3D11Texture2D* d3d11_texture, + const SkColor4f& color); + + // Clears the current back buffer to |color| on the immediate context. + static bool ClearBackBufferToColor(ID3D11Device* d3d11_device, + IDXGISwapChain1* swap_chain, + const SkColor4f& color); struct GPU_GLES2_EXPORT SwapChainBackings { SwapChainBackings(std::unique_ptr<SharedImageBacking> front_buffer,
diff --git a/gpu/command_buffer/service/shared_image/dcomp_image_backing_factory_unittest.cc b/gpu/command_buffer/service/shared_image/dcomp_image_backing_factory_unittest.cc index d0e33d0..defed2f1 100644 --- a/gpu/command_buffer/service/shared_image/dcomp_image_backing_factory_unittest.cc +++ b/gpu/command_buffer/service/shared_image/dcomp_image_backing_factory_unittest.cc
@@ -98,60 +98,6 @@ shared_image_representation_factory_; std::unique_ptr<DCompImageBackingFactory> shared_image_factory_; - void RunFirstDrawCoversImageTest(uint32_t usage) { - Mailbox mailbox = Mailbox::GenerateForSharedImage(); - std::unique_ptr<SharedImageBacking> backing = - shared_image_factory_->CreateSharedImage( - mailbox, viz::SinglePlaneFormat::kRGBA_8888, nullptr, - gfx::Size(100, 100), gfx::ColorSpace::CreateSRGB(), - kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage, "TestLabel", - false); - ASSERT_NE(nullptr, backing); - std::unique_ptr<SharedImageRepresentationFactoryRef> factory_ref = - shared_image_manager_.Register(std::move(backing), - memory_type_tracker_.get()); - - std::unique_ptr<SkiaImageRepresentation> skia_representation = - shared_image_representation_factory_->ProduceSkia(mailbox, - context_state_); - - // First draw cannot be partial - { - std::vector<GrBackendSemaphore> begin_semaphores; - std::vector<GrBackendSemaphore> end_semaphores; - std::unique_ptr<SkiaImageRepresentation::ScopedWriteAccess> write_access = - skia_representation->BeginScopedWriteAccess( - 1, SkSurfaceProps(), gfx::Rect(0, 0, 1, 1), &begin_semaphores, - &end_semaphores, - SkiaImageRepresentation::AllowUnclearedAccess::kYes, true); - EXPECT_EQ(nullptr, write_access); - } - - { - std::vector<GrBackendSemaphore> begin_semaphores; - std::vector<GrBackendSemaphore> end_semaphores; - std::unique_ptr<SkiaImageRepresentation::ScopedWriteAccess> write_access = - skia_representation->BeginScopedWriteAccess( - 1, SkSurfaceProps(), gfx::Rect(factory_ref->size()), - &begin_semaphores, &end_semaphores, - SkiaImageRepresentation::AllowUnclearedAccess::kYes, true); - EXPECT_NE(nullptr, write_access); - skia_representation->SetCleared(); - } - - // Subsequent draws can be partial - { - std::vector<GrBackendSemaphore> begin_semaphores; - std::vector<GrBackendSemaphore> end_semaphores; - std::unique_ptr<SkiaImageRepresentation::ScopedWriteAccess> write_access = - skia_representation->BeginScopedWriteAccess( - 1, SkSurfaceProps(), gfx::Rect(0, 0, 1, 1), &begin_semaphores, - &end_semaphores, - SkiaImageRepresentation::AllowUnclearedAccess::kYes, true); - EXPECT_NE(nullptr, write_access); - } - } - void RunDXGISwapChainAlphaTest(bool has_alpha) { Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageBacking> backing = @@ -391,14 +337,6 @@ } } -TEST_F(DCompImageBackingFactoryTest, FirstDrawCoversImageDXGISwapChain) { - RunFirstDrawCoversImageTest(kDXGISwapChainUsage); -} - -TEST_F(DCompImageBackingFactoryTest, FirstDrawCoversImageDCompSurface) { - RunFirstDrawCoversImageTest(kDCompSurfaceUsage); -} - // Ensure that creating a DXGI swap chain SI, we get a swap chain with the right // alpha mode. TEST_F(DCompImageBackingFactoryTest, DXGISwapChainAlphaOpaque) { @@ -548,26 +486,14 @@ context_state_->gr_context()->submit(true); } - // Create a shared image, clear it to |color|, - void RunTest(uint32_t usage, - viz::SharedImageFormat format, - gfx::ColorSpace color_space, - bool has_alpha, - SkColor clear_color, - SkColor expected_window_color) { - // Bake the SDR white level into the color space so SharedImage backings can - // know about it. - if (color_space.IsAffectedBySDRWhiteLevel()) { - auto sk_color_space = - color_space.ToSkColorSpace(gfx::ColorSpace::kDefaultSDRWhiteLevel); - color_space = gfx::ColorSpace(*sk_color_space, /*is_hdr=*/true); - } - - DVLOG(2) << "usage = " << CreateLabelForSharedImageUsage(usage) - << ", format = " << format.ToString() - << ", color_space = " << color_space.ToString() - << ", has_alpha = " << has_alpha; - + // Create a backing, fill |draw_area| with |draw_color|, and schedule the + // overlay + void ScheduleImageWithOneDraw(uint32_t usage, + viz::SharedImageFormat format, + const gfx::ColorSpace& color_space, + bool has_alpha, + const gfx::Rect& draw_area, + SkColor draw_color) { Mailbox mailbox = Mailbox::GenerateForSharedImage(); std::unique_ptr<SharedImageBacking> backing = shared_image_factory_->CreateSharedImage( @@ -580,15 +506,11 @@ shared_image_manager_.Register(std::move(backing), memory_type_tracker_.get()); - { - std::unique_ptr<SkiaImageRepresentation> skia_representation = - shared_image_representation_factory_->ProduceSkia(mailbox, - context_state_); - ASSERT_NE(nullptr, skia_representation); - FillAreaAndSubmit(skia_representation.get(), gfx::Rect(window_size()), - clear_color); - skia_representation->SetCleared(); - } + std::unique_ptr<SkiaImageRepresentation> skia_representation = + shared_image_representation_factory_->ProduceSkia(mailbox, + context_state_); + FillAreaAndSubmit(skia_representation.get(), draw_area, draw_color); + skia_representation->SetCleared(); { std::unique_ptr<OverlayImageRepresentation> overlay_representation = @@ -602,6 +524,31 @@ InitializeVisualTreeWithContent(layer_content.Get()); CommitAndWait(); } + } + + // Runs a sanity check test that verifies backings with different color spaces + // are valid and contain the values we expect. + void RunFormatAndColorSpaceTest(uint32_t usage, + viz::SharedImageFormat format, + gfx::ColorSpace color_space, + bool has_alpha, + SkColor clear_color, + SkColor expected_window_color) { + // Bake the SDR white level into the color space so SharedImage backings can + // know about it. + if (color_space.IsAffectedBySDRWhiteLevel()) { + auto sk_color_space = + color_space.ToSkColorSpace(gfx::ColorSpace::kDefaultSDRWhiteLevel); + color_space = gfx::ColorSpace(*sk_color_space, /*is_hdr=*/true); + } + + DVLOG(2) << "usage = " << CreateLabelForSharedImageUsage(usage) + << ", format = " << format.ToString() + << ", color_space = " << color_space.ToString() + << ", has_alpha = " << has_alpha; + + ScheduleImageWithOneDraw(usage, format, color_space, has_alpha, + gfx::Rect(window_size()), clear_color); // CheckColors accounts for color space conversion shift gfx::test::CheckColors( @@ -611,6 +558,41 @@ gfx::Point(window_size_.width() / 4, window_size_.height() / 4))); } + // Check that a backing whose first draw does not cover the entire surface has + // its untouched pixels initialized to transparent black. + void RunIncompleteFirstDrawTest(uint32_t usage) { + // First draw does not cover full surface + const SkColor expected_color = SK_ColorRED; + ScheduleImageWithOneDraw(usage, viz::SinglePlaneFormat::kRGBA_8888, + gfx::ColorSpace::CreateSRGB(), true, + gfx::Rect(1, 1), expected_color); + + SkBitmap window_readback = + gl::GLTestHelper::ReadBackWindow(window(), window_size()); + + // The part that we drew should be our expected color + EXPECT_SKCOLOR_EQ(expected_color, gl::GLTestHelper::GetColorAtPoint( + window_readback, gfx::Point(0, 0))); + + // The rest of the image should be the color of the window's redirection + // surface, since there's only one visual. + // Note this checks that we replicate the behavior of SoftwareRenderer--it + // is normally invalid to read a uninitialized portion of a SharedImage. + const SkColor redirection_surface_color = SK_ColorBLACK; + EXPECT_SKCOLOR_EQ( + redirection_surface_color, + gl::GLTestHelper::GetColorAtPoint(window_readback, gfx::Point(0, 1))); + EXPECT_SKCOLOR_EQ( + redirection_surface_color, + gl::GLTestHelper::GetColorAtPoint(window_readback, gfx::Point(1, 0))); + EXPECT_SKCOLOR_EQ( + redirection_surface_color, + gl::GLTestHelper::GetColorAtPoint(window_readback, gfx::Point(1, 1))); + EXPECT_SKCOLOR_EQ( + redirection_surface_color, + gl::GLTestHelper::GetColorAtPoint(window_readback, gfx::Point(99, 99))); + } + const gfx::Size& window_size() const { return window_size_; } private: @@ -654,17 +636,19 @@ SkColor test_color = SkColorSetRGB(0x20, 0x40, 0x80); SkColor expected_color = test_color; for (auto format : formats) { - RunTest(kDCompSurfaceUsage, format, gfx::ColorSpace::CreateSRGB(), false, - test_color, expected_color); + RunFormatAndColorSpaceTest(kDCompSurfaceUsage, format, + gfx::ColorSpace::CreateSRGB(), false, test_color, + expected_color); } } TEST_F(DCompImageBackingFactoryVisualTreeTest, DCompSurfaceCanDisplayLinear) { SkColor test_color = SkColorSetRGB(0x20, 0x40, 0x80); SkColor expected_color = SkColorSetRGB(0x35, 0x65, 0xc3); - RunTest(kDCompSurfaceUsage, viz::SinglePlaneFormat::kRGBA_F16, - gfx::ColorSpace::CreateSCRGBLinear80Nits(), false, test_color, - expected_color); + RunFormatAndColorSpaceTest(kDCompSurfaceUsage, + viz::SinglePlaneFormat::kRGBA_F16, + gfx::ColorSpace::CreateSCRGBLinear80Nits(), false, + test_color, expected_color); } TEST_F(DCompImageBackingFactoryVisualTreeTest, @@ -677,8 +661,9 @@ SkColor test_color = SkColorSetARGB(0x80, 0x20, 0x40, 0x80); SkColor expected_color = SkColorSetRGB(0x10, 0x20, 0x40); for (auto format : formats) { - RunTest(kDCompSurfaceUsage, format, gfx::ColorSpace::CreateSRGB(), true, - test_color, expected_color); + RunFormatAndColorSpaceTest(kDCompSurfaceUsage, format, + gfx::ColorSpace::CreateSRGB(), true, test_color, + expected_color); } } @@ -686,9 +671,10 @@ DCompSurfaceCanDisplayLinearWithAlpha) { SkColor test_color = SkColorSetARGB(0x80, 0x20, 0x40, 0x80); SkColor expected_color = SkColorSetRGB(0x10, 0x20, 0x40); - RunTest(kDCompSurfaceUsage, viz::SinglePlaneFormat::kRGBA_F16, - gfx::ColorSpace::CreateSCRGBLinear80Nits(), true, test_color, - expected_color); + RunFormatAndColorSpaceTest(kDCompSurfaceUsage, + viz::SinglePlaneFormat::kRGBA_F16, + gfx::ColorSpace::CreateSCRGBLinear80Nits(), true, + test_color, expected_color); } TEST_F(DCompImageBackingFactoryVisualTreeTest, DXGISwapChainCanDisplay) { @@ -702,24 +688,27 @@ SkColor test_color = SkColorSetRGB(0x20, 0x40, 0x80); SkColor expected_color = test_color; for (auto format : formats) { - RunTest(kDXGISwapChainUsage, format, gfx::ColorSpace::CreateSRGB(), false, - test_color, expected_color); + RunFormatAndColorSpaceTest(kDXGISwapChainUsage, format, + gfx::ColorSpace::CreateSRGB(), false, test_color, + expected_color); } } TEST_F(DCompImageBackingFactoryVisualTreeTest, DXGISwapChainCanDisplayLinear) { SkColor test_color = SkColorSetRGB(0x20, 0x40, 0x80); SkColor expected_color = SkColorSetRGB(0x35, 0x65, 0xc3); - RunTest(kDXGISwapChainUsage, viz::SinglePlaneFormat::kRGBA_F16, - gfx::ColorSpace::CreateSCRGBLinear80Nits(), false, test_color, - expected_color); + RunFormatAndColorSpaceTest(kDXGISwapChainUsage, + viz::SinglePlaneFormat::kRGBA_F16, + gfx::ColorSpace::CreateSCRGBLinear80Nits(), false, + test_color, expected_color); } TEST_F(DCompImageBackingFactoryVisualTreeTest, DXGISwapChainCanDisplayHDR10) { SkColor test_color = SkColorSetRGB(0x20, 0x40, 0x80); SkColor expected_color = SkColorSetRGB(0x35, 0x65, 0xc3); - RunTest(kDXGISwapChainUsage, viz::SinglePlaneFormat::kRGBA_1010102, - gfx::ColorSpace::CreateHDR10(), false, test_color, expected_color); + RunFormatAndColorSpaceTest( + kDXGISwapChainUsage, viz::SinglePlaneFormat::kRGBA_1010102, + gfx::ColorSpace::CreateHDR10(), false, test_color, expected_color); } TEST_F(DCompImageBackingFactoryVisualTreeTest, @@ -732,8 +721,9 @@ SkColor test_color = SkColorSetARGB(0x80, 0x20, 0x40, 0x80); SkColor expected_color = SkColorSetRGB(0x10, 0x20, 0x40); for (auto format : formats) { - RunTest(kDXGISwapChainUsage, format, gfx::ColorSpace::CreateSRGB(), true, - test_color, expected_color); + RunFormatAndColorSpaceTest(kDXGISwapChainUsage, format, + gfx::ColorSpace::CreateSRGB(), true, test_color, + expected_color); } } @@ -741,17 +731,19 @@ DXGISwapChainCanDisplayLinearWithAlpha) { SkColor test_color = SkColorSetARGB(0x80, 0x20, 0x40, 0x80); SkColor expected_color = SkColorSetRGB(0x10, 0x20, 0x40); - RunTest(kDXGISwapChainUsage, viz::SinglePlaneFormat::kRGBA_F16, - gfx::ColorSpace::CreateSCRGBLinear80Nits(), true, test_color, - expected_color); + RunFormatAndColorSpaceTest(kDXGISwapChainUsage, + viz::SinglePlaneFormat::kRGBA_F16, + gfx::ColorSpace::CreateSCRGBLinear80Nits(), true, + test_color, expected_color); } TEST_F(DCompImageBackingFactoryVisualTreeTest, DXGISwapChainCanDisplayHDR10WithAlpha) { SkColor test_color = SkColorSetARGB(0x80, 0x20, 0x40, 0x80); SkColor expected_color = SkColorSetRGB(0x10, 0x20, 0x40); - RunTest(kDXGISwapChainUsage, viz::SinglePlaneFormat::kRGBA_1010102, - gfx::ColorSpace::CreateHDR10(), true, test_color, expected_color); + RunFormatAndColorSpaceTest( + kDXGISwapChainUsage, viz::SinglePlaneFormat::kRGBA_1010102, + gfx::ColorSpace::CreateHDR10(), true, test_color, expected_color); } TEST_F(DCompImageBackingFactoryVisualTreeTest, @@ -834,4 +826,14 @@ } } +TEST_F(DCompImageBackingFactoryVisualTreeTest, + DCompSurfaceIncompleteFirstDrawInitializesToTransparent) { + RunIncompleteFirstDrawTest(kDCompSurfaceUsage); +} + +TEST_F(DCompImageBackingFactoryVisualTreeTest, + DXGISwapChainIncompleteFirstDrawInitializesToTransparent) { + RunIncompleteFirstDrawTest(kDXGISwapChainUsage); +} + } // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image/dcomp_surface_image_backing.cc b/gpu/command_buffer/service/shared_image/dcomp_surface_image_backing.cc index 13187eb..f9590a81 100644 --- a/gpu/command_buffer/service/shared_image/dcomp_surface_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/dcomp_surface_image_backing.cc
@@ -9,6 +9,7 @@ #include "components/viz/common/resources/resource_format_utils.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/service/shared_context_state.h" +#include "gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h" #include "gpu/command_buffer/service/shared_image/shared_image_format_utils.h" #include "third_party/angle/include/EGL/egl.h" #include "third_party/angle/include/EGL/eglext.h" @@ -21,6 +22,7 @@ #include "ui/gfx/color_space_win.h" #include "ui/gl/direct_composition_support.h" #include "ui/gl/egl_util.h" +#include "ui/gl/gl_angle_util_win.h" #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_surface.h" @@ -28,6 +30,41 @@ namespace gpu { +namespace { + +bool ClearDCompSurface(IDCompositionSurface* surface, + const gfx::Size& surface_size) { + HRESULT hr = S_OK; + + RECT rect = gfx::Rect(surface_size).ToRECT(); + Microsoft::WRL::ComPtr<ID3D11Texture2D> draw_texture; + POINT update_offset = {}; + hr = surface->BeginDraw(&rect, IID_PPV_ARGS(&draw_texture), &update_offset); + if (FAILED(hr)) { + LOG(ERROR) << "BeginDraw failed: " << logging::SystemErrorCodeToString(hr); + return false; + } + + Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device = + gl::QueryD3D11DeviceObjectFromANGLE(); + // DX11 protects the DComp surface atlas so this clear only affects pixels in + // the update rect. + if (!D3DImageBackingFactory::ClearTextureToColor( + d3d11_device.Get(), draw_texture.Get(), SkColors::kTransparent)) { + return false; + } + + hr = surface->EndDraw(); + if (FAILED(hr)) { + LOG(ERROR) << "EndDraw failed: " << logging::SystemErrorCodeToString(hr); + return false; + } + + return true; +} + +} // namespace + // An EGL surface that can temporarily encapsulate a D3D texture (and ANGLE // draw offset). This is used so Skia can draw into the draw texture returned // by IDCompositionSurface::BeginDraw. @@ -240,9 +277,16 @@ return nullptr; } + // SharedImage allows an incomplete first draw so long as we only read from + // the part that we've previously drawn to. However, IDCompositionSurface + // requires a full draw on the first |BeginDraw|. To make an incomplete first + // draw valid, we'll initialize all the pixels and expand the swap rect. if (!IsCleared() && gfx::Rect(size()) != update_rect) { - LOG(ERROR) << "First draw to surface must draw to everything"; - return nullptr; + LOG(WARNING) << "First draw to surface should draw to everything"; + if (!ClearDCompSurface(dcomp_surface_.Get(), size())) { + LOG(ERROR) << "Could not initialize DComp surface"; + return nullptr; + } } TRACE_EVENT0("gpu", "DCompSurfaceImageBacking::BeginDraw");
diff --git a/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_backing.cc b/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_backing.cc index 24132aae..c6c7506 100644 --- a/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_backing.cc +++ b/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_backing.cc
@@ -177,7 +177,7 @@ DCHECK(!in_fence); } -void DXGISwapChainImageBacking::DidBeginWriteAccess( +bool DXGISwapChainImageBacking::DidBeginWriteAccess( const gfx::Rect& swap_rect) { if (pending_swap_rect_.has_value()) { // Force a Present if there's already a pending swap rect. For normal usage @@ -187,23 +187,56 @@ // debugging. LOG(WARNING) << "Multiple skia write accesses per overlay access, flushing " "pending swap."; - Present(false); + if (!Present(false)) { + return false; + } } - pending_swap_rect_ = swap_rect; + gfx::Rect pending_swap_rect = swap_rect; - // To clear only uninitialized buffers, this must happen after |Present|s of - // outstanding draws, including the one above. + absl::optional<SkColor4f> initialize_color; + + // SharedImage allows an incomplete first draw so long as we only read from + // the part that we've previously drawn to. However, IDXGISwapChain requires a + // full draw on the first |Present1|. To make an incomplete first draw valid, + // we'll initialize all the pixels and expand the swap rect. + const gfx::Rect full_swap_rect = gfx::Rect(size()); + if (!IsCleared() && swap_rect != full_swap_rect) { + LOG(WARNING) << "First draw to surface should draw to everything"; + + initialize_color = SkColors::kTransparent; + + // Ensure that the next swap contains the entire swap chain since we just + // cleared it. + pending_swap_rect = full_swap_rect; + } + + // See comment in |DXGISwapChainImageBacking::Create| for why we need this. if (buffers_need_alpha_initialization_count_ > 0) { // We only need to write the alpha channel, but we clear since it's simpler // and are guaranteed to not have pixels we need to preserve before the // first write to each buffer. - if (!D3DImageBackingFactory::ClearBackBufferToOpaque(dxgi_swap_chain_, - d3d11_device_)) { - LOG(ERROR) << "Could not initialize back buffer alpha"; - } - buffers_need_alpha_initialization_count_--; + initialize_color = SkColors::kBlack; } + + if (initialize_color.has_value()) { + // To clear only uninitialized buffers, this must happen after |Present|s of + // outstanding draws, including the one above. + if (!D3DImageBackingFactory::ClearBackBufferToColor( + d3d11_device_.Get(), dxgi_swap_chain_.Get(), + initialize_color.value())) { + LOG(ERROR) << "Could not initialize back buffer alpha"; + return false; + } + + if (buffers_need_alpha_initialization_count_ > 0) { + buffers_need_alpha_initialization_count_--; + } + } + + pending_swap_rect_ = {pending_swap_rect}; + + return true; } bool DXGISwapChainImageBacking::Present(
diff --git a/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_backing.h b/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_backing.h index 8774238a..7af7d32 100644 --- a/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_backing.h +++ b/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_backing.h
@@ -81,7 +81,7 @@ friend class SkiaGLImageRepresentationDXGISwapChain; // Called by the Skia representation to indicate where it intends to draw. - void DidBeginWriteAccess(const gfx::Rect& swap_rect); + bool DidBeginWriteAccess(const gfx::Rect& swap_rect); absl::optional<gfx::Rect> pending_swap_rect_; Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
diff --git a/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_representation.cc b/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_representation.cc index 69d30b5..a4c29bce 100644 --- a/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_representation.cc +++ b/gpu/command_buffer/service/shared_image/dxgi_swap_chain_image_representation.cc
@@ -135,19 +135,16 @@ std::vector<GrBackendSemaphore>* begin_semaphores, std::vector<GrBackendSemaphore>* end_semaphores, std::unique_ptr<GrBackendSurfaceMutableState>* end_state) { - if (!IsCleared() && gfx::Rect(size()) != update_rect) { - LOG(ERROR) << "First draw to surface must draw to everything"; - return {}; - } - std::vector<sk_sp<SkSurface>> surfaces = SkiaGLImageRepresentation::BeginWriteAccess( final_msaa_count, surface_props, update_rect, begin_semaphores, end_semaphores, end_state); if (!surfaces.empty()) { - static_cast<DXGISwapChainImageBacking*>(backing())->DidBeginWriteAccess( - update_rect); + if (!static_cast<DXGISwapChainImageBacking*>(backing()) + ->DidBeginWriteAccess(update_rect)) { + return {}; + } } return surfaces;
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc index b3e49f1..ae1d5db 100644 --- a/gpu/command_buffer/service/webgpu_decoder_impl.cc +++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -1577,8 +1577,7 @@ adapters.push_back(adapter); } } else if (adapterProperties.backendType != WGPUBackendType_Null && - adapterProperties.backendType != WGPUBackendType_OpenGL && - adapterProperties.backendType != WGPUBackendType_D3D11) { + adapterProperties.backendType != WGPUBackendType_OpenGL) { adapters.push_back(adapter); } }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 278045ea..7bc5d74 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -33684,7 +33684,7 @@ swarming_host: "chromium-swarm.appspot.com" dimensions: "builder:ios15-beta-simulator" dimensions: "cpu:x86-64" - dimensions: "os:Mac-12" + dimensions: "os:Mac-13" dimensions: "pool:luci.chromium.ci" exe { cipd_package: "infra/chromium/bootstrapper/${platform}" @@ -61932,7 +61932,7 @@ dimensions: "builder:android_compile_dbg" dimensions: "cores:32" dimensions: "cpu:x86-64" - dimensions: "os:Ubuntu-18.04" + dimensions: "os:Ubuntu-22.04" dimensions: "pool:luci.chromium.try" dimensions: "ssd:1" exe {
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index 761e4bd..7ab7d216 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -7405,6 +7405,11 @@ short_name: "x64" } builders { + name: "buildbucket/luci.chromium.ci/Dawn Mac x64 Experimental Release (Intel)" + category: "ToT|Mac|Intel" + short_name: "exp" + } + builders { name: "buildbucket/luci.chromium.ci/Dawn Mac x64 Release (Intel)" category: "ToT|Mac|Intel" short_name: "x64"
diff --git a/infra/config/generated/testing/gn_isolate_map.pyl b/infra/config/generated/testing/gn_isolate_map.pyl index b6637df8..c8b3b76 100644 --- a/infra/config/generated/testing/gn_isolate_map.pyl +++ b/infra/config/generated/testing/gn_isolate_map.pyl
@@ -983,10 +983,6 @@ "label": "//ios/showcase:ios_showcase_eg2tests_module", "type": "generated_script", }, - "ios_swift_interop_xcuitests_module": { - "label": "//ios/chrome/test/swift_interop:ios_swift_interop_xcuitests_module", - "type": "generated_script", - }, "ios_testing_unittests": { "label": "//ios/testing:ios_testing_unittests", "type": "generated_script",
diff --git a/infra/config/lib/linux-default.json b/infra/config/lib/linux-default.json index 6eb76a8..1cf19afa 100644 --- a/infra/config/lib/linux-default.json +++ b/infra/config/lib/linux-default.json
@@ -15,6 +15,7 @@ "android-arm64-rel": "Ubuntu-22.04", "android-nougat-x86-rel": "Ubuntu-22.04", "android-x64-cast": "Ubuntu-22.04", + "android_compile_dbg": "Ubuntu-22.04", "android_cronet": "Ubuntu-22.04", "chromeos-amd64-generic-rel": "Ubuntu-22.04", "chromeos-amd64-generic-rel-compilator": "Ubuntu-22.04",
diff --git a/infra/config/subprojects/chromium/ci/chromium.dawn.star b/infra/config/subprojects/chromium/ci/chromium.dawn.star index 8d071ec..f199668 100644 --- a/infra/config/subprojects/chromium/ci/chromium.dawn.star +++ b/infra/config/subprojects/chromium/ci/chromium.dawn.star
@@ -449,10 +449,10 @@ run_tests_serially = True, ), # Uncomment this entry when this experimental tester is actually in use. - # console_view_entry = consoles.console_view_entry( - # category = "ToT|Mac|Intel", - # short_name = "exp", - # ), + console_view_entry = consoles.console_view_entry( + category = "ToT|Mac|Intel", + short_name = "exp", + ), list_view = "chromium.gpu.experimental", )
diff --git a/infra/config/subprojects/chromium/ci/chromium.fyi.star b/infra/config/subprojects/chromium/ci/chromium.fyi.star index 8b968a42..15f0776 100644 --- a/infra/config/subprojects/chromium/ci/chromium.fyi.star +++ b/infra/config/subprojects/chromium/ci/chromium.fyi.star
@@ -2405,7 +2405,7 @@ ), build_gs_bucket = "chromium-fyi-archive", ), - os = os.MAC_DEFAULT, + os = os.MAC_13, console_view_entry = [ consoles.console_view_entry( category = "iOS|iOS15",
diff --git a/infra/config/targets/targets.star b/infra/config/targets/targets.star index a457030..fc7526fe 100644 --- a/infra/config/targets/targets.star +++ b/infra/config/targets/targets.star
@@ -1215,11 +1215,6 @@ ) targets.generated_script( - name = "ios_swift_interop_xcuitests_module", - label = "//ios/chrome/test/swift_interop:ios_swift_interop_xcuitests_module", -) - -targets.generated_script( name = "ios_testing_unittests", label = "//ios/testing:ios_testing_unittests", )
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 5fd53a5..3ef17ad4 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -2419,13 +2419,13 @@ <message name="IDS_IOS_READING_LIST_SNACKBAR_MESSAGE" desc="Message briefly displayed at the bottom of the screen to the user to inform that the selected page has been added to the reading list. [Length: 35em]" meaning="The selected page has been added to your reading list. [Length: 35em]"> Added to Reading List </message> - <message name="IDS_IOS_READING_LIST_SNACKBAR_MESSAGE_FOR_ACCOUNT" desc="Message briefly displayed at the bottom of the screen to the user to inform that the selected page has been added to the reading list of their account." meaning="The selected page has been added to your account's reading list."> + <message name="IDS_IOS_READING_LIST_SNACKBAR_MESSAGE_FOR_ACCOUNT" desc="This confirmation message is intended to help users understand that a page has been saved to the Reading List that is saved in their Google Account. The confirmation message appears at the bottom of the page after users choose to save a page. The tone should be informative." meaning="The selected page has been added to your account's reading list."> {count, plural, =1 {Page added to your reading list in your account, {email}} other {Pages added to your reading list in your account, {email}}} </message> - <message name="IDS_IOS_READING_LIST_SNACKBAR_UNDO_ACTION" desc="Text shown for the undo button in the snackbar which is shown when a new reading list item is added. Should be in uppercase letters. [CHAR_LIMIT=14]" meaning="Undo the action of adding new item to the reading list by removing the newly added item. [CHAR_LIMIT=14]"> - UNDO + <message name="IDS_IOS_READING_LIST_SNACKBAR_UNDO_ACTION" desc="This string is found on a button that removes a page from the Reading List when the user taps it. The button is on a confirmation message that users see when they save a page to the Reading List. This text is a verb and is short for the longer phrase 'undo the addition of this page to my Reading List.' The tone should be informative. Use Apple-style title case. [CHAR_LIMIT=15]" meaning="Undo the action of adding new item to the reading list by removing the newly added item. Use Apple-style title case. [CHAR_LIMIT=15]"> + Undo </message> <message name="IDS_IOS_READING_LIST_ENTRY_ACCESSIBILITY_LABEL" desc="Accessibility label for a reading list entry. Summarizes fields in the reading list entry (title, status and url). Read by Text To Speech. Similar to IDS_IOS_READING_LIST_ENTRY_WITH_UPLOAD_STATE_ACCESSIBILITY_LABEL"> <ph name="TITLE"><ex>Chromium - The Chromium Projects</ex>$1</ph>, <ph name="STATE"><ex>Available offline</ex>$2</ph>, <ph name="URL"><ex>http://www.chromium.org/Home</ex>$3</ph> @@ -4300,8 +4300,8 @@ <message name="IDS_IOS_VOICE_SEARCH_SETTING_TTS" desc="The label for setting switch enabling text-to-speech response after voice search [Length: 29em] [iOS only]"> Speak Answers Back </message> - <message name="IDS_IOS_SIGNIN_PROMO_READING_LIST" desc="Text to inform the user that they can sign in and sync to get the reading list shared between devices."> - Sign in to open and save your reading list in your Google Account. + <message name="IDS_IOS_SIGNIN_PROMO_READING_LIST" desc="This string is on a promo intended to promote signing in to Chrome with the user's Google Account. It appears on the Reading List page when the user is not signed in. We want users to read this promo and click 'Continue as {name}' to sign in to their Google Account. The tone should be informative and lightweight."> + Sign in to get your reading list on all your devices. </message> <message name="IDS_IOS_SIGNIN_PROMO_BOOKMARKS" desc="This string is on a promo intended to promote signing in to Chrome with the user's Google Account. It appears on the Bookmarks page when the user is not signed in. We want users to read this promo and click 'Continue as name' to sign in to their Google Account. The tone should be informative and lightweight. [Length: 90em]"> Sign in to get your bookmarks on all your devices.
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_READING_LIST_SNACKBAR_UNDO_ACTION.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_READING_LIST_SNACKBAR_UNDO_ACTION.png.sha1 index 958a946..bdfd1c3 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_READING_LIST_SNACKBAR_UNDO_ACTION.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_READING_LIST_SNACKBAR_UNDO_ACTION.png.sha1
@@ -1 +1 @@ -aa76b920633a7ed5a4b6fc22ae180265dec01cb7 \ No newline at end of file +4b1722d0a8ef30720304edbbba6dfda63acf836b \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SIGNIN_PROMO_READING_LIST.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SIGNIN_PROMO_READING_LIST.png.sha1 index 3dea87f..0df31374 100644 --- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SIGNIN_PROMO_READING_LIST.png.sha1 +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_SIGNIN_PROMO_READING_LIST.png.sha1
@@ -1 +1 @@ -df668a51e55526a56c830e9ccc552bd2c64fbe1b \ No newline at end of file +056de25143a23223434ba71495361f5cfadf850f \ No newline at end of file
diff --git a/ios/chrome/browser/component_updater/BUILD.gn b/ios/chrome/browser/component_updater/BUILD.gn index c1b1967..aa01110 100644 --- a/ios/chrome/browser/component_updater/BUILD.gn +++ b/ios/chrome/browser/component_updater/BUILD.gn
@@ -16,6 +16,7 @@ "//components/services/unzip:in_process", "//components/services/unzip/public/mojom", "//components/update_client", + "//components/update_client:buildflags", "//components/update_client:common_impl", "//ios/chrome/browser/shared/model/application_context", "//ios/chrome/common",
diff --git a/ios/chrome/browser/component_updater/ios_component_updater_configurator.mm b/ios/chrome/browser/component_updater/ios_component_updater_configurator.mm index a09919f..7040926 100644 --- a/ios/chrome/browser/component_updater/ios_component_updater_configurator.mm +++ b/ios/chrome/browser/component_updater/ios_component_updater_configurator.mm
@@ -11,12 +11,15 @@ #import <vector> #import "base/containers/flat_map.h" +#import "base/files/file_path.h" +#import "base/path_service.h" #import "base/version.h" #import "components/component_updater/component_updater_command_line_config_policy.h" #import "components/component_updater/configurator_impl.h" #import "components/services/patch/in_process_file_patcher.h" #import "components/services/unzip/in_process_unzipper.h" #import "components/update_client/activity_data_service.h" +#import "components/update_client/buildflags.h" #import "components/update_client/crx_downloader_factory.h" #import "components/update_client/net/network_chromium.h" #import "components/update_client/patch/patch_impl.h" @@ -72,6 +75,9 @@ GetProtocolHandlerFactory() const override; absl::optional<bool> IsMachineExternallyManaged() const override; update_client::UpdaterStateProvider GetUpdaterStateProvider() const override; +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) + absl::optional<base::FilePath> GetCrxCachePath() const override; +#endif private: friend class base::RefCountedThreadSafe<IOSConfigurator>; @@ -224,6 +230,16 @@ return configurator_impl_.GetUpdaterStateProvider(); } +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) +absl::optional<base::FilePath> IOSConfigurator::GetCrxCachePath() const { + base::FilePath path; + if (!base::PathService::Get(base::DIR_CACHE, &path)) { + return absl::nullopt; + } + return path.Append(FILE_PATH_LITTERAL("ios_crx_cache")); +} +#endif + } // namespace scoped_refptr<update_client::Configurator> MakeIOSComponentUpdaterConfigurator(
diff --git a/ios/chrome/browser/main/browser_agent_util.mm b/ios/chrome/browser/main/browser_agent_util.mm index 6e833e4..83cb929 100644 --- a/ios/chrome/browser/main/browser_agent_util.mm +++ b/ios/chrome/browser/main/browser_agent_util.mm
@@ -117,7 +117,6 @@ WebStateUpdateBrowserAgent::CreateForBrowser(browser); ReadingListBrowserAgent::CreateForBrowser(browser); - WebStateUpdateBrowserAgent::CreateForBrowser(browser); PagePlaceholderBrowserAgent::CreateForBrowser(browser); // This needs to be called last in case any downstream browser agents need to
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn index b82a1f7..5c789cb 100644 --- a/ios/chrome/browser/passwords/BUILD.gn +++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -36,6 +36,7 @@ ] deps = [ ":infobar_delegates", + ":password_checkup_metrics", ":store_factory", "//base", "//base:i18n", @@ -226,7 +227,7 @@ "well_known_change_password_tab_helper_unittest.mm", ] deps = [ - ":password_checkup_utils", + ":password_checkup_metrics", ":passwords", "//base", "//base/test:test_support",
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h index 3378cb0..eb185b7 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h +++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h
@@ -104,6 +104,9 @@ void NotifyPasswordCheckStatusChanged(); + // Logs counts of insecure credentials after each password check. + void LogInsecureCredentialsCountMetrics(); + // Remembers whether a password check is running right now. bool is_check_running_ = false;
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm index a390f54..8f24d81 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm +++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm
@@ -4,6 +4,8 @@ #import "ios/chrome/browser/passwords/ios_chrome_password_check_manager.h" +#import <set> + #import "base/strings/utf_string_conversions.h" #import "base/task/sequenced_task_runner.h" #import "components/keyed_service/core/service_access_type.h" @@ -16,6 +18,7 @@ #import "ios/chrome/browser/passwords/ios_chrome_affiliation_service_factory.h" #import "ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.h" #import "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h" +#import "ios/chrome/browser/passwords/password_checkup_metrics.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -195,6 +198,8 @@ browser_state_->GetPrefs()->SetTime( password_manager::prefs::kSyncedLastTimePasswordCheckCompleted, base::Time::Now()); + + LogInsecureCredentialsCountMetrics(); } if (state != State::kRunning) { // If check was running @@ -244,3 +249,27 @@ const CredentialUIEntry& credential) { insecure_credentials_manager_.UnmuteCredential(credential); } + +void IOSChromePasswordCheckManager::LogInsecureCredentialsCountMetrics() { + std::vector<CredentialUIEntry> insecure_credentials = + GetInsecureCredentials(); + std::set<std::pair<std::u16string, std::u16string>> unique_entries; + std::set<std::pair<std::u16string, std::u16string>> unique_unmuted_entries; + + for (const auto& credential : insecure_credentials) { + unique_entries.insert({credential.username, credential.password}); + for (const auto& [insecure_type, insecure_metadata] : + credential.password_issues) { + if (!insecure_metadata.is_muted.value()) { + unique_unmuted_entries.insert( + {credential.username, credential.password}); + break; + } + } + } + + password_manager::LogCountOfInsecureUsernamePasswordPairs( + unique_entries.size()); + password_manager::LogCountOfUnmutedInsecureUsernamePasswordPairs( + unique_unmuted_entries.size()); +}
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm index 2b04be1..7425592 100644 --- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm +++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm
@@ -16,6 +16,7 @@ #import "base/strings/string_util.h" #import "base/strings/utf_string_conversions.h" #import "base/test/bind.h" +#import "base/test/metrics/histogram_tester.h" #import "base/test/scoped_feature_list.h" #import "base/time/time.h" #import "components/keyed_service/core/service_access_type.h" @@ -33,6 +34,7 @@ #import "ios/chrome/browser/passwords/ios_chrome_bulk_leak_check_service_factory.h" #import "ios/chrome/browser/passwords/ios_chrome_password_check_manager_factory.h" #import "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h" +#import "ios/chrome/browser/passwords/password_checkup_metrics.h" #import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/shared/model/browser_state/test_chrome_browser_state.h" #import "ios/web/public/test/web_task_environment.h" @@ -247,6 +249,50 @@ EXPECT_NE(base::Time(), manager().GetLastPasswordCheckTime()); } +// Checks that insecure credential count metrics are logged after a check has +// finished. +TEST_F(IOSChromePasswordCheckManagerTest, InsecureCredentialCountsMetrics) { + base::HistogramTester histogram_tester; + + PasswordForm leaked_form = MakeSavedPassword(kExampleCom, kUsername116); + AddIssueToForm(&leaked_form, InsecureType::kLeaked, base::Minutes(1)); + store().AddLogin(leaked_form); + + PasswordForm phished_form = + MakeSavedPassword("https://site1.com", kUsername116); + AddIssueToForm(&phished_form, InsecureType::kPhished, base::Minutes(1)); + store().AddLogin(phished_form); + + PasswordForm weak_form = MakeSavedPassword("https://site1.com", kUsername116); + AddIssueToForm(&weak_form, InsecureType::kWeak, base::Minutes(1)); + store().AddLogin(weak_form); + + PasswordForm reused_form = + MakeSavedPassword("https://site2.com", kUsername116); + AddIssueToForm(&reused_form, InsecureType::kReused, base::Minutes(1)); + store().AddLogin(reused_form); + + // Adding a muted warning. This shouldn't be counted in the unmuted histogram. + PasswordForm muted_form = + MakeSavedPassword("https://site32.com", kUsername216); + AddIssueToForm(&muted_form, InsecureType::kLeaked, base::Minutes(1), + /*is_muted=*/true); + store().AddLogin(muted_form); + + manager().StartPasswordCheck(); + RunUntilIdle(); + + static_cast<BulkLeakCheckServiceInterface::Observer*>(&manager()) + ->OnStateChanged(BulkLeakCheckServiceInterface::State::kIdle); + + EXPECT_EQ(histogram_tester.GetTotalSum( + password_manager::kInsecureCredentialsCountHistogram), + 2); + EXPECT_EQ(histogram_tester.GetTotalSum( + password_manager::kUnmutedInsecureCredentialsCountHistogram), + 1); +} + // Tests whether adding and removing an observer works as expected. TEST_F(IOSChromePasswordCheckManagerTest, NotifyObserversAboutInsecureCredentialChanges) {
diff --git a/ios/chrome/browser/passwords/password_checkup_metrics.h b/ios/chrome/browser/passwords/password_checkup_metrics.h index 0c30cee..c8f26f61 100644 --- a/ios/chrome/browser/passwords/password_checkup_metrics.h +++ b/ios/chrome/browser/passwords/password_checkup_metrics.h
@@ -9,6 +9,14 @@ namespace password_manager { +// Name of the histogram for logging count of unique pairs of username and +// password present in insecure credential warnings. +extern const char kInsecureCredentialsCountHistogram[]; + +// Name of the histogram for logging count of unique pairs of username and +// password present in insecure credentials warnings not muted by the user. +extern const char kUnmutedInsecureCredentialsCountHistogram[]; + // Logs the user action of changing an insecure password on its affiliated // website. void LogChangePasswordOnWebsite(WarningType context); @@ -40,6 +48,14 @@ // Logs the user action of opening the password checkup home page. void LogOpenPasswordCheckupHomePage(); +// Logs the number of unique pairs of username and password present in an +// insecure credential warning. +void LogCountOfInsecureUsernamePasswordPairs(int count); + +// Logs the number of unique pairs of username and password present in an +// insecure credential warning not muted by the user. +void LogCountOfUnmutedInsecureUsernamePasswordPairs(int count); + } // namespace password_manager #endif // IOS_CHROME_BROWSER_PASSWORDS_PASSWORD_CHECKUP_METRICS_H_
diff --git a/ios/chrome/browser/passwords/password_checkup_metrics.mm b/ios/chrome/browser/passwords/password_checkup_metrics.mm index 935fe67..9247f7a 100644 --- a/ios/chrome/browser/passwords/password_checkup_metrics.mm +++ b/ios/chrome/browser/passwords/password_checkup_metrics.mm
@@ -82,6 +82,12 @@ namespace password_manager { +const char kInsecureCredentialsCountHistogram[] = + "PasswordManager.BulkCheck.InsecureCredentials.Count"; + +const char kUnmutedInsecureCredentialsCountHistogram[] = + "PasswordManager.BulkCheck.InsecureCredentials.Unmuted.Count"; + void LogChangePasswordOnWebsite(WarningType context) { LogPasswordCheckInteraction( PasswordCheckInteractionIOS::kChangePasswordOnWebsite, context); @@ -132,4 +138,13 @@ PasswordCheckInteractionIOSWithoutContext::kOpenCheckupHomepage); } +void LogCountOfInsecureUsernamePasswordPairs(int count) { + base::UmaHistogramCounts1000(kInsecureCredentialsCountHistogram, count); +} + +void LogCountOfUnmutedInsecureUsernamePasswordPairs(int count) { + base::UmaHistogramCounts1000(kUnmutedInsecureCredentialsCountHistogram, + count); +} + } // namespace password_manager
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm index c43a5dc..2a2f1ac5 100644 --- a/ios/chrome/browser/prefs/browser_prefs.mm +++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -225,6 +225,9 @@ registry->RegisterIntegerPref(kTrialGroupMICeAndDefaultBrowserVersionPrefName, -1); + registry->RegisterIntegerPref( + prefs::kIosCredentialProviderPromoLastActionTaken, -1); + registry->RegisterBooleanPref(prefs::kIosCredentialProviderPromoStopPromo, false);
diff --git a/ios/chrome/browser/prefs/pref_names.cc b/ios/chrome/browser/prefs/pref_names.cc index 44550b4..73bb413 100644 --- a/ios/chrome/browser/prefs/pref_names.cc +++ b/ios/chrome/browser/prefs/pref_names.cc
@@ -124,6 +124,10 @@ const char kIosBringAndroidTabsPromptDisplayed[] = "ios.bring_android_tabs.prompt_displayed"; +// Integer to record the last action that a user has taken on the CPE promo. +const char kIosCredentialProviderPromoLastActionTaken[] = + "ios.credential_provider_promo_last_action_taken"; + // Boolean that is true when the CredentialProviderPromoEnabled policy is // enabled. const char kIosCredentialProviderPromoPolicyEnabled[] =
diff --git a/ios/chrome/browser/prefs/pref_names.h b/ios/chrome/browser/prefs/pref_names.h index 12cc62b..d1b354a 100644 --- a/ios/chrome/browser/prefs/pref_names.h +++ b/ios/chrome/browser/prefs/pref_names.h
@@ -26,6 +26,7 @@ extern const char kHttpServerProperties[]; extern const char kInactiveTabsTimeThreshold[]; extern const char kIncognitoInterstitialEnabled[]; +extern const char kIosCredentialProviderPromoLastActionTaken[]; extern const char kIosCredentialProviderPromoPolicyEnabled[]; extern const char kIosCredentialProviderPromoStopPromo[]; extern const char kIosCredentialProviderPromoSource[];
diff --git a/ios/chrome/browser/search_engines/BUILD.gn b/ios/chrome/browser/search_engines/BUILD.gn index b1e2a4bae..261f931 100644 --- a/ios/chrome/browser/search_engines/BUILD.gn +++ b/ios/chrome/browser/search_engines/BUILD.gn
@@ -3,7 +3,7 @@ # found in the LICENSE file. import("//ios/build/chrome_build.gni") -import("//ios/web/public/js_messaging/optimize_js.gni") +import("//ios/web/public/js_messaging/optimize_ts.gni") import("//rlz/buildflags/buildflags.gni") source_set("search_engines") { @@ -135,9 +135,10 @@ configs += [ "//build/config/compiler:enable_arc" ] } -optimize_js("search_engine_js") { - primary_script = "resources/search_engine.js" - sources = [ "resources/search_engine.js" ] +optimize_ts("search_engine_js") { + sources = [ "resources/search_engine.ts" ] + + deps = [ "//ios/web/public/js_messaging:util_scripts" ] } source_set("eg_app_support+eg2") {
diff --git a/ios/chrome/browser/search_engines/resources/search_engine.js b/ios/chrome/browser/search_engines/resources/search_engine.js deleted file mode 100644 index fad1b502b..0000000 --- a/ios/chrome/browser/search_engines/resources/search_engine.js +++ /dev/null
@@ -1,308 +0,0 @@ -// Copyright 2018 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview Add functionality related to getting search engine details. - */ - -/** - * Encodes |url| in "application/x-www-form-urlencoded" content type of <form>. - * The standard is defined in: - * https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1 - * This solution comes from: - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent - * @private - */ -function encodeFormData_(url) { - return encodeURIComponent(url).replace('%20', '+'); -}; - -/** - * Returns if |element| can submit a form(i.e. <button> or <input - * type="submit">). - * @param {Element} element An element inside a <form>. - * @return {boolean} If |element| can submit the form. - * @private - */ -function isSubmitElement_(element) { - return (element.tagName == 'BUTTON') || - (element.tagName == 'INPUT' && element.type == 'submit'); -}; - -/** - * Returns if |element| is checkable(i.e. <input type="radio"> or <input - * type="checkbox">). - * @param {Element} element An element inside a <form>. - * @return {boolean} If |element| is checkable. - * @private - */ -function isCheckableElement_(element) { - return ( - element.tagName == 'INPUT' && - (element.type == 'radio' || element.type == 'checkbox')); -}; - -/** - * Records the active submit element of <form> being submitted. - * @type {Element} - * @private - */ -let activeSubmitElement_ = null; - -/** - * Returns the submit element which triggers the submission of |form|. If there - * is no submit element clicked before |form|'s submission, the first submit - * element of |form| will be returned. - * @param {Element} form The <form> on submission. - * @return {Element|undefined} The element which submits |form| or the first - * submit element in |form|. Returns undefined if not found. - * @private - */ -function getActiveSubmitElement_(form) { - if (activeSubmitElement_ && activeSubmitElement_.form === form) { - return activeSubmitElement_; - } - for (let i = 0; i < form.elements.length; ++i) { - if (isSubmitElement_(form.elements[i])) { - return form.elements[i]; - } - } -}; - -/** - * A set of all the text categories of <input>'s type attribute. - * This set is based on: - * https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/forms/text_field_input_type.h - * https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/forms/base_text_input_type.h - * "password" is not in the map because it makes the <form> invalid. - * @type {Set<string>} - * @private - */ -const textInputTypes_ = - new Set(['email', 'search', 'tel', 'text', 'url', 'number']); - -/** - * Returns false if |element| is <input type="radio|checkbox"> or <select> and - * it's not in its default state, otherwise true. The default state is the state - * of the form element on initial load of the page, and leties depending upon - * the form element. - * @param {Element} element Element in <form>. - * @return {boolean} If the element is in its default state. - * @private - */ -function isInDefaultState_(element) { - if (isCheckableElement_(element)) { - return element.checked == element.defaultChecked; - } else if (element.tagName == 'SELECT') { - for (let i = 0; i < element.options.length; ++i) { - let option = element.options[i]; - if (option.selected != option.defaultSelected) { - return false; - } - } - } - return true; -}; - -/** - * Looks for a suitable search text field in |form|. Returns undefined if |form| - * is not a valid searchable <form>. The code is based on the function with same - * name in: - * https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/exported/web_searchable_form_data.cc - * - * The criteria for a valid searchable <form>: - * 1. Has no <textarea>; - * 2. Has no <input type="password">; - * 3. Has no <input type="file">; - * 4. Has exactly one <input> with "type" from |textInputTypes_|; - * 5. Has no element that is not in default state; - * Any element that doesn't have "name" attribute or has "disabled" attribute - * will be ignored. - * - * @param {Element} form The form being submitted. - * @return {Element|undefined} The only one text <input> in |form|, or undefined - * if |form| is not a valid searchable <form>. - * @private - */ -function findSuitableSearchInputElement_(form) { - let result = undefined; - for (let i = 0; i < form.elements.length; ++i) { - let element = form.elements[i]; - if (element.disabled || !element.name) { - continue; - } - if (!isInDefaultState_(element) || element.tagName == 'TEXTAREA') { - return; - } - if (element.tagName == 'INPUT') { - if (element.type == 'file' || element.type == 'password') { - return; - } - if (textInputTypes_.has(element.type)) { - if (result) { - return; - } - result = element; - } - } - } - return result; -}; - -/** - * Generates a searchable URL from |form| if it's a valid searchable <form>. - * The code is based on the function with same name in: - * https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/exported/web_searchable_form_data.cc - * - * @param {Element} form The <form> element. - * @return {string|undefined} The searchable URL, or undefined if |form| is not - * a valid searchable <form>. - * @private - * TODO(crbug.com/433824): Use <form>'s "accept-charset" attribute to encode the - * searchableURL. - */ -function generateSearchableUrl_(form) { - // Only consider <form> that navigates in current frame, because currently - // TemplateURLs are created by SearchEngineTabHelper, which cannot handle - // navigation across WebState. - if (form.target && form.target != '_self') - return; - - // Only consider forms that GET data. - if (form.method && form.method.toLowerCase() != 'get') { - return; - } - - let searchInput = findSuitableSearchInputElement_(form); - if (!searchInput) { - return; - } - - let activeSubmitElement = getActiveSubmitElement_(form); - - // The "name=value" pairs appended to the end of the action URL. - let queryArgs = []; - for (let i = 0; i < form.elements.length; ++i) { - let element = form.elements[i]; - if (element.disabled || !element.name) { - continue; - } - if (isSubmitElement_(element)) { - // Only append the active submit element's name-value pair. - if (element === activeSubmitElement) { - let value = element.value; - // <input type="submit"> will have "Submit" as default "value" when - // submitted with empty "value" and non-empty "name". This probably - // comes from the default label text of <input type="submit">: - // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/submit - if (element.tagName == 'INPUT' && !value) { - value = 'Submit'; - } - queryArgs.push( - encodeFormData_(element.name) + '=' + encodeFormData_(value)); - } - continue; - } - if (element === searchInput) { - queryArgs.push(encodeFormData_(element.name) + '={searchTerms}'); - } else { - // Ignore unchecked checkable element. - if (isCheckableElement_(element) && !element.checked) { - continue; - } - queryArgs.push( - encodeFormData_(element.name) + '=' + encodeFormData_(element.value)); - } - } - // If |form| uses "GET" method, appended query args in |form|.action should be - // dropped. Use URL class to get rid of these query args. - let url = new URL(form.action); - return url.origin + url.pathname + '?' + queryArgs.join('&'); -}; - -/** - * Adds listener for 'click' event on |document|. When a submit element is - * clicked, records it in |activeSubmitElement_| for |generateSearchableUrl_|, - * which will be called in the 'submit' event callbacks within current call - * stack. Appends a callback at the end of Js task queue with timeout=0ms that - * sets |activeSubmitElement_| back to undefined after the submission. - * - * The call stack of form submission: - * User clicks button. - * "click" event emitted and bubbles up to |document|. - * Records current button as |activeSubmitElement_|. - * Posts callback that unsets active submit element by setTimeout(..., 0). - * "click" event ends. - * "submit" event emitted and bubbles up to |document|. - * Generates searchable URL based on |activeSubmitElement_|. - * "submit" event ends. - * Call stack of user's click on button finishes. - * ... - * Js task queue running... - * ... - * Callback posted by setTimeout(..., 0) is invoked and clean up - * |activeSubmitElement_|. - */ -document.addEventListener('click', function(event) { - if (event.defaultPrevented) { - return; - } - let element = event.target; - if (!(element instanceof Element) || !isSubmitElement_(element)) { - return; - } - activeSubmitElement_ = element; - setTimeout(function() { - if (activeSubmitElement_ === element) { - activeSubmitElement_ = null; - } - }, 0); -}); - -/** - * Adds listener for 'submit' event on |document|. When a <form> is submitted, - * try to generate a searchableUrl. If succeeded, send it back to native code. - * TODO(crbug.com/433824): Refactor /components/autofill/ios/form_util to reuse - * FormActivityObserver, so that all the data about form submission can be - * sent in a single message. - */ -document.addEventListener('submit', function(event) { - if (event.defaultPrevented || !(event.target instanceof Element)) { - return; - } - let url = generateSearchableUrl_(event.target); - if (url) { - __gCrWeb.common.sendWebKitMessage( 'SearchEngineMessage', - {'command': 'searchableUrl', 'url': url}); - } -}, false); - -/** - * Finds <link> of OSDD(Open Search Description Document) in the main frame. If - * found, sends a message containing the page's URL and OSDD's URL to native - * side. If the page has multiple OSDD <links>s (which should never happen on a - * sane web site), only send the first <link>. - * @return {undefined} - */ -function findOpenSearchLink() { - let links = document.getElementsByTagName('link'); - for (let i = 0; i < links.length; ++i) { - if (links[i].type == 'application/opensearchdescription+xml') { - __gCrWeb.common.sendWebKitMessage( 'SearchEngineMessage', { - 'command': 'openSearch', - 'pageUrl': document.URL, - 'osddUrl': links[i].href - }); - return; - } - }; -} - -// If document is loaded, finds the Open Search <link>, otherwise waits until -// it's loaded and then starts finding. -if (document.readyState == 'complete') { - findOpenSearchLink(); -} else { - window.addEventListener('load', findOpenSearchLink); -}
diff --git a/ios/chrome/browser/search_engines/resources/search_engine.ts b/ios/chrome/browser/search_engines/resources/search_engine.ts new file mode 100644 index 0000000..e9e785b --- /dev/null +++ b/ios/chrome/browser/search_engines/resources/search_engine.ts
@@ -0,0 +1,325 @@ +// Copyright 2018 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Add functionality related to getting search engine details. + */ + +import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js'; + +/** + * Encodes `url` in "application/x-www-form-urlencoded" content type of <form>. + * The standard is defined in: + * https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1 + * This solution comes from: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent + */ +function encodeFormData(url: string): string { + return encodeURIComponent(url).replace('%20', '+'); +}; + +/** + * Returns element if it's of a type that can submit a form or null otherwise. + */ +function asSubmitElement(element: Element): HTMLButtonElement|HTMLInputElement| + null { + if (element instanceof HTMLButtonElement) { + return element; + } + if (element instanceof HTMLInputElement && element.type === 'submit') { + return element; + } + return null; +}; + +/** + * Returns the value stored in the element's `name` property. If the + * element does not have the name property, then null is returned. + */ +function getElementName(element: Element): string|null { + return (element as Element & {'name': string}).name; +} + +/** + * Returns whether the element is disabled. If the element does not have the + * disabled property, then null is returned. + */ +function isDisabledElement(element: Element): boolean { + return (element as Element & {'disabled': boolean}).disabled; +} + +/** + * Returns if `element` is checkable(i.e. <input type="radio"> or <input + * type="checkbox">). + * @param element An element inside a <form>. + */ +function isCheckableElement(element: Element): boolean { + return element instanceof HTMLInputElement && + (element.type === 'radio' || element.type === 'checkbox'); +}; + +// Records the active submit element of <form> being submitted. +let activeSubmitElement: HTMLButtonElement|HTMLInputElement|null = null; + +/** + * Returns the submit element which triggers the submission of `form`. If there + * is no submit element clicked before `form`'s submission, the first submit + * element of `form` will be returned. Otherwise, returns undefined if not + * found. + * @param form The <form> on submission. + */ +function getActiveSubmitElement(form: HTMLFormElement): HTMLButtonElement| + HTMLInputElement|null { + if (activeSubmitElement && activeSubmitElement.form === form) { + return activeSubmitElement; + } + for (const element of form.elements) { + const submitElement = asSubmitElement(element); + if (submitElement) { + return submitElement + } + } + + return null; +}; + +/** + * A set of all the text categories of <input>'s type attribute. + * This set is based on: + * https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/forms/text_field_input_type.h + * https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/forms/base_text_input_type.h + * "password" is not in the map because it makes the <form> invalid. + */ +const TEXT_INPUT_TYPES = + new Set(['email', 'search', 'tel', 'text', 'url', 'number']); + +/** + * Returns false if `element` is <input type="radio|checkbox"> or <select> and + * it's not in its default state, otherwise true. The default state is the state + * of the form element on initial load of the page, and leties depending upon + * the form element. + * @param element an Element in <form>. + */ +function isInDefaultState(element: Element): boolean { + if (isCheckableElement(element)) { + const inputElement = element as HTMLInputElement; + return inputElement.checked === inputElement.defaultChecked; + } + + if (element instanceof HTMLSelectElement) { + for (const option of element.options) { + if (option.selected != option.defaultSelected) { + return false; + } + } + } + + return true; +}; + +/** + * Looks for a suitable search text field in |form|. Returns undefined if |form| + * is not a valid searchable <form>. The code is based on the function with same + * name in: + * https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/exported/web_searchable_form_data.cc + * + * The criteria for a valid searchable <form>: + * 1. Has no <textarea>; + * 2. Has no <input type="password">; + * 3. Has no <input type="file">; + * 4. Has exactly one <input> with "type" from `TEXT_INPUT_TYPES_`; + * 5. Has no element that is not in default state; + * Any element that doesn't have "name" attribute or has "disabled" attribute + * will be ignored. + * @param form The form being submitted. + */ +function findSuitableSearchInputElement(form: HTMLFormElement): + HTMLInputElement|undefined { + let result: HTMLInputElement|undefined = undefined; + for (const element of form.elements) { + if (isDisabledElement(element) || !getElementName(element)) { + continue; + } + if (!isInDefaultState(element) || element instanceof HTMLTextAreaElement) { + return; + } + if (element instanceof HTMLInputElement) { + if (element.type === 'file' || element.type === 'password') { + return; + } + if (TEXT_INPUT_TYPES.has(element.type)) { + if (result) { + return; + } + result = element; + } + } + } + return result; +}; + +/** + * Generates a searchable URL from `form` if it's a valid searchable <form>. + * The code is based on the function with same name in: + * https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/exported/web_searchable_form_data.cc + * TODO(crbug.com/433824): Use <form>'s "accept-charset" attribute to encode the + * searchableURL. + */ +function generateSearchableUrl(form: Element): string|undefined { + if (!(form instanceof HTMLFormElement)) { + return; + } + + // Only consider <form> that navigates in current frame, because currently + // TemplateURLs are created by SearchEngineTabHelper, which cannot handle + // navigation across WebState. + if (form.target && form.target !== '_self') + return; + + // Only consider forms that GET data. + if (form.method && form.method.toLowerCase() !== 'get') { + return; + } + + const searchInput = findSuitableSearchInputElement(form); + if (!searchInput) { + return; + } + + const activeSubmitElement = getActiveSubmitElement(form); + + // The "name=value" pairs appended to the end of the action URL. + const queryArgs: string[] = []; + for (const element of form.elements) { + const elementName = getElementName(element); + if (isDisabledElement(element) || !elementName) { + continue; + } + + const submitElement = asSubmitElement(element); + if (submitElement) { + // Only append the active submit element's name-value pair. + if (submitElement === activeSubmitElement) { + let value = submitElement.value; + // <input type="submit"> will have "Submit" as default "value" when + // submitted with empty "value" and non-empty "name". This probably + // comes from the default label text of <input type="submit">: + // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/submit + if (submitElement instanceof HTMLInputElement && !value) { + value = 'Submit'; + } + + queryArgs.push( + encodeFormData(elementName) + '=' + encodeFormData(value)); + } + continue; + } + if (element === searchInput) { + queryArgs.push(encodeFormData(elementName) + '={searchTerms}'); + } else { + // Ignore unchecked checkable element. + if (isCheckableElement(element) && + !(element as HTMLInputElement).checked) { + continue; + } + const elementValue = (element as Element & {'value': string}).value; + queryArgs.push( + encodeFormData(elementName) + '=' + encodeFormData(elementValue)); + } + } + // If `form` uses "GET" method, appended query args in `form`.action should be + // dropped. Use URL class to get rid of these query args. + const url = new URL(form.action); + return url.origin + url.pathname + '?' + queryArgs.join('&'); +}; + +/** + * Adds listener for 'click' event on `document`. When a submit element is + * clicked, records it in `activeSubmitElement` for `generateSearchableUrl`, + * which will be called in the 'submit' event callbacks within current call + * stack. Appends a callback at the end of Js task queue with timeout=0ms that + * sets `activeSubmitElement` back to undefined after the submission. + * + * The call stack of form submission: + * User clicks button. + * "click" event emitted and bubbles up to `document`. + * Records current button as `activeSubmitElement`. + * Posts callback that unsets active submit element by setTimeout(..., 0). + * "click" event ends. + * "submit" event emitted and bubbles up to `document`. + * Generates searchable URL based on `activeSubmitElement`. + * "submit" event ends. + * Call stack of user's click on button finishes. + * ... + * Js task queue running... + * ... + * Callback posted by setTimeout(..., 0) is invoked and clean up + * `activeSubmitElement`. + */ +document.addEventListener('click', function(event) { + if (event.defaultPrevented) { + return; + } + let element = event.target; + + if (!(element instanceof Element)) { + return; + } + const submitElement = asSubmitElement(element); + if (!submitElement) { + return; + } + activeSubmitElement = submitElement; + setTimeout(function() { + if (activeSubmitElement === element) { + activeSubmitElement = null; + } + }, 0); +}); + +/** + * Adds listener for 'submit' event on `document`. When a <form> is submitted, + * try to generate a searchableUrl. If succeeded, send it back to native code. + * TODO(crbug.com/433824): Refactor /components/autofill/ios/form_util to reuse + * FormActivityObserver, so that all the data about form submission can be + * sent in a single message. + */ +document.addEventListener('submit', function(event) { + if (event.defaultPrevented || !(event.target instanceof Element)) { + return; + } + const url = generateSearchableUrl(event.target); + if (url) { + sendWebKitMessage( + 'SearchEngineMessage', {'command': 'searchableUrl', 'url': url}); + } +}, false); + +/** + * Finds <link> of OSDD(Open Search Description Document) in the main frame. If + * found, sends a message containing the page's URL and OSDD's URL to native + * side. If the page has multiple OSDD <links>s (which should never happen on a + * sane web site), only send the first <link>. + */ +function findOpenSearchLink(): void { + const links = document.getElementsByTagName('link'); + for (const link of links) { + if (link.type == 'application/opensearchdescription+xml') { + sendWebKitMessage('SearchEngineMessage', { + 'command': 'openSearch', + 'pageUrl': document.URL, + 'osddUrl': link.href + }); + return; + } + }; +} + +// If document is loaded, finds the Open Search <link>, otherwise waits until +// it's loaded and then starts finding. +if (document.readyState === 'complete') { + findOpenSearchLink(); +} else { + window.addEventListener('load', findOpenSearchLink); +}
diff --git a/ios/chrome/browser/shared/public/commands/bookmarks_commands.h b/ios/chrome/browser/shared/public/commands/bookmarks_commands.h index b65a04d..35dcc4d 100644 --- a/ios/chrome/browser/shared/public/commands/bookmarks_commands.h +++ b/ios/chrome/browser/shared/public/commands/bookmarks_commands.h
@@ -10,6 +10,7 @@ #import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h" +class GURL; @class ReadingListAddCommand; // Protocol for commands arounds Bookmarks manipulation. @@ -25,8 +26,8 @@ - (void)bookmark:(BookmarkAddCommand*)command; // Opens the Bookmarks UI in edit mode and selects the bookmark node -// corresponding to the values provided within `command`. -- (void)openToExternalBookmark:(BookmarkAddCommand*)command; +// corresponding to `URL`. +- (void)openToExternalBookmark:(GURL)URL; @end
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm index a062419..3a4c783 100644 --- a/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm +++ b/ios/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
@@ -563,15 +563,13 @@ [self presentFolderChooser]; } -- (void)openToExternalBookmark:(BookmarkAddCommand*)command { - if (!_profileBookmarkModel->loaded() || command.URLs.count != 1 || - command.presentFolderChooser) { +- (void)openToExternalBookmark:(GURL)URL { + if (!_profileBookmarkModel->loaded()) { return; } const BookmarkNode* existingBookmark = - _profileBookmarkModel->GetMostRecentlyAddedUserNodeForURL( - command.URLs.firstObject.URL); + _profileBookmarkModel->GetMostRecentlyAddedUserNodeForURL(URL); [self presentBookmarksAtDisplayedFolderNode:_profileBookmarkModel->mobile_node() selectingBookmark:existingBookmark];
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 e678159..1947209 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -944,7 +944,7 @@ if (self.bottomPosition) return NO; - return YES; + return self.viewVisible; } #pragma mark - UIViewController
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.mm b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.mm index a850d28e..d88d621 100644 --- a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.mm +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.mm
@@ -196,6 +196,9 @@ credential_provider_promo::RecordAction( [self.mediator promoOriginalSource], self.trigger == CredentialProviderPromoTrigger::RemindMeLater, action); + GetApplicationContext()->GetLocalState()->SetInteger( + prefs::kIosCredentialProviderPromoLastActionTaken, + static_cast<int>(action)); } @end
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator_unittest.mm b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator_unittest.mm index 4ccfe35..b73d8ce 100644 --- a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator_unittest.mm +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator_unittest.mm
@@ -24,6 +24,8 @@ #error "This file requires ARC support." #endif +using credential_provider_promo::IOSCredentialProviderPromoAction; + // Test fixture for testing the CredentialProviderPromoCoordinator class. class CredentialProviderPromoCoordinatorTest : public PlatformTest { public: @@ -45,6 +47,13 @@ } ~CredentialProviderPromoCoordinatorTest() override { [coordinator_ stop]; } + // Returns the last action taken by the user on the promo that is stored in + // local state. + int LastActionTaken() { + return local_state_.Get()->GetInteger( + prefs::kIosCredentialProviderPromoLastActionTaken); + } + protected: web::WebTaskEnvironment task_environment_; IOSChromeScopedTestingLocalState local_state_; @@ -225,3 +234,21 @@ kGoToSettings, 1); } + +// Tests that the last action taken is recorded in local state. +TEST_F(CredentialProviderPromoCoordinatorTest, LastActionTaken) { + // Trigger the promo with SetUpList. The primary CTA of the promo, when + // triggered from SetUpList, is 'go to settings'. + [credential_provider_promo_command_handler_ + showCredentialProviderPromoWithTrigger:CredentialProviderPromoTrigger:: + SetUpList]; + EXPECT_EQ(LastActionTaken(), -1); + + // Perform the action. Coordinator will record the action 'go to settings'. + ASSERT_TRUE([coordinator_ + conformsToProtocol:@protocol(ConfirmationAlertActionHandler)]); + [(id<ConfirmationAlertActionHandler>) + coordinator_ confirmationAlertPrimaryAction]; + EXPECT_EQ(LastActionTaken(), + static_cast<int>(IOSCredentialProviderPromoAction::kGoToSettings)); +}
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_content_delegate.h b/ios/chrome/browser/ui/ntp/new_tab_page_content_delegate.h index 1836cda..f0eda2c 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_content_delegate.h +++ b/ios/chrome/browser/ui/ntp/new_tab_page_content_delegate.h
@@ -8,9 +8,6 @@ // Delegate for actions relating to the NTP content. @protocol NewTabPageContentDelegate -// Reloads content suggestions collection view. -- (void)reloadContentSuggestions; - // YES if the content requires the header to stick while scrolling. - (BOOL)isContentHeaderSticky;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm index 624f963..cadefe0 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -459,7 +459,6 @@ [self.NTPViewController resetStateUponReload]; self.discoverFeedService->RefreshFeed( FeedRefreshTrigger::kForegroundUserTriggered); - [self reloadContentSuggestions]; } - (void)locationBarDidBecomeFirstResponder { @@ -1118,13 +1117,6 @@ #pragma mark - NewTabPageContentDelegate -- (void)reloadContentSuggestions { - // No need to reload ContentSuggestions since the mediator receives all - // model state changes and immediately updates the consumer with the new - // state. - return; -} - - (BOOL)isContentHeaderSticky { return [self isFollowingFeedAvailable] && [self isFeedHeaderVisible] && !IsStickyHeaderDisabledForFollowingFeed();
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm index a3e4838..a2fe45dc 100644 --- a/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm +++ b/ios/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
@@ -386,7 +386,6 @@ -([self stickyOmniboxHeight] + [self feedHeaderHeight]); [self.contentSuggestionsViewController.view setNeedsLayout]; [self.contentSuggestionsViewController.view layoutIfNeeded]; - [self.ntpContentDelegate reloadContentSuggestions]; } if (previousTraitCollection.preferredContentSizeCategory !=
diff --git a/ios/chrome/browser/ui/price_notifications/BUILD.gn b/ios/chrome/browser/ui/price_notifications/BUILD.gn index dc1bbcf..0cf4eb2d 100644 --- a/ios/chrome/browser/ui/price_notifications/BUILD.gn +++ b/ios/chrome/browser/ui/price_notifications/BUILD.gn
@@ -36,6 +36,7 @@ "//ios/chrome/browser/shared/public/commands", "//ios/chrome/browser/shared/ui/table_view", "//ios/chrome/browser/shared/ui/table_view:utils", + "//ios/chrome/browser/tabs", "//ios/chrome/browser/ui/price_notifications/cells", "//url", ]
diff --git a/ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.mm b/ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.mm index d39c31e..132e723 100644 --- a/ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.mm +++ b/ios/chrome/browser/ui/price_notifications/price_notifications_price_tracking_mediator.mm
@@ -18,9 +18,9 @@ #import "ios/chrome/browser/push_notification/push_notification_client_id.h" #import "ios/chrome/browser/push_notification/push_notification_service.h" #import "ios/chrome/browser/push_notification/push_notification_util.h" -#import "ios/chrome/browser/shared/public/commands/bookmark_add_command.h" #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h" #import "ios/chrome/browser/shared/public/commands/price_notifications_commands.h" +#import "ios/chrome/browser/tabs/tab_title_util.h" #import "ios/chrome/browser/ui/price_notifications/cells/price_notifications_table_view_item.h" #import "ios/chrome/browser/ui/price_notifications/price_notifications_alert_presenter.h" #import "ios/chrome/browser/ui/price_notifications/price_notifications_consumer.h" @@ -170,10 +170,8 @@ - (void)navigateToBookmarks { [self.handler hidePriceNotifications]; - BookmarkAddCommand* command = - [[BookmarkAddCommand alloc] initWithWebState:self.webState - presentFolderChooser:NO]; - [self.bookmarksHandler openToExternalBookmark:command]; + GURL URL = _webState->GetLastCommittedURL(); + [self.bookmarksHandler openToExternalBookmark:URL]; } #pragma mark - Private
diff --git a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_coordinator.mm index d956642b..eedd11e 100644 --- a/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_checkup/password_checkup_coordinator.mm
@@ -143,6 +143,11 @@ [self stopPasswordIssuesCoordinator]; } +- (void)setShouldDismissOnAllIssuesGone { + // No-op: This method is only used in the context of a + // PasswordIssuesCoordinator. +} + #pragma mark - Private - (void)stopPasswordIssuesCoordinator {
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm index 9d73a58..9d999087 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator.mm
@@ -283,10 +283,13 @@ title:title message:message barButtonItem:self.viewController.deleteButton]; + + __weak __typeof(self.delegate) weakDelegate = self.delegate; __weak __typeof(self.mediator) weakMediator = self.mediator; [self.actionSheetCoordinator addItemWithTitle:buttonText action:^{ + [weakDelegate passwordDetailsWillDeletePassword]; [weakMediator removeCredential:password]; } style:UIAlertActionStyleDestructive];
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h index 1b0aacde..6173810 100644 --- a/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h +++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_coordinator_delegate.h
@@ -14,6 +14,10 @@ - (void)passwordDetailsCoordinatorDidRemove: (PasswordDetailsCoordinator*)coordinator; +// Called when a passwword is currently being deleted from the +// details page. +- (void)passwordDetailsWillDeletePassword; + @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_DETAILS_PASSWORD_DETAILS_COORDINATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.h b/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.h index 6fa0341..9734d16 100644 --- a/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.h +++ b/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.h
@@ -23,6 +23,17 @@ - (void)passwordIssuesCoordinatorDidRemove: (PasswordIssuesCoordinator*)coordinator; +// Called by a PasswordIssuesCoordinator child to tell its +// PasswordIssuesCoordinator parent to dismiss its own +// PasswordIssuesTableViewController when all password issues are gone. This +// happens when the PasswordIssuesCoordinator child gets notified by its +// PasswordDetailsCoordinator that a password will be deleted from the password +// details page. A PasswordIssuesCoordinator should dismiss its +// PasswordIssuesTableViewController immediately after being notified that all +// issues are gone only when its last issue was resolved from a password +// deletion from the details page. +- (void)setShouldDismissOnAllIssuesGone; + @end // This coordinator presents a list of compromised credentials for the user.
diff --git a/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.mm b/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.mm index 5ed2276..322947ad 100644 --- a/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/password_issues/password_issues_coordinator.mm
@@ -66,6 +66,18 @@ // Coordinator for password issues displaying dismissed compromised // credentials. PasswordIssuesCoordinator* _dismissedPasswordIssuesCoordinator; + + // Flag indicating if the coordinator should dismiss its view controller + // because the last password issue was resolved by a password deletion. + BOOL _shouldDismissOnAllIssuesGone; + + // Flag indicating if the coordinator should dismiss its view controller after + // the view controller of a child coordinator is removed from the stack. When + // the issues and dismissed warnings are removed by the user, the coordinator + // should dismiss its view controller and go back to the previous screen. If + // there are child coordinators, this flag is used to dismiss the view + // controller after the children are dismissed. + BOOL _shouldDismissAfterChildCoordinatorRemoved; } // Main view controller for this coordinator. @@ -183,6 +195,72 @@ } - (void)dismissAfterAllIssuesGone { + // Early return if the last issue was not resolved by a password deletion, but + // by a password change. When the last issue is resolved by a password change, + // the details page has to be dismissed manually by the user. + if (_shouldDismissOnAllIssuesGone) { + [self navigateToPreviousViewController]; + } else { + _shouldDismissAfterChildCoordinatorRemoved = YES; + } +} + +#pragma mark - PasswordDetailsCoordinatorDelegate + +- (void)passwordDetailsCoordinatorDidRemove: + (PasswordDetailsCoordinator*)coordinator { + DCHECK_EQ(self.passwordDetails, coordinator); + [self.passwordDetails stop]; + self.passwordDetails.delegate = nil; + self.passwordDetails = nil; + + [self onChildCoordinatorDidRemove]; +} + +- (void)passwordDetailsWillDeletePassword { + _shouldDismissOnAllIssuesGone = self.mediator.hasOneIssueLeft; + [self.delegate setShouldDismissOnAllIssuesGone]; +} + +#pragma mark - PasswordIssuesCoordinatorDelegate + +- (void)passwordIssuesCoordinatorDidRemove: + (PasswordIssuesCoordinator*)coordinator { + CHECK_EQ(_dismissedPasswordIssuesCoordinator, coordinator); + [self stopDismissedPasswordIssuesCoordinator]; + + [self onChildCoordinatorDidRemove]; +} + +- (void)setShouldDismissOnAllIssuesGone { + _shouldDismissOnAllIssuesGone = self.mediator.hasOneIssueLeft; +} + +#pragma mark - Private + +- (void)stopDismissedPasswordIssuesCoordinator { + [_dismissedPasswordIssuesCoordinator stop]; + _dismissedPasswordIssuesCoordinator.reauthModule = nil; + _dismissedPasswordIssuesCoordinator.delegate = nil; + _dismissedPasswordIssuesCoordinator = nil; +} + +// Called after the view controller of a child coordinator of `self` was removed +// from the navigation stack. +- (void)onChildCoordinatorDidRemove { + // If the content of the view controller was gone while a child coordinator + // was presenting content, dismiss the view controller now that the child + // coordinator's vc was removed. + if (_shouldDismissAfterChildCoordinatorRemoved) { + CHECK_EQ(self.baseNavigationController.topViewController, + self.viewController); + _shouldDismissAfterChildCoordinatorRemoved = NO; + [self.baseNavigationController popViewControllerAnimated:NO]; + } +} + +// Navigates to the previous view controller in the navigation stack. +- (void)navigateToPreviousViewController { UINavigationController* baseNavigationController = self.baseNavigationController; NSInteger indexInNavigationController = @@ -204,31 +282,4 @@ animated:YES]; } -#pragma mark - PasswordDetailsCoordinatorDelegate - -- (void)passwordDetailsCoordinatorDidRemove: - (PasswordDetailsCoordinator*)coordinator { - DCHECK_EQ(self.passwordDetails, coordinator); - [self.passwordDetails stop]; - self.passwordDetails.delegate = nil; - self.passwordDetails = nil; -} - -#pragma mark - PasswordIssuesCoordinatorDelegate - -- (void)passwordIssuesCoordinatorDidRemove: - (PasswordIssuesCoordinator*)coordinator { - CHECK_EQ(_dismissedPasswordIssuesCoordinator, coordinator); - [self stopDismissedPasswordIssuesCoordinator]; -} - -#pragma mark - Private - -- (void)stopDismissedPasswordIssuesCoordinator { - [_dismissedPasswordIssuesCoordinator stop]; - _dismissedPasswordIssuesCoordinator.reauthModule = nil; - _dismissedPasswordIssuesCoordinator.delegate = nil; - _dismissedPasswordIssuesCoordinator = nil; -} - @end
diff --git a/ios/chrome/browser/ui/settings/password/password_issues/password_issues_mediator.mm b/ios/chrome/browser/ui/settings/password/password_issues/password_issues_mediator.mm index 5542dbb24..01d866e7 100644 --- a/ios/chrome/browser/ui/settings/password/password_issues/password_issues_mediator.mm +++ b/ios/chrome/browser/ui/settings/password/password_issues/password_issues_mediator.mm
@@ -246,6 +246,10 @@ } - (BOOL)hasOneIssueLeft { + if (_warningType == WarningType::kReusedPasswordsWarning) { + return _insecureCredentials.has_value() && + _insecureCredentials->size() == 2; + } return _insecureCredentials.has_value() && _insecureCredentials->size() == 1 && _dismissedWarningsCount == 0; }
diff --git a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm index fdc72cf..967a145 100644 --- a/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm +++ b/ios/chrome/browser/ui/settings/password/passwords_coordinator.mm
@@ -351,6 +351,11 @@ self.passwordIssuesCoordinator = nil; } +- (void)setShouldDismissOnAllIssuesGone { + // No-op: This method is only used in the context of a + // PasswordIssuesCoordinator. +} + #pragma mark - PasswordCheckupCoordinatorDelegate - (void)passwordCheckupCoordinatorDidRemove: @@ -371,6 +376,11 @@ self.passwordDetailsCoordinator = nil; } +- (void)passwordDetailsWillDeletePassword { + // No-op: This method is only used when the Password Details page is presented + // from a PasswordIssuesCoordinator. +} + #pragma mark AddPasswordDetailsCoordinatorDelegate - (void)passwordDetailsTableViewControllerDidFinish:
diff --git a/ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.mm b/ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.mm index 982b4f1..df2f977 100644 --- a/ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.mm +++ b/ios/chrome/browser/ui/settings/safety_check/safety_check_coordinator.mm
@@ -284,6 +284,11 @@ self.passwordIssuesCoordinator = nil; } +- (void)setShouldDismissOnAllIssuesGone { + // No-op: This method is only used in the context of a + // PasswordIssuesCoordinator. +} + #pragma mark - PrivacySafeBrowsingCoordinatorDelegate - (void)privacySafeBrowsingCoordinatorDidRemove:
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm index 33ef0db0..4805124 100644 --- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm +++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -769,6 +769,11 @@ self.passwordDetailsCoordinator = nil; } +- (void)passwordDetailsWillDeletePassword { + // No-op: This method is only used when the Password Details page is presented + // from a PasswordIssuesCoordinator. +} + #pragma mark - ClearBrowsingDataCoordinatorDelegate - (void)clearBrowsingDataCoordinatorViewControllerWasRemoved:
diff --git a/ios/web/content/BUILD.gn b/ios/web/content/BUILD.gn index f5aa0d2..2724bf1 100644 --- a/ios/web/content/BUILD.gn +++ b/ios/web/content/BUILD.gn
@@ -11,6 +11,8 @@ sources = [ "content_browser_context.h", "content_browser_context.mm", + "js_messaging/content_java_script_feature_manager.h", + "js_messaging/content_java_script_feature_manager.mm", "js_messaging/content_web_frame.h", "js_messaging/content_web_frame.mm", "js_messaging/content_web_frames_manager.h",
diff --git a/ios/web/content/init/ios_content_renderer_client.cc b/ios/web/content/init/ios_content_renderer_client.cc index 75a4065..2cde335 100644 --- a/ios/web/content/init/ios_content_renderer_client.cc +++ b/ios/web/content/init/ios_content_renderer_client.cc
@@ -25,8 +25,9 @@ void IOSContentRendererClient::RunScriptsAtDocumentStart( content::RenderFrame* render_frame) { - // TODO(crbug.com/1423527): Inject document start scripts from - // JavaScriptFeatures. + js_injection::JsCommunication* communication = + js_injection::JsCommunication::Get(render_frame); + communication->RunScriptsAtDocumentStart(); } void IOSContentRendererClient::RunScriptsAtDocumentEnd(
diff --git a/ios/web/content/js_messaging/content_java_script_feature_manager.h b/ios/web/content/js_messaging/content_java_script_feature_manager.h new file mode 100644 index 0000000..2210075 --- /dev/null +++ b/ios/web/content/js_messaging/content_java_script_feature_manager.h
@@ -0,0 +1,66 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_WEB_CONTENT_JS_MESSAGING_CONTENT_JAVA_SCRIPT_FEATURE_MANAGER_H_ +#define IOS_WEB_CONTENT_JS_MESSAGING_CONTENT_JAVA_SCRIPT_FEATURE_MANAGER_H_ + +#import <set> +#import <string> +#import <vector> + +namespace content { +class RenderFrameHost; +} + +namespace js_injection { +class JsCommunicationHost; +} + +namespace web { + +class JavaScriptFeature; + +// Configures JavaScriptFeatures, by injecting document start and end scripts, +// and owning a mapping for routing script message callbacks. +class ContentJavaScriptFeatureManager { + public: + explicit ContentJavaScriptFeatureManager( + std::vector<JavaScriptFeature*> features); + ~ContentJavaScriptFeatureManager(); + + ContentJavaScriptFeatureManager(const ContentJavaScriptFeatureManager&) = + delete; + ContentJavaScriptFeatureManager& operator=( + const ContentJavaScriptFeatureManager&) = delete; + + // Adds document start scripts for the configured features, to the given + // `js_communication_host`. + void AddDocumentStartScripts( + js_injection::JsCommunicationHost* js_communication_host); + + // Injects document end scripts for the configured features, into the given + // `render_frame_host`. + void InjectDocumentEndScripts(content::RenderFrameHost* render_frame_host); + + // Returns true if this feature manager already has the given `feature`. + bool HasFeature(const JavaScriptFeature* feature) const; + + private: + // Adds the given `feature` to the set of features managed by this feature + // manager, unless the given `feature` has already been added. + void AddFeature(const JavaScriptFeature* feature); + + // The features which are managed by this feature manager. + std::set<const JavaScriptFeature*> features_; + + // Scripts that are injected when the document element is created. + std::vector<std::u16string> document_start_scripts_; + + // Scripts that are injected after the document has loaded. + std::vector<std::u16string> document_end_scripts_; +}; + +} // namespace web + +#endif // IOS_WEB_CONTENT_JS_MESSAGING_CONTENT_JAVA_SCRIPT_FEATURE_MANAGER_H_
diff --git a/ios/web/content/js_messaging/content_java_script_feature_manager.mm b/ios/web/content/js_messaging/content_java_script_feature_manager.mm new file mode 100644 index 0000000..13ac49c --- /dev/null +++ b/ios/web/content/js_messaging/content_java_script_feature_manager.mm
@@ -0,0 +1,97 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/web/content/js_messaging/content_java_script_feature_manager.h" + +#import "base/ios/ios_util.h" +#import "base/strings/string_util.h" +#import "base/strings/sys_string_conversions.h" +#import "components/js_injection/browser/js_communication_host.h" +#import "content/public/browser/render_frame_host.h" +#import "ios/web/public/js_messaging/java_script_feature.h" +#import "ios/web/public/js_messaging/java_script_feature_util.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +namespace web { + +namespace { + +std::u16string MakeInjectableIntoMainFrameOnly(const std::u16string& script) { + std::u16string format_string = u"if (window == window.top) { $1 }"; + return base::ReplaceStringPlaceholders(format_string, script, + /*offset=*/nullptr); +} + +} // namespace + +ContentJavaScriptFeatureManager::ContentJavaScriptFeatureManager( + std::vector<JavaScriptFeature*> features) { + for (JavaScriptFeature* feature : features) { + AddFeature(feature); + } +} + +ContentJavaScriptFeatureManager::~ContentJavaScriptFeatureManager() {} + +void ContentJavaScriptFeatureManager::AddDocumentStartScripts( + js_injection::JsCommunicationHost* js_communication_host) { + for (std::u16string user_script : document_start_scripts_) { + js_communication_host->AddDocumentStartJavaScript(user_script, {"*"}); + } +} + +void ContentJavaScriptFeatureManager::InjectDocumentEndScripts( + content::RenderFrameHost* render_frame_host) { + for (std::u16string user_script : document_end_scripts_) { + render_frame_host->ExecuteJavaScript( + user_script, content::RenderFrameHost::JavaScriptResultCallback()); + } +} + +bool ContentJavaScriptFeatureManager::HasFeature( + const JavaScriptFeature* feature) const { + return features_.find(feature) != features_.end(); +} + +void ContentJavaScriptFeatureManager::AddFeature( + const JavaScriptFeature* feature) { + if (HasFeature(feature)) { + return; + } + + features_.insert(feature); + + // Add dependent features. + for (const JavaScriptFeature* dep_feature : feature->GetDependentFeatures()) { + AddFeature(dep_feature); + } + + // Setup user scripts. + for (const JavaScriptFeature::FeatureScript& feature_script : + feature->GetScripts()) { + std::u16string user_script = + base::SysNSStringToUTF16(feature_script.GetScriptString()); + bool main_frame_only = + feature_script.GetTargetFrames() != + JavaScriptFeature::FeatureScript::TargetFrames::kAllFrames; + + if (main_frame_only) { + user_script = MakeInjectableIntoMainFrameOnly(user_script); + } + + if (feature_script.GetInjectionTime() == + JavaScriptFeature::FeatureScript::InjectionTime::kDocumentStart) { + document_start_scripts_.push_back(user_script); + } else { + document_end_scripts_.push_back(user_script); + } + } + + // TODO(crbug.com/1423527): Add mapping for script message handlers. +} + +} // namespace web
diff --git a/ios/web/content/js_messaging/content_web_frames_manager.h b/ios/web/content/js_messaging/content_web_frames_manager.h index d650b030..920dea731 100644 --- a/ios/web/content/js_messaging/content_web_frames_manager.h +++ b/ios/web/content/js_messaging/content_web_frames_manager.h
@@ -22,6 +22,7 @@ namespace web { +class ContentJavaScriptFeatureManager; class ContentWebState; // ContentWebFramesManager is a WebFramesManager that is built on top @@ -45,6 +46,7 @@ // WebContentsObserver overrides. void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override; void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; + void DOMContentLoaded(content::RenderFrameHost* render_frame_host) override; void PrimaryPageChanged(content::Page& page) override; void DidFinishNavigation( content::NavigationHandle* navigation_handle) override; @@ -72,6 +74,9 @@ // Used for receiving messages from JavaScript. std::unique_ptr<js_injection::JsCommunicationHost> js_communication_host_; + + // Manages JavaScriptFeatures. + std::unique_ptr<ContentJavaScriptFeatureManager> js_feature_manager_; }; } // namespace web
diff --git a/ios/web/content/js_messaging/content_web_frames_manager.mm b/ios/web/content/js_messaging/content_web_frames_manager.mm index eaa7d55..192a2b4 100644 --- a/ios/web/content/js_messaging/content_web_frames_manager.mm +++ b/ios/web/content/js_messaging/content_web_frames_manager.mm
@@ -11,9 +11,11 @@ #import "content/public/browser/navigation_handle.h" #import "content/public/browser/page.h" #import "content/public/browser/web_contents.h" +#import "ios/web/content/js_messaging/content_java_script_feature_manager.h" #import "ios/web/content/js_messaging/content_web_frame.h" #import "ios/web/content/js_messaging/ios_web_message_host_factory.h" #import "ios/web/content/web_state/content_web_state.h" +#import "ios/web/public/js_messaging/java_script_feature_util.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -31,6 +33,23 @@ auto message_host_factory = std::make_unique<IOSWebMessageHostFactory>(); js_communication_host_->AddWebMessageHostFactory( std::move(message_host_factory), u"webkitMessageHandler", {"*"}); + + std::vector<JavaScriptFeature*> java_script_features; + java_script_features.push_back( + java_script_features::GetBaseJavaScriptFeature()); + + // TODO(crbug.com/1423527): Insert another feature that overrides the + // definition of sendWebKitMessage from common.js, to use + // webkitMessageHandler.postMessage. + java_script_features.push_back( + java_script_features::GetCommonJavaScriptFeature()); + java_script_features.push_back( + java_script_features::GetMessageJavaScriptFeature()); + + // TODO(crbug.com/1423527): Insert other JavaScriptFeatures. + js_feature_manager_ = std::make_unique<ContentJavaScriptFeatureManager>( + std::move(java_script_features)); + js_feature_manager_->AddDocumentStartScripts(js_communication_host_.get()); } ContentWebFramesManager::~ContentWebFramesManager() = default; @@ -103,6 +122,11 @@ content_to_web_id_map_.erase(web_id_it); } +void ContentWebFramesManager::DOMContentLoaded( + content::RenderFrameHost* render_frame_host) { + js_feature_manager_->InjectDocumentEndScripts(render_frame_host); +} + void ContentWebFramesManager::PrimaryPageChanged(content::Page& page) { main_frame_content_id_ = page.GetMainDocument().GetGlobalId(); } @@ -118,6 +142,9 @@ return; } + // TODO(crbug.com/1423527): Inject JavaScript to override `getFrameId` to + // return the WebFrame id chosen in `RenderFrameCreated`. + content::GlobalRenderFrameHostId content_id = render_frame_host->GetGlobalId(); if (available_frame_hosts_.count(content_id)) {
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn index b878242..5bd9bfe 100644 --- a/ios/web_view/BUILD.gn +++ b/ios/web_view/BUILD.gn
@@ -351,6 +351,7 @@ "//components/translate/ios/browser", "//components/unified_consent", "//components/update_client", + "//components/update_client:buildflags", "//components/update_client:common_impl", "//components/url_formatter", "//components/variations",
diff --git a/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm b/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm index 2e625d1..d1ec790 100644 --- a/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm +++ b/ios/web_view/internal/component_updater/web_view_component_updater_configurator.mm
@@ -12,12 +12,15 @@ #import <vector> #import "base/containers/flat_map.h" +#import "base/files/file_path.h" +#import "base/path_service.h" #import "base/version.h" #import "components/component_updater/component_updater_command_line_config_policy.h" #import "components/component_updater/configurator_impl.h" #import "components/services/patch/in_process_file_patcher.h" #import "components/services/unzip/in_process_unzipper.h" #import "components/update_client/activity_data_service.h" +#import "components/update_client/buildflags.h" #import "components/update_client/crx_downloader_factory.h" #import "components/update_client/net/network_chromium.h" #import "components/update_client/patch/patch_impl.h" @@ -75,6 +78,9 @@ GetProtocolHandlerFactory() const override; absl::optional<bool> IsMachineExternallyManaged() const override; update_client::UpdaterStateProvider GetUpdaterStateProvider() const override; +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) + absl::optional<base::FilePath> GetCrxCachePath() const override; +#endif private: friend class base::RefCountedThreadSafe<WebViewConfigurator>; @@ -229,6 +235,16 @@ return configurator_impl_.GetUpdaterStateProvider(); } +#if BUILDFLAG(ENABLE_PUFFIN_PATCHES) +absl::optional<base::FilePath> WebViewConfigurator::GetCrxCachePath() const { + base::FilePath path; + if (!base::PathService::Get(base::DIR_CACHE, &path)) { + return absl::nullopt; + } + return path.Append(FILE_PATH_LITTERAL("ios_webview_crx_cache")); +} +#endif + } // namespace scoped_refptr<update_client::Configurator> MakeComponentUpdaterConfigurator(
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 95e4be74..4cc47611 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -585,6 +585,12 @@ "OpenscreenCastStreamingSession", base::FEATURE_DISABLED_BY_DEFAULT); +// Controls whether or not frame drops are included in the video bitrate +// calculation for the OpenscreenFrameSender backed VideoSender implementation. +BASE_FEATURE(kOpenscreenVideoBitrateFactorInFrameDrops, + "OpenscreenVideoBitrateFactorInFrameDrops", + base::FEATURE_ENABLED_BY_DEFAULT); + // Controls whether the Mirroring Service will fetch, analyze, and store // information on the quality of the session using RTCP logs. BASE_FEATURE(kEnableRtcpReporting,
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index 3cae6c1..fd5a333 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -262,6 +262,7 @@ MEDIA_EXPORT extern const base::FeatureParam<int> kShareThisTabDialogActivationDelayMs; MEDIA_EXPORT BASE_DECLARE_FEATURE(kOpenscreenCastStreamingSession); +MEDIA_EXPORT BASE_DECLARE_FEATURE(kOpenscreenVideoBitrateFactorInFrameDrops); MEDIA_EXPORT BASE_DECLARE_FEATURE(kOverlayFullscreenVideo); MEDIA_EXPORT BASE_DECLARE_FEATURE(kPauseBackgroundMutedAudio); MEDIA_EXPORT BASE_DECLARE_FEATURE(kPlatformAudioEncoder);
diff --git a/media/cast/BUILD.gn b/media/cast/BUILD.gn index cc9c4106..6849c3d 100644 --- a/media/cast/BUILD.gn +++ b/media/cast/BUILD.gn
@@ -212,6 +212,8 @@ "sender/openscreen_frame_sender.h", "sender/performance_metrics_overlay.cc", "sender/performance_metrics_overlay.h", + "sender/video_bitrate_suggester.cc", + "sender/video_bitrate_suggester.h", "sender/video_sender.cc", "sender/video_sender.h", ] @@ -366,6 +368,8 @@ "net/udp_transport_unittest.cc", "sender/audio_sender_unittest.cc", "sender/congestion_control_unittest.cc", + "sender/openscreen_frame_sender_unittest.cc", + "sender/video_bitrate_suggester_unittest.cc", "sender/video_sender_unittest.cc", "test/end2end_unittest.cc", "test/receiver/audio_decoder_unittest.cc",
diff --git a/media/cast/DEPS b/media/cast/DEPS index b78c2d4..ccc911c 100644 --- a/media/cast/DEPS +++ b/media/cast/DEPS
@@ -12,3 +12,11 @@ "+ui/base", "+ui/gfx", ] + +specific_include_rules = { + ".*unittest.cc": [ + # TODO(https://crbug.com/1442745): there should be a test support class + # for this component. + "+components/openscreen_platform", + ], +} \ No newline at end of file
diff --git a/media/cast/cast_config.cc b/media/cast/cast_config.cc index 7f3a3fc5..6ddb5e69 100644 --- a/media/cast/cast_config.cc +++ b/media/cast/cast_config.cc
@@ -50,6 +50,39 @@ VideoCodecParams::~VideoCodecParams() = default; FrameSenderConfig::FrameSenderConfig() = default; +FrameSenderConfig::FrameSenderConfig(uint32_t sender_ssrc, + uint32_t receiver_ssrc, + base::TimeDelta min_playout_delay, + base::TimeDelta max_playout_delay, + RtpPayloadType rtp_payload_type, + bool use_hardware_encoder, + int rtp_timebase, + int channels, + int max_bitrate, + int min_bitrate, + int start_bitrate, + double max_frame_rate, + Codec codec, + std::string aes_key, + std::string aes_iv_mask, + VideoCodecParams video_codec_params) + : sender_ssrc(sender_ssrc), + receiver_ssrc(receiver_ssrc), + min_playout_delay(min_playout_delay), + max_playout_delay(max_playout_delay), + rtp_payload_type(rtp_payload_type), + use_hardware_encoder(use_hardware_encoder), + rtp_timebase(rtp_timebase), + channels(channels), + max_bitrate(max_bitrate), + min_bitrate(min_bitrate), + start_bitrate(start_bitrate), + max_frame_rate(max_frame_rate), + codec(codec), + aes_key(aes_key), + aes_iv_mask(aes_iv_mask), + video_codec_params(video_codec_params) {} + FrameSenderConfig::FrameSenderConfig(const FrameSenderConfig& other) = default; FrameSenderConfig::FrameSenderConfig(FrameSenderConfig&& other) = default; FrameSenderConfig& FrameSenderConfig::operator=(
diff --git a/media/cast/cast_config.h b/media/cast/cast_config.h index 07d575fa..be5b805 100644 --- a/media/cast/cast_config.h +++ b/media/cast/cast_config.h
@@ -150,6 +150,22 @@ struct FrameSenderConfig { FrameSenderConfig(); + FrameSenderConfig(uint32_t sender_ssrc, + uint32_t receiver_ssrc, + base::TimeDelta min_playout_delay, + base::TimeDelta max_playout_delay, + RtpPayloadType rtp_payload_type, + bool use_hardware_encoder, + int rtp_timebase, + int channels, + int max_bitrate, + int min_bitrate, + int start_bitrate, + double max_frame_rate, + Codec codec, + std::string aes_key, + std::string aes_iv_mask, + VideoCodecParams video_codec_params); FrameSenderConfig(const FrameSenderConfig& other); FrameSenderConfig(FrameSenderConfig&& other); FrameSenderConfig& operator=(const FrameSenderConfig& other);
diff --git a/media/cast/common/openscreen_conversion_helpers.cc b/media/cast/common/openscreen_conversion_helpers.cc index 6a880a0..2f84751 100644 --- a/media/cast/common/openscreen_conversion_helpers.cc +++ b/media/cast/common/openscreen_conversion_helpers.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "media/cast/common/openscreen_conversion_helpers.h" +#include "base/strings/string_number_conversions.h" #include "media/base/audio_codecs.h" #include "media/base/video_codecs.h" @@ -170,6 +171,33 @@ return openscreen::IPAddress(version, address.bytes().data()); } +std::array<uint8_t, kAesKeyLength> AesKeyToArray(std::string aes_key) { + std::vector<uint8_t> vec; + if (!base::HexStringToBytes(aes_key, &vec)) { + return {}; + } + if (vec.size() != static_cast<unsigned long>(kAesKeyLength)) { + return {}; + } + std::array<uint8_t, kAesKeyLength> out; + for (size_t i = 0; i < vec.size(); ++i) { + out[i] = vec[i]; + } + return out; +} + +openscreen::cast::SessionConfig ToOpenscreenSessionConfig( + const FrameSenderConfig& config, + bool is_pli_enabled) { + return openscreen::cast::SessionConfig( + config.sender_ssrc, config.receiver_ssrc, config.rtp_timebase, + config.channels, + std::chrono::milliseconds(config.max_playout_delay.InMilliseconds()), + + AesKeyToArray(config.aes_key), AesKeyToArray(config.aes_iv_mask), + is_pli_enabled); +} + openscreen::cast::AudioCaptureConfig ToOpenscreenAudioConfig( const FrameSenderConfig& config) { return openscreen::cast::AudioCaptureConfig{
diff --git a/media/cast/common/openscreen_conversion_helpers.h b/media/cast/common/openscreen_conversion_helpers.h index 8dc79b8..e6a3ae0 100644 --- a/media/cast/common/openscreen_conversion_helpers.h +++ b/media/cast/common/openscreen_conversion_helpers.h
@@ -51,6 +51,14 @@ openscreen::IPAddress ToOpenscreenIPAddress(const net::IPAddress& address); +// TODO(https://crbug.com/1441658): should be replaced with Open Screen's +// internal conversion methods. +constexpr int kAesKeyLength = 16; +std::array<uint8_t, kAesKeyLength> AesKeyToArray(std::string aes_key); + +openscreen::cast::SessionConfig ToOpenscreenSessionConfig( + const FrameSenderConfig& config, + bool is_pli_enabled); openscreen::cast::AudioCaptureConfig ToOpenscreenAudioConfig( const FrameSenderConfig& config); openscreen::cast::VideoCaptureConfig ToOpenscreenVideoConfig(
diff --git a/media/cast/sender/frame_sender.h b/media/cast/sender/frame_sender.h index 1f6d0f7..8b4db22 100644 --- a/media/cast/sender/frame_sender.h +++ b/media/cast/sender/frame_sender.h
@@ -98,14 +98,15 @@ std::unique_ptr<SenderEncodedFrame> encoded_frame) = 0; // Returns the reason the frame should be dropped, or kNotDropped if it should - // not be dropped. + // not be dropped. This method should be called exactly once for each frame, + // as its result may be used to calculate updates to the suggested bitrate. // // Callers are recommended to compute the frame duration based on the // difference between the next and last frames' reference times, or the period // between frames of the configured max frame rate if the reference times are // unavailable. virtual CastStreamingFrameDropReason ShouldDropNextFrame( - base::TimeDelta frame_duration) const = 0; + base::TimeDelta frame_duration) = 0; // Returns the RTP timestamp on the frame associated with |frame_id|. // In practice this should be implemented as a ring buffer using the lower
diff --git a/media/cast/sender/frame_sender_impl.cc b/media/cast/sender/frame_sender_impl.cc index 18c982a..08706fe9 100644 --- a/media/cast/sender/frame_sender_impl.cc +++ b/media/cast/sender/frame_sender_impl.cc
@@ -508,7 +508,7 @@ } CastStreamingFrameDropReason FrameSenderImpl::ShouldDropNextFrame( - base::TimeDelta frame_duration) const { + base::TimeDelta frame_duration) { // Check that accepting the next frame won't cause more frames to become // in-flight than the system's design limit. const int count_frames_in_flight =
diff --git a/media/cast/sender/frame_sender_impl.h b/media/cast/sender/frame_sender_impl.h index 2e6bc53..cffd066 100644 --- a/media/cast/sender/frame_sender_impl.h +++ b/media/cast/sender/frame_sender_impl.h
@@ -40,7 +40,7 @@ CastStreamingFrameDropReason EnqueueFrame( std::unique_ptr<SenderEncodedFrame> encoded_frame) override; CastStreamingFrameDropReason ShouldDropNextFrame( - base::TimeDelta frame_duration) const override; + base::TimeDelta frame_duration) override; RtpTimeTicks GetRecordedRtpTimestamp(FrameId frame_id) const override; int GetUnacknowledgedFrameCount() const override; int GetSuggestedBitrate(base::TimeTicks playout_time,
diff --git a/media/cast/sender/openscreen_frame_sender.cc b/media/cast/sender/openscreen_frame_sender.cc index 60d2b0c..39493d09 100644 --- a/media/cast/sender/openscreen_frame_sender.cc +++ b/media/cast/sender/openscreen_frame_sender.cc
@@ -73,12 +73,15 @@ : cast_environment_(cast_environment), sender_(std::move(sender)), client_(client), - get_bitrate_cb_(std::move(get_bitrate_cb)), max_frame_rate_(config.max_frame_rate), is_audio_(config.rtp_payload_type <= RtpPayloadType::AUDIO_LAST), min_playout_delay_(config.min_playout_delay), max_playout_delay_(config.max_playout_delay) { DCHECK_GT(sender_->config().rtp_timebase, 0); + if (!is_audio_) { + bitrate_suggester_ = std::make_unique<VideoBitrateSuggester>( + config, std::move(get_bitrate_cb)); + } const std::chrono::milliseconds target_playout_delay = sender_->config().target_playout_delay; @@ -141,7 +144,13 @@ } base::TimeDelta OpenscreenFrameSender::GetInFlightMediaDuration() const { + // Start by including the encoder backlog duration, defined as the + // difference between the timestamps of the last frame to enter the encoder + // and the last frame to exit the encoder. base::TimeDelta duration = client_->GetEncoderBacklogDuration(); + + // If we have sent at least one frame, then include the duration currently + // in flight (as recorded by the Open Screen sender). if (!last_enqueued_frame_id_.is_null()) { const RtpTimeTicks newest_timestamp = GetRecordedRtpTimestamp(last_enqueued_frame_id_); @@ -168,7 +177,7 @@ base::TimeDelta playout_delay) { // Currently only used by the video sender. DCHECK(!is_audio_); - return get_bitrate_cb_.Run(); + return bitrate_suggester_->GetSuggestedBitrate(); } double OpenscreenFrameSender::MaxFrameRate() const { @@ -205,7 +214,7 @@ CastStreamingFrameDropReason OpenscreenFrameSender::EnqueueFrame( std::unique_ptr<SenderEncodedFrame> encoded_frame) { DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); - + DCHECK(encoded_frame); VLOG_WITH_SSRC(2) << "About to send another frame. last enqueued=" << last_enqueued_frame_id_; @@ -291,12 +300,13 @@ } CastStreamingFrameDropReason OpenscreenFrameSender::ShouldDropNextFrame( - base::TimeDelta frame_duration) const { + base::TimeDelta frame_duration) { // Check that accepting the next frame won't cause more frames to become // in-flight than the system's design limit. const int count_frames_in_flight = GetUnacknowledgedFrameCount() + client_->GetNumberOfFramesInEncoder(); if (count_frames_in_flight >= kMaxUnackedFrames) { + RecordShouldDropNextFrame(/*should_drop=*/true); return CastStreamingFrameDropReason::kTooManyFramesInFlight; } @@ -306,11 +316,14 @@ const double max_frames_in_flight = max_frame_rate_ * duration_in_flight.InSecondsF(); if (count_frames_in_flight >= max_frames_in_flight + kMaxFrameBurst) { + RecordShouldDropNextFrame(/*should_drop=*/true); return CastStreamingFrameDropReason::kBurstThresholdExceeded; } - // Check that accepting the next frame won't exceed the allowed in-flight - // media duration. + // At this point, we know we don't have too many frames, but we still need + // to ensure we don't have too much duration in flight. This case should + // not be hit very often, unless some frames have a higher duration than + // expected. const base::TimeDelta duration_would_be_in_flight = duration_in_flight + frame_duration; const base::TimeDelta allowed_in_flight = GetAllowedInFlightMediaDuration(); @@ -330,11 +343,18 @@ } } if (duration_would_be_in_flight > allowed_in_flight) { + RecordShouldDropNextFrame(/*should_drop=*/true); return CastStreamingFrameDropReason::kInFlightDurationTooHigh; } // Next frame is accepted. + RecordShouldDropNextFrame(/*should_drop=*/false); return CastStreamingFrameDropReason::kNotDropped; } +void OpenscreenFrameSender::RecordShouldDropNextFrame(bool should_drop) { + if (bitrate_suggester_) { + bitrate_suggester_->RecordShouldDropNextFrame(should_drop); + } +} } // namespace media::cast
diff --git a/media/cast/sender/openscreen_frame_sender.h b/media/cast/sender/openscreen_frame_sender.h index 9f42402..101f1ae 100644 --- a/media/cast/sender/openscreen_frame_sender.h +++ b/media/cast/sender/openscreen_frame_sender.h
@@ -18,7 +18,7 @@ #include "media/cast/net/cast_transport.h" #include "media/cast/net/rtcp/rtcp_defines.h" #include "media/cast/sender/frame_sender.h" - +#include "media/cast/sender/video_bitrate_suggester.h" #include "third_party/openscreen/src/cast/streaming/sender.h" namespace media::cast { @@ -53,7 +53,7 @@ CastStreamingFrameDropReason EnqueueFrame( std::unique_ptr<SenderEncodedFrame> encoded_frame) override; CastStreamingFrameDropReason ShouldDropNextFrame( - base::TimeDelta frame_duration) const override; + base::TimeDelta frame_duration) override; RtpTimeTicks GetRecordedRtpTimestamp(FrameId frame_id) const override; int GetUnacknowledgedFrameCount() const override; int GetSuggestedBitrate(base::TimeTicks playout_time, @@ -90,10 +90,14 @@ base::TimeDelta GetInFlightMediaDuration() const; private: + friend class OpenscreenFrameSenderTest; + // Returns the maximum media duration currently allowed in-flight. This // fluctuates in response to the currently-measured network latency. base::TimeDelta GetAllowedInFlightMediaDuration() const; + void RecordShouldDropNextFrame(bool should_drop); + // The cast environment. const scoped_refptr<CastEnvironment> cast_environment_; @@ -150,6 +154,10 @@ // buffer is the lower 8 bits of the FrameId. RtpTimeTicks frame_rtp_timestamps_[256]; + // TODO(https://crbug.com/1316434): move this property to VideoSender once + // the legacy implementation has been removed. + std::unique_ptr<VideoBitrateSuggester> bitrate_suggester_; + // NOTE: Weak pointers must be invalidated before all other member variables. base::WeakPtrFactory<OpenscreenFrameSender> weak_factory_{this}; };
diff --git a/media/cast/sender/openscreen_frame_sender_unittest.cc b/media/cast/sender/openscreen_frame_sender_unittest.cc new file mode 100644 index 0000000..a759b65 --- /dev/null +++ b/media/cast/sender/openscreen_frame_sender_unittest.cc
@@ -0,0 +1,236 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cast/sender/openscreen_frame_sender.h" + +#include <memory> +#include <utility> + +#include "base/functional/bind.h" +#include "components/openscreen_platform/task_runner.h" +#include "media/base/fake_single_thread_task_runner.h" +#include "media/cast/cast_config.h" +#include "media/cast/cast_environment.h" +#include "media/cast/common/openscreen_conversion_helpers.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/openscreen/src/cast/streaming/environment.h" +#include "third_party/openscreen/src/cast/streaming/sender.h" +#include "third_party/openscreen/src/cast/streaming/sender_packet_router.h" +#include "third_party/openscreen/src/platform/api/time.h" +#include "third_party/openscreen/src/platform/base/trivial_clock_traits.h" + +namespace media::cast { +namespace { + +constexpr uint32_t kFirstSsrc = 35535; +constexpr int kRtpTimebase = 9000; +constexpr char kAesSecretKey[] = "65386FD9BCC30BC7FB6A4DD1D3B0FA5E"; +constexpr char kAesIvMask[] = "64A6AAC2821880145271BB15B0188821"; +constexpr int kAudioBitrate = 100 * 1000; + +static const FrameSenderConfig kAudioConfig{kFirstSsrc, + kFirstSsrc + 1, + base::Milliseconds(100), + kDefaultTargetPlayoutDelay, + RtpPayloadType::AUDIO_OPUS, + /* use_hardware_encoder= */ false, + kDefaultAudioSamplingRate, + /* channels= */ 2, + kAudioBitrate, + kAudioBitrate, + kAudioBitrate, + kDefaultMaxFrameRate, + Codec::kAudioOpus, + kAesSecretKey, + kAesIvMask, + VideoCodecParams{}}; +static const openscreen::cast::SessionConfig kOpenscreenAudioConfig = + ToOpenscreenSessionConfig(kAudioConfig, /* is_pli_enabled= */ true); + +static const FrameSenderConfig kVideoConfig{ + kFirstSsrc + 2, + kFirstSsrc + 3, + base::Milliseconds(100), + kDefaultTargetPlayoutDelay, + RtpPayloadType::VIDEO_VP8, + /* use_hardware_encoder= */ false, + kRtpTimebase, + /* channels = */ 1, + kDefaultMaxVideoBitrate, + kDefaultMinVideoBitrate, + (kDefaultMinVideoBitrate + kDefaultMaxVideoBitrate) / 2, + kDefaultMaxFrameRate, + Codec::kVideoVp8, + kAesSecretKey, + kAesIvMask, + VideoCodecParams{}}; +static const openscreen::cast::SessionConfig kOpenscreenVideoConfig = + ToOpenscreenSessionConfig(kVideoConfig, /* is_pli_enabled= */ true); + +} // namespace + +class OpenscreenFrameSenderTest : public ::testing::Test, + public FrameSender::Client { + public: + // FrameSender::Client overrides. + int GetNumberOfFramesInEncoder() const override { return 0; } + base::TimeDelta GetEncoderBacklogDuration() const override { return {}; } + void OnFrameCanceled(FrameId frame_id) override {} + + int get_suggested_bitrate() { return suggested_bitrate_; } + + protected: + OpenscreenFrameSenderTest() + : task_runner_( + base::MakeRefCounted<FakeSingleThreadTaskRunner>(&testing_clock_)), + cast_environment_(base::MakeRefCounted<CastEnvironment>(&testing_clock_, + task_runner_, + task_runner_, + task_runner_)), + openscreen_task_runner_(task_runner_), + openscreen_environment_(openscreen::Clock::now, + &openscreen_task_runner_, + openscreen::IPEndpoint::kAnyV4()), + openscreen_packet_router_(&openscreen_environment_, + 20, + std::chrono::milliseconds(10)) { + auto openscreen_audio_sender = std::make_unique<openscreen::cast::Sender>( + &openscreen_environment_, &openscreen_packet_router_, + kOpenscreenAudioConfig, openscreen::cast::RtpPayloadType::kAudioOpus); + auto openscreen_video_sender = std::make_unique<openscreen::cast::Sender>( + &openscreen_environment_, &openscreen_packet_router_, + kOpenscreenVideoConfig, openscreen::cast::RtpPayloadType::kVideoVp8); + + audio_sender_ = std::make_unique<OpenscreenFrameSender>( + cast_environment_, kAudioConfig, std::move(openscreen_audio_sender), + *this, + base::BindRepeating(&OpenscreenFrameSenderTest::get_suggested_bitrate, + // Safe because we destroy the audio sender before + // destroying `this`. + base::Unretained(this))); + + video_sender_ = std::make_unique<OpenscreenFrameSender>( + cast_environment_, kVideoConfig, std::move(openscreen_video_sender), + *this, + base::BindRepeating(&OpenscreenFrameSenderTest::get_suggested_bitrate, + // Safe because we destroy the audio sender before + // destroying `this`. + base::Unretained(this))); + } + + void RecordShouldDropNextFrame(bool should_drop) { + video_sender_->RecordShouldDropNextFrame(should_drop); + } + + void set_suggested_bitrate(int bitrate) { suggested_bitrate_ = bitrate; } + + OpenscreenFrameSender& audio_sender() { return *audio_sender_; } + + OpenscreenFrameSender& video_sender() { return *video_sender_; } + + private: + base::SimpleTestTickClock testing_clock_; + const scoped_refptr<FakeSingleThreadTaskRunner> task_runner_; + const scoped_refptr<CastEnvironment> cast_environment_; + + // openscreen::Sender related classes. + openscreen_platform::TaskRunner openscreen_task_runner_; + openscreen::cast::Environment openscreen_environment_; + openscreen::cast::SenderPacketRouter openscreen_packet_router_; + std::unique_ptr<openscreen::cast::Sender> openscreen_video_sender_; + std::unique_ptr<openscreen::cast::Sender> openscreen_audio_sender_; + + std::unique_ptr<OpenscreenFrameSender> audio_sender_; + std::unique_ptr<OpenscreenFrameSender> video_sender_; + + int suggested_bitrate_ = 0; +}; + +TEST_F(OpenscreenFrameSenderTest, RespectsTargetPlayoutDelay) { + EXPECT_EQ(kDefaultTargetPlayoutDelay, audio_sender().GetTargetPlayoutDelay()); + EXPECT_EQ(kDefaultTargetPlayoutDelay, video_sender().GetTargetPlayoutDelay()); + + const auto new_delay = base::Milliseconds(123); + audio_sender().SetTargetPlayoutDelay(new_delay); + video_sender().SetTargetPlayoutDelay(new_delay); + EXPECT_EQ(new_delay, audio_sender().GetTargetPlayoutDelay()); + EXPECT_EQ(new_delay, video_sender().GetTargetPlayoutDelay()); + + // Should never go below the minimum (100 milliseconds, set above). + const auto too_low_delay = base::Milliseconds(98); + audio_sender().SetTargetPlayoutDelay(too_low_delay); + video_sender().SetTargetPlayoutDelay(too_low_delay); + EXPECT_EQ(base::Milliseconds(100), audio_sender().GetTargetPlayoutDelay()); + EXPECT_EQ(base::Milliseconds(100), video_sender().GetTargetPlayoutDelay()); + + // Should never go above the maximum (kDefaultTargetPlayoutDelay, set above). + const auto too_high_delay = base::Milliseconds(1000); + audio_sender().SetTargetPlayoutDelay(too_high_delay); + video_sender().SetTargetPlayoutDelay(too_high_delay); + EXPECT_EQ(kDefaultTargetPlayoutDelay, audio_sender().GetTargetPlayoutDelay()); + EXPECT_EQ(kDefaultTargetPlayoutDelay, video_sender().GetTargetPlayoutDelay()); +} + +TEST_F(OpenscreenFrameSenderTest, CanEnqueueFirstFrame) { + auto audio_frame = std::make_unique<SenderEncodedFrame>(); + audio_frame->frame_id = openscreen::cast::FrameId(1); + audio_frame->referenced_frame_id = audio_frame->frame_id; + audio_frame->reference_time = base::TimeTicks::Now(); + EXPECT_EQ(CastStreamingFrameDropReason::kNotDropped, + audio_sender().EnqueueFrame(std::move(audio_frame))); + + auto video_frame = std::make_unique<SenderEncodedFrame>(); + video_frame->frame_id = openscreen::cast::FrameId(1); + video_frame->referenced_frame_id = video_frame->frame_id; + video_frame->reference_time = base::TimeTicks::Now(); + EXPECT_EQ(CastStreamingFrameDropReason::kNotDropped, + video_sender().EnqueueFrame(std::move(video_frame))); +} + +TEST_F(OpenscreenFrameSenderTest, RecordsRtpTimestamps) { + constexpr RtpTimeTicks kAudioRtpTimestamp{456}; + auto audio_frame = std::make_unique<SenderEncodedFrame>(); + audio_frame->frame_id = openscreen::cast::FrameId(1); + audio_frame->referenced_frame_id = audio_frame->frame_id; + audio_frame->reference_time = base::TimeTicks::Now(); + audio_frame->rtp_timestamp = kAudioRtpTimestamp; + EXPECT_EQ(CastStreamingFrameDropReason::kNotDropped, + audio_sender().EnqueueFrame(std::move(audio_frame))); + EXPECT_EQ(kAudioRtpTimestamp, audio_sender().GetRecordedRtpTimestamp( + openscreen::cast::FrameId(1))); + + constexpr RtpTimeTicks kVideoRtpTimestamp{1337}; + auto video_frame = std::make_unique<SenderEncodedFrame>(); + video_frame->frame_id = openscreen::cast::FrameId(1); + video_frame->referenced_frame_id = video_frame->frame_id; + video_frame->reference_time = base::TimeTicks::Now(); + video_frame->rtp_timestamp = kVideoRtpTimestamp; + EXPECT_EQ(CastStreamingFrameDropReason::kNotDropped, + video_sender().EnqueueFrame(std::move(video_frame))); + EXPECT_EQ(kVideoRtpTimestamp, video_sender().GetRecordedRtpTimestamp( + openscreen::cast::FrameId(1))); + + // Should return empty if the frame ID is not recorded. + EXPECT_EQ(RtpTimeTicks{}, audio_sender().GetRecordedRtpTimestamp( + openscreen::cast::FrameId(2000))); + EXPECT_EQ(RtpTimeTicks{}, video_sender().GetRecordedRtpTimestamp( + openscreen::cast::FrameId(2000))); +} + +TEST_F(OpenscreenFrameSenderTest, HandlesSuggestedBitratesCorrectly) { + // NOTE: the VideoBitrateSuggester tests this workflow more thoroughly. + + // We should start with the maximum video bitrate. + set_suggested_bitrate(5000001); + EXPECT_EQ(5000000, video_sender().GetSuggestedBitrate(base::TimeTicks{}, + base::TimeDelta{})); + + // It should cap at the bitrate suggested by Open Screen. + set_suggested_bitrate(4998374); + EXPECT_EQ(4998374, video_sender().GetSuggestedBitrate(base::TimeTicks{}, + base::TimeDelta{})); +} + +} // namespace media::cast
diff --git a/media/cast/sender/video_bitrate_suggester.cc b/media/cast/sender/video_bitrate_suggester.cc new file mode 100644 index 0000000..ad7b4b7 --- /dev/null +++ b/media/cast/sender/video_bitrate_suggester.cc
@@ -0,0 +1,85 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cast/sender/video_bitrate_suggester.h" + +#include <algorithm> +#include <limits> +#include <memory> +#include <utility> +#include <vector> + +#include "base/feature_list.h" +#include "base/logging.h" +#include "media/base/media_switches.h" +#include "media/cast/common/openscreen_conversion_helpers.h" +#include "media/cast/common/sender_encoded_frame.h" +#include "media/cast/constants.h" + +namespace media::cast { + +VideoBitrateSuggester::VideoBitrateSuggester( + const FrameSenderConfig& config, + FrameSender::GetSuggestedVideoBitrateCB get_bitrate_cb) + : get_bitrate_cb_(std::move(get_bitrate_cb)), + min_bitrate_(config.min_bitrate), + max_bitrate_(config.max_bitrate), + suggested_max_bitrate_(max_bitrate_) {} + +VideoBitrateSuggester::~VideoBitrateSuggester() = default; + +int VideoBitrateSuggester::GetSuggestedBitrate() { + // Skip the more complicated calculation if the feature is not enabled. + if (!base::FeatureList::IsEnabled( + media::kOpenscreenVideoBitrateFactorInFrameDrops)) { + return get_bitrate_cb_.Run(); + } + + // The bitrate retrieved from the callback is based on network usage, however + // we also need to consider how well this device is handling encoding at + // this bitrate overall. + const int suggested_bitrate = + std::min(get_bitrate_cb_.Run(), suggested_max_bitrate_); + + // Honor the config boundaries. + return std::clamp(suggested_bitrate, min_bitrate_, max_bitrate_); +} + +void VideoBitrateSuggester::RecordShouldDropNextFrame(bool should_drop) { + // Nothing to do if frame drop logic is disabled. + if (!base::FeatureList::IsEnabled( + media::kOpenscreenVideoBitrateFactorInFrameDrops)) { + return; + } + + ++number_of_frames_requested_; + if (should_drop) { + ++number_of_frames_dropped_; + } + + // We don't want to change the bitrate too frequently in order to give + // things time to adjust, so only adjust every 100 frames (about 3 seconds + // at 30FPS). + constexpr int kWindowSize = 100; + if (number_of_frames_requested_ == kWindowSize) { + constexpr int kBitrateSteps = 8; + DCHECK_GE(max_bitrate_, min_bitrate_); + const int adjustment = (max_bitrate_ - min_bitrate_) / kBitrateSteps; + + // Generally speaking we shouldn't be dropping any frames, so even one is + // a bad sign. + if (number_of_frames_dropped_ > 0) { + suggested_max_bitrate_ = + std::max(min_bitrate_, suggested_max_bitrate_ - adjustment); + } else { + suggested_max_bitrate_ = + std::min(max_bitrate_, suggested_max_bitrate_ + adjustment); + } + + // Reset the recorded frame drops to start a new window. + number_of_frames_requested_ = 0; + number_of_frames_dropped_ = 0; + } +} +} // namespace media::cast
diff --git a/media/cast/sender/video_bitrate_suggester.h b/media/cast/sender/video_bitrate_suggester.h new file mode 100644 index 0000000..64d7727c --- /dev/null +++ b/media/cast/sender/video_bitrate_suggester.h
@@ -0,0 +1,46 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_CAST_SENDER_VIDEO_BITRATE_SUGGESTER_H_ +#define MEDIA_CAST_SENDER_VIDEO_BITRATE_SUGGESTER_H_ + +#include "media/cast/cast_config.h" +#include "media/cast/sender/frame_sender.h" + +namespace media::cast { + +class VideoBitrateSuggester { + public: + VideoBitrateSuggester(const FrameSenderConfig& config, + FrameSender::GetSuggestedVideoBitrateCB get_bitrate_cb); + VideoBitrateSuggester(VideoBitrateSuggester&& other) = delete; + VideoBitrateSuggester& operator=(VideoBitrateSuggester&& other) = delete; + VideoBitrateSuggester(const VideoBitrateSuggester&) = delete; + VideoBitrateSuggester& operator=(const VideoBitrateSuggester&) = delete; + ~VideoBitrateSuggester(); + + void RecordShouldDropNextFrame(bool should_drop); + + int GetSuggestedBitrate(); + + private: + // The method for getting the recommended bitrate. + FrameSender::GetSuggestedVideoBitrateCB get_bitrate_cb_; + + // The minimum and maximum bitrates set from the config. + int min_bitrate_ = 0; + int max_bitrate_ = 0; + + // The suggested maximum bitrate, factoring in frame drops. + int suggested_max_bitrate_ = 0; + + // We keep track of how many frames get dropped in order to lower the video + // bitrate when appropriate. + int number_of_frames_requested_ = 0; + int number_of_frames_dropped_ = 0; +}; + +} // namespace media::cast + +#endif // MEDIA_CAST_SENDER_VIDEO_BITRATE_SUGGESTER_H_
diff --git a/media/cast/sender/video_bitrate_suggester_unittest.cc b/media/cast/sender/video_bitrate_suggester_unittest.cc new file mode 100644 index 0000000..1e37986 --- /dev/null +++ b/media/cast/sender/video_bitrate_suggester_unittest.cc
@@ -0,0 +1,133 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/cast/sender/video_bitrate_suggester.h" + +#include <memory> +#include <utility> + +#include "base/functional/bind.h" +#include "base/test/scoped_feature_list.h" +#include "media/base/media_switches.h" +#include "media/cast/cast_config.h" +#include "media/cast/cast_environment.h" +#include "media/cast/common/openscreen_conversion_helpers.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media::cast { +namespace { + +constexpr uint32_t kFirstSsrc = 35535; +constexpr int kRtpTimebase = 9000; +constexpr char kAesSecretKey[] = "65386FD9BCC30BC7FB6A4DD1D3B0FA5E"; +constexpr char kAesIvMask[] = "64A6AAC2821880145271BB15B0188821"; + +static const FrameSenderConfig kVideoConfig{ + kFirstSsrc + 2, + kFirstSsrc + 3, + base::Milliseconds(100), + kDefaultTargetPlayoutDelay, + RtpPayloadType::VIDEO_VP8, + /* use_hardware_encoder= */ false, + kRtpTimebase, + /* channels = */ 1, + kDefaultMaxVideoBitrate, + kDefaultMinVideoBitrate, + (kDefaultMinVideoBitrate + kDefaultMaxVideoBitrate) / 2, + kDefaultMaxFrameRate, + Codec::kVideoVp8, + kAesSecretKey, + kAesIvMask, + VideoCodecParams{}}; +static const openscreen::cast::SessionConfig kOpenscreenVideoConfig = + ToOpenscreenSessionConfig(kVideoConfig, /* is_pli_enabled= */ true); + +} // namespace + +class VideoBitrateSuggesterTest : public ::testing::Test { + public: + int get_suggested_bitrate() { return suggested_bitrate_; } + + protected: + VideoBitrateSuggesterTest() { + feature_list_.InitAndEnableFeature( + media::kOpenscreenVideoBitrateFactorInFrameDrops); + video_bitrate_suggester_ = std::make_unique<VideoBitrateSuggester>( + kVideoConfig, + base::BindRepeating(&VideoBitrateSuggesterTest::get_suggested_bitrate, + // Safe because we destroy the audio sender before + // destroying `this`. + base::Unretained(this))); + } + + void RecordShouldDropNextFrame(bool should_drop) { + video_bitrate_suggester_->RecordShouldDropNextFrame(should_drop); + } + + void set_suggested_bitrate(int bitrate) { suggested_bitrate_ = bitrate; } + + VideoBitrateSuggester& video_bitrate_suggester() { + return *video_bitrate_suggester_; + } + + private: + std::unique_ptr<VideoBitrateSuggester> video_bitrate_suggester_; + base::test::ScopedFeatureList feature_list_; + int suggested_bitrate_ = 0; +}; + +TEST_F(VideoBitrateSuggesterTest, SuggestsBitratesCorrectly) { + // We should start with the maximum video bitrate. + set_suggested_bitrate(5000001); + EXPECT_EQ(5000000, video_bitrate_suggester().GetSuggestedBitrate()); + + // After a period with multiple frame drops, this should go down. + RecordShouldDropNextFrame(true); + RecordShouldDropNextFrame(true); + for (int i = 0; i < 99; ++i) { + RecordShouldDropNextFrame(false); + } + + // It should now go down. + EXPECT_EQ(4412500, video_bitrate_suggester().GetSuggestedBitrate()); + + // It should continue to go down to the minimum as long as frames are being + // dropped. + int last_suggestion = 4412500; + for (int i = 0; i < 7; ++i) { + RecordShouldDropNextFrame(true); + for (int j = 0; j < 99; ++j) { + RecordShouldDropNextFrame(false); + } + + // It should drop every time. + const int suggestion = video_bitrate_suggester().GetSuggestedBitrate(); + EXPECT_LT(suggestion, last_suggestion); + last_suggestion = suggestion; + } + + // And then stabilize at the bottom. + EXPECT_EQ(300000, video_bitrate_suggester().GetSuggestedBitrate()); + + // It should increase once we stop dropping frames. + last_suggestion = 300000; + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 100; ++j) { + RecordShouldDropNextFrame(false); + } + const int suggestion = video_bitrate_suggester().GetSuggestedBitrate(); + EXPECT_GT(suggestion, last_suggestion); + last_suggestion = suggestion; + } + + // And stop at the maximum. + EXPECT_EQ(5000000, video_bitrate_suggester().GetSuggestedBitrate()); + + // Finally, it should cap at the bitrate suggested by Open Screen. + set_suggested_bitrate(4998374); + EXPECT_EQ(4998374, video_bitrate_suggester().GetSuggestedBitrate()); +} + +} // namespace media::cast
diff --git a/media/gpu/v4l2/v4l2_stateless_video_decoder.cc b/media/gpu/v4l2/v4l2_stateless_video_decoder.cc index 19a19b8..e5bcf28e 100644 --- a/media/gpu/v4l2/v4l2_stateless_video_decoder.cc +++ b/media/gpu/v4l2/v4l2_stateless_video_decoder.cc
@@ -23,9 +23,13 @@ base::WeakPtr<VideoDecoderMixin::Client> client) : VideoDecoderMixin(std::move(media_log), std::move(decoder_task_runner), - std::move(client)) {} + std::move(client)) { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); +} -V4L2StatelessVideoDecoder::~V4L2StatelessVideoDecoder() {} +V4L2StatelessVideoDecoder::~V4L2StatelessVideoDecoder() { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); +} // static absl::optional<SupportedVideoDecoderConfigs> @@ -40,15 +44,18 @@ InitCB init_cb, const OutputCB& output_cb, const WaitingCB& waiting_cb) { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); NOTIMPLEMENTED(); } void V4L2StatelessVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); NOTIMPLEMENTED(); } void V4L2StatelessVideoDecoder::Reset(base::OnceClosure reset_cb) { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); NOTIMPLEMENTED(); } @@ -78,12 +85,43 @@ } void V4L2StatelessVideoDecoder::ApplyResolutionChange() { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); NOTIMPLEMENTED(); } size_t V4L2StatelessVideoDecoder::GetMaxOutputFramePoolSize() const { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); NOTIMPLEMENTED(); return 0; } +scoped_refptr<V4L2DecodeSurface> V4L2StatelessVideoDecoder::CreateSurface() { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); + NOTIMPLEMENTED(); + return nullptr; +} + +bool V4L2StatelessVideoDecoder::SubmitSlice(V4L2DecodeSurface* dec_surface, + const uint8_t* data, + size_t size) { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); + NOTIMPLEMENTED(); + return false; +} + +void V4L2StatelessVideoDecoder::DecodeSurface( + scoped_refptr<V4L2DecodeSurface> dec_surface) { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); + NOTIMPLEMENTED(); +} + +void V4L2StatelessVideoDecoder::SurfaceReady( + scoped_refptr<V4L2DecodeSurface> dec_surface, + int32_t bitstream_id, + const gfx::Rect& visible_rect, + const VideoColorSpace& color_space) { + DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_); + NOTIMPLEMENTED(); +} + } // namespace media
diff --git a/media/gpu/v4l2/v4l2_stateless_video_decoder.h b/media/gpu/v4l2/v4l2_stateless_video_decoder.h index a398de4..f1652d2 100644 --- a/media/gpu/v4l2/v4l2_stateless_video_decoder.h +++ b/media/gpu/v4l2/v4l2_stateless_video_decoder.h
@@ -17,6 +17,7 @@ #include "media/base/video_decoder.h" #include "media/base/waiting.h" #include "media/gpu/chromeos/video_decoder_pipeline.h" +#include "media/gpu/v4l2/v4l2_decode_surface_handler.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace media { @@ -25,7 +26,9 @@ // using a memory to memory interface. // https://www.kernel.org/doc/html/latest/userspace-api/media/mediactl/request-api.html // https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html -class MEDIA_GPU_EXPORT V4L2StatelessVideoDecoder : public VideoDecoderMixin { +class MEDIA_GPU_EXPORT V4L2StatelessVideoDecoder + : public VideoDecoderMixin, + public V4L2DecodeSurfaceHandler { public: static std::unique_ptr<VideoDecoderMixin> Create( std::unique_ptr<MediaLog> media_log, @@ -52,12 +55,25 @@ void ApplyResolutionChange() override; size_t GetMaxOutputFramePoolSize() const override; + // V4L2DecodeSurfaceHandler implementation. + scoped_refptr<V4L2DecodeSurface> CreateSurface() override; + bool SubmitSlice(V4L2DecodeSurface* dec_surface, + const uint8_t* data, + size_t size) override; + void DecodeSurface(scoped_refptr<V4L2DecodeSurface> dec_surface) override; + void SurfaceReady(scoped_refptr<V4L2DecodeSurface> dec_surface, + int32_t bitstream_id, + const gfx::Rect& visible_rect, + const VideoColorSpace& color_space) override; + private: V4L2StatelessVideoDecoder( std::unique_ptr<MediaLog> media_log, scoped_refptr<base::SequencedTaskRunner> decoder_task_runner, base::WeakPtr<VideoDecoderMixin::Client> client); ~V4L2StatelessVideoDecoder() override; + + SEQUENCE_CHECKER(decoder_sequence_checker_); }; } // namespace media
diff --git a/services/accessibility/BUILD.gn b/services/accessibility/BUILD.gn index 6446a53..aa0ddfe1 100644 --- a/services/accessibility/BUILD.gn +++ b/services/accessibility/BUILD.gn
@@ -73,6 +73,17 @@ ] deps = [ ":lib" ] + + if (supports_os_accessibility_service) { + sources += [ + "features/mojo/test/js_test_interface.cc", + "features/mojo/test/js_test_interface.h", + ] + deps += [ + "//base/test:test_support", + "//services/accessibility/features/mojo/test:mojom_js_api", + ] + } } source_set("tests") { @@ -93,10 +104,7 @@ "features/v8_manager_unittest.cc", "os_accessibility_service_unittest.cc", ] - deps += [ - "//base", - "//services/accessibility/features/mojo/test:mojom_js_api", - ] + deps += [ "//base" ] data_deps = [ "//services/accessibility/features/mojo/test:test_support_data" ] } else {
diff --git a/services/accessibility/features/mojo/test/js_test_interface.cc b/services/accessibility/features/mojo/test/js_test_interface.cc new file mode 100644 index 0000000..71bfe71 --- /dev/null +++ b/services/accessibility/features/mojo/test/js_test_interface.cc
@@ -0,0 +1,59 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/accessibility/features/mojo/test/js_test_interface.h" + +#include "base/test/bind.h" + +namespace ax { + +JSTestInterface::JSTestInterface(base::OnceCallback<void(bool)> on_complete) + : on_complete_(std::move(on_complete)), receiver_(this) {} +JSTestInterface::~JSTestInterface() = default; +void JSTestInterface::BindReceiver( + mojo::GenericPendingReceiver pending_receiver) { + auto receiver = pending_receiver.As<axtest::mojom::TestBindingInterface>(); + receiver_.Bind(std::move(receiver)); + receiver_.set_disconnect_handler(base::BindLambdaForTesting( + [this]() { std::move(on_complete_).Run(false); })); +} + +bool JSTestInterface::MatchesInterface(const std::string& interface_name) { + return interface_name == "axtest.mojom.TestBindingInterface"; +} + +void JSTestInterface::AddTestInterface(AddTestInterfaceCallback callback) { + int index = test_interface_receivers_.size(); + test_interface_receivers_.emplace_back(); + auto pending_receiver = + test_interface_receivers_[index].BindNewPipeAndPassReceiver(); + std::move(callback).Run(std::move(pending_receiver)); +} + +void JSTestInterface::GetTestStruct(int num, + const std::string& name, + GetTestStructCallback callback) { + auto result = axtest::mojom::TestStruct::New(); + result->is_structy = true; + // Modify the passed values a bit to ensure it's not just an echo. + result->num = num + 1; + result->name = name + " rocks"; + std::move(callback).Run(std::move(result)); +} + +void JSTestInterface::SendEnumToTestInterface(axtest::mojom::TestEnum num) { + for (auto& receiver : test_interface_receivers_) { + receiver->TestMethod(num); + } +} + +void JSTestInterface::Disconnect() { + receiver_.reset(); +} + +void JSTestInterface::TestComplete(bool success) { + std::move(on_complete_).Run(success); +} + +} // namespace ax
diff --git a/services/accessibility/features/mojo/test/js_test_interface.h b/services/accessibility/features/mojo/test/js_test_interface.h new file mode 100644 index 0000000..2b0e52a --- /dev/null +++ b/services/accessibility/features/mojo/test/js_test_interface.h
@@ -0,0 +1,50 @@ + +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_ACCESSIBILITY_FEATURES_MOJO_TEST_JS_TEST_INTERFACE_H_ +#define SERVICES_ACCESSIBILITY_FEATURES_MOJO_TEST_JS_TEST_INTERFACE_H_ + +#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/remote.h" +#include "services/accessibility/features/interface_binder.h" +#include "services/accessibility/features/mojo/test/test_api.test-mojom.h" + +namespace ax { + +// C++ implementation of the TestBindingInterface mojom. The other end of the +// pipe is held in Javascript. This can be used to run tests in JS and inform +// when they fail or complete. +class JSTestInterface : public axtest::mojom::TestBindingInterface, + public InterfaceBinder { + public: + // Creates a JSTestInterface with a callback that runs when the test + // has finished with a bool representing whether the test was successful. + explicit JSTestInterface(base::OnceCallback<void(bool)> on_complete); + ~JSTestInterface() override; + JSTestInterface& operator=(const JSTestInterface&) = delete; + JSTestInterface(const JSTestInterface&) = delete; + + // InterfaceBinder overrides: + void BindReceiver(mojo::GenericPendingReceiver pending_receiver) override; + bool MatchesInterface(const std::string& interface_name) override; + + // axtest::mojom::TestBindingInterface overrides: + void AddTestInterface(AddTestInterfaceCallback callback) override; + void GetTestStruct(int num, + const std::string& name, + GetTestStructCallback callback) override; + void SendEnumToTestInterface(axtest::mojom::TestEnum num) override; + void Disconnect() override; + void TestComplete(bool success) override; + + private: + base::OnceCallback<void(bool)> on_complete_; + mojo::Receiver<axtest::mojom::TestBindingInterface> receiver_; + std::vector<mojo::Remote<axtest::mojom::TestInterface>> + test_interface_receivers_; +}; +} // namespace ax + +#endif // SERVICES_ACCESSIBILITY_FEATURES_MOJO_TEST_JS_TEST_INTERFACE_H_
diff --git a/services/accessibility/features/v8_manager_unittest.cc b/services/accessibility/features/v8_manager_unittest.cc index 584afba..7b72c74 100644 --- a/services/accessibility/features/v8_manager_unittest.cc +++ b/services/accessibility/features/v8_manager_unittest.cc
@@ -17,75 +17,13 @@ #include "mojo/public/c/system/types.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" -#include "services/accessibility/features/mojo/test/test_api.test-mojom.h" +#include "services/accessibility/features/mojo/test/js_test_interface.h" #include "services/accessibility/public/mojom/accessibility_service.mojom-shared.h" #include "testing/gtest/include/gtest/gtest.h" #include "v8_manager.h" namespace ax { -// C++ implementation of the TestBindingInterface. The other end of the pipe is -// held in Javascript. -class TestBindingInterfaceImpl : public axtest::mojom::TestBindingInterface, - public InterfaceBinder { - public: - explicit TestBindingInterfaceImpl(base::OnceCallback<void(bool)> on_complete) - : on_complete_(std::move(on_complete)), receiver_(this) {} - ~TestBindingInterfaceImpl() override = default; - TestBindingInterfaceImpl& operator=(const TestBindingInterfaceImpl&) = delete; - TestBindingInterfaceImpl(const TestBindingInterfaceImpl&) = delete; - - // InterfaceBinder overrides: - void BindReceiver(mojo::GenericPendingReceiver pending_receiver) override { - auto receiver = pending_receiver.As<axtest::mojom::TestBindingInterface>(); - receiver_.Bind(std::move(receiver)); - receiver_.set_disconnect_handler(base::BindLambdaForTesting( - [this]() { std::move(on_complete_).Run(false); })); - } - - bool MatchesInterface(const std::string& interface_name) override { - return interface_name == "axtest.mojom.TestBindingInterface"; - } - - // axtest::mojom::TestBindingInterface overrides: - void AddTestInterface(AddTestInterfaceCallback callback) override { - int index = test_interface_receivers_.size(); - test_interface_receivers_.emplace_back(); - auto pending_receiver = - test_interface_receivers_[index].BindNewPipeAndPassReceiver(); - std::move(callback).Run(std::move(pending_receiver)); - } - - void GetTestStruct(int num, - const std::string& name, - GetTestStructCallback callback) override { - auto result = axtest::mojom::TestStruct::New(); - result->is_structy = true; - // Modify the passed values a bit to ensure it's not just an echo. - result->num = num + 1; - result->name = name + " rocks"; - std::move(callback).Run(std::move(result)); - } - - void SendEnumToTestInterface(axtest::mojom::TestEnum num) override { - for (auto& receiver : test_interface_receivers_) { - receiver->TestMethod(num); - } - } - - void Disconnect() override { receiver_.reset(); } - - void TestComplete(bool success) override { - std::move(on_complete_).Run(success); - } - - private: - base::OnceCallback<void(bool)> on_complete_; - mojo::Receiver<axtest::mojom::TestBindingInterface> receiver_; - std::vector<mojo::Remote<axtest::mojom::TestInterface>> - test_interface_receivers_; -}; - class V8ManagerTest : public testing::Test { public: V8ManagerTest() = default; @@ -107,8 +45,8 @@ void RunJSMojoTest(const std::string& js_script) { base::RunLoop waiter; - std::unique_ptr<TestBindingInterfaceImpl> test_interface = - std::make_unique<TestBindingInterfaceImpl>( + std::unique_ptr<JSTestInterface> test_interface = + std::make_unique<JSTestInterface>( base::BindLambdaForTesting([&waiter](bool success) { EXPECT_TRUE(success) << "Mojo JS was not successful"; waiter.Quit(); @@ -196,8 +134,8 @@ #endif // BUILDFLAG(IS_FUCHSIA) TEST_F(V8ManagerTest, MAYBE_CheckMojoConstants) { base::RunLoop waiter; - std::unique_ptr<TestBindingInterfaceImpl> test_interface = - std::make_unique<TestBindingInterfaceImpl>( + std::unique_ptr<JSTestInterface> test_interface = + std::make_unique<JSTestInterface>( base::BindLambdaForTesting([&waiter](bool success) { EXPECT_TRUE(success) << "Mojo JS was not successful"; waiter.Quit();
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index cb1a9a4a1..e533d11c 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5730,9 +5730,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5743,8 +5743,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -5895,9 +5895,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -5908,8 +5908,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -6042,9 +6042,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -6055,8 +6055,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json index f472308..1ca7bed 100644 --- a/testing/buildbot/chromium.coverage.json +++ b/testing/buildbot/chromium.coverage.json
@@ -25491,9 +25491,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -25504,8 +25504,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -25656,9 +25656,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -25669,8 +25669,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -25803,9 +25803,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -25816,8 +25816,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 839bd7f..83883fd 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -21545,7 +21545,7 @@ } ], "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com", - "shards": 36 + "shards": 15 }, "test_id_prefix": "ninja://ios/chrome/test/wpt:wpt_tests_ios/" } @@ -31957,110 +31957,6 @@ { "args": [ "--platform", - "iPad Pro (12.9-inch) (3rd generation)", - "--version", - "16.4", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xcode-build-version", - "14e222b", - "--xctest", - "--xcode-parallelization" - ], - "isolate_name": "ios_swift_interop_xcuitests_module", - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "ios_swift_interop_xcuitests_module iPad Pro (12.9-inch) (3rd generation) 16.4", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:3e597065cb23c1fe03aeb2ebd792d83e0709c5c2" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "os": "Mac-13" - } - ], - "named_caches": [ - { - "name": "xcode_ios_14e222b", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_16_4", - "path": "Runtime-ios-16.4" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://ios/chrome/test/swift_interop:ios_swift_interop_xcuitests_module/", - "variant_id": "iPad Pro (12.9-inch) (3rd generation) 16.4" - }, - { - "args": [ - "--platform", - "iPhone X", - "--version", - "16.4", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xcode-build-version", - "14e222b", - "--xctest", - "--xcode-parallelization" - ], - "isolate_name": "ios_swift_interop_xcuitests_module", - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "ios_swift_interop_xcuitests_module iPhone X 16.4", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:3e597065cb23c1fe03aeb2ebd792d83e0709c5c2" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "os": "Mac-13" - } - ], - "named_caches": [ - { - "name": "xcode_ios_14e222b", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_16_4", - "path": "Runtime-ios-16.4" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://ios/chrome/test/swift_interop:ios_swift_interop_xcuitests_module/", - "variant_id": "iPhone X 16.4" - }, - { - "args": [ - "--platform", "iPhone X", "--version", "16.4", @@ -36453,114 +36349,6 @@ { "args": [ "--platform", - "iPad Air (3rd generation)", - "--version", - "16.4", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xcode-build-version", - "14e222b", - "--readline-timeout", - "600", - "--xctest", - "--xcode-parallelization" - ], - "isolate_name": "ios_swift_interop_xcuitests_module", - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "ios_swift_interop_xcuitests_module iPad Air (3rd generation) 16.4", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:3e597065cb23c1fe03aeb2ebd792d83e0709c5c2" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "os": "Mac-13" - } - ], - "named_caches": [ - { - "name": "xcode_ios_14e222b", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_16_4", - "path": "Runtime-ios-16.4" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://ios/chrome/test/swift_interop:ios_swift_interop_xcuitests_module/", - "variant_id": "iPad Air (3rd generation) 16.4" - }, - { - "args": [ - "--platform", - "iPhone X", - "--version", - "16.4", - "--out-dir", - "${ISOLATED_OUTDIR}", - "--xcode-build-version", - "14e222b", - "--readline-timeout", - "600", - "--xctest", - "--xcode-parallelization" - ], - "isolate_name": "ios_swift_interop_xcuitests_module", - "merge": { - "script": "//testing/merge_scripts/standard_isolated_script_merge.py" - }, - "name": "ios_swift_interop_xcuitests_module iPhone X 16.4", - "resultdb": { - "enable": true, - "has_native_resultdb_integration": true - }, - "swarming": { - "can_use_on_swarming_builders": true, - "cipd_packages": [ - { - "cipd_package": "infra/tools/mac_toolchain/${platform}", - "location": ".", - "revision": "git_revision:3e597065cb23c1fe03aeb2ebd792d83e0709c5c2" - } - ], - "dimension_sets": [ - { - "cpu": "x86-64", - "os": "Mac-13" - } - ], - "named_caches": [ - { - "name": "xcode_ios_14e222b", - "path": "Xcode.app" - }, - { - "name": "runtime_ios_16_4", - "path": "Runtime-ios-16.4" - } - ], - "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com" - }, - "test_id_prefix": "ninja://ios/chrome/test/swift_interop:ios_swift_interop_xcuitests_module/", - "variant_id": "iPhone X 16.4" - }, - { - "args": [ - "--platform", "iPhone X", "--version", "16.4", @@ -41594,9 +41382,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -41606,8 +41394,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -41759,9 +41547,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -41771,8 +41559,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -41906,9 +41694,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -41918,8 +41706,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -43383,9 +43171,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -43395,8 +43183,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -43548,9 +43336,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -43560,8 +43348,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -43695,9 +43483,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -43707,8 +43495,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -44443,9 +44231,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" }, @@ -44455,8 +44243,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index db5b21a..ddcfac5 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -18080,12 +18080,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -18096,8 +18096,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -18265,12 +18265,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -18281,8 +18281,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [ @@ -18427,12 +18427,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 115.0.5762.0", + "description": "Run with ash-chrome version 115.0.5763.0", "isolate_profile_data": true, "merge": { "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -18443,8 +18443,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v115.0.5762.0", - "revision": "version:115.0.5762.0" + "location": "lacros_version_skew_tests_v115.0.5763.0", + "revision": "version:115.0.5763.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl index b6637df8..c8b3b76 100644 --- a/testing/buildbot/gn_isolate_map.pyl +++ b/testing/buildbot/gn_isolate_map.pyl
@@ -983,10 +983,6 @@ "label": "//ios/showcase:ios_showcase_eg2tests_module", "type": "generated_script", }, - "ios_swift_interop_xcuitests_module": { - "label": "//ios/chrome/test/swift_interop:ios_swift_interop_xcuitests_module", - "type": "generated_script", - }, "ios_testing_unittests": { "label": "//ios/testing:ios_testing_unittests", "type": "generated_script",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 4157e21..a36de22 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -4008,10 +4008,6 @@ 'ui_base_unittests': {}, }, - 'ios_swift_interop_xcuitests': { - 'ios_swift_interop_xcuitests_module': {}, - }, - # END tests which run on the GPU bots 'js_code_coverage_browser_tests' : { @@ -5638,7 +5634,7 @@ }, 'results_handler': 'layout tests', 'swarming': { - 'shards': 36, + 'shards': 15, 'expiration': 18000, 'hard_timeout': 14400, }, @@ -6988,13 +6984,6 @@ 'SIM_IPHONE_X_16_4', ] }, - 'ios_swift_interop_xcuitests': { - 'mixins': ['xcode_parallelization'], - 'variants': [ - 'SIM_IPHONE_X_16_4', - 'SIM_IPAD_PRO_3RD_GEN_16_4', - ], - }, }, 'ios16_sdk_simulator_tests': { @@ -7033,13 +7022,6 @@ 'SIM_IPAD_PRO_3RD_GEN_16_4', ], }, - 'ios_swift_interop_xcuitests': { - 'mixins': ['xcode_parallelization'], - 'variants': [ - 'SIM_IPHONE_X_16_4', - 'SIM_IPAD_AIR_3RD_GEN_16_4', - ], - }, }, 'ios_asan_tests': {
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index e61b876..fdf4525 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5762.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v115.0.5763.0/test_ash_chrome', ], - 'description': 'Run with ash-chrome version 115.0.5762.0', + 'description': 'Run with ash-chrome version 115.0.5763.0', 'identifier': 'Lacros version skew testing ash canary', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v115.0.5762.0', - 'revision': 'version:115.0.5762.0', + 'location': 'lacros_version_skew_tests_v115.0.5763.0', + 'revision': 'version:115.0.5763.0', }, ], },
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 149c99d..973eab1 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1,20 +1,4 @@ { - "AboveNormalCompositingBrowserWin": [ - { - "platforms": [ - "windows" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "AboveNormalCompositingBrowserWin", - "MainThreadCompositingPriority" - ] - } - ] - } - ], "AccessibilityPageZoom": [ { "platforms": [ @@ -408,24 +392,6 @@ ] } ], - "AndroidScrollOptimizations": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Holdback_20221115", - "enable_features": [ - "AndroidBatteryMetricsReportOnUIThread" - ], - "disable_features": [ - "AndroidScrollOptimizations" - ] - } - ] - } - ], "AndroidSystemTracing": [ { "platforms": [ @@ -1036,6 +1002,7 @@ "enable_features": [ "AutofillEnableCardArtImage", "AutofillEnableCardProductName", + "AutofillEnableNewCardArtAndNetworkImages", "AutofillEnableVirtualCardMetadata" ] } @@ -2083,21 +2050,6 @@ ] } ], - "BrowserIOThreadADPF": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "kADPFForBrowserIOThread" - ] - } - ] - } - ], "BrowserPeriodicYieldingToNative": [ { "platforms": [ @@ -2938,6 +2890,23 @@ ] } ], + "ChromeRootStoreUsed": [ + { + "platforms": [ + "linux", + "chromeos", + "chromeos_lacros" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "ChromeRootStoreUsed" + ] + } + ] + } + ], "ChromeStartRefactor": [ { "platforms": [ @@ -7609,21 +7578,6 @@ ] } ], - "KeepAndroidTintedResources": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "Enabled", - "enable_features": [ - "KeepAndroidTintedResources" - ] - } - ] - } - ], "KeyboardAccessoryAddressIPH": [ { "platforms": [ @@ -8117,7 +8071,8 @@ "fuchsia", "ios", "linux", - "mac" + "mac", + "windows" ], "experiments": [ { @@ -8859,6 +8814,9 @@ "OmniboxLightBackgroundColorHovered": "0xE3E7F0" }, "enable_features": [ + "Cr2023ActionChips", + "OmniboxExpandedStateHeight", + "OmniboxExpandedStateShape", "OmniboxSteadyStateBackgroundColor", "OmniboxSteadyStateTextColor", "OmniboxSteadyStateTextStyle" @@ -12733,26 +12691,6 @@ ] } ], - "SyncPromoAfterSigninInterceptStudy": [ - { - "platforms": [ - "chromeos_lacros", - "fuchsia", - "linux", - "mac", - "windows" - ], - "experiments": [ - { - "name": "EnabledWithSyncPromo", - "enable_features": [ - "SigninInterceptBubbleV2", - "SyncPromoAfterSigninIntercept" - ] - } - ] - } - ], "SyncTrustedVaultVerifyDeviceRegistration": [ { "platforms": [ @@ -13425,6 +13363,21 @@ ] } ], + "UkmReduceAddEntryIPC": [ + { + "platforms": [ + "android" + ], + "experiments": [ + { + "name": "Enabled", + "enable_features": [ + "UkmReduceAddEntryIPC" + ] + } + ] + } + ], "UnifiedAutoplay": [ { "platforms": [
diff --git a/third_party/blink/renderer/bindings/core/v8/binding_security.cc b/third_party/blink/renderer/bindings/core/v8/binding_security.cc index 2b1d01d..60d1bcec 100644 --- a/third_party/blink/renderer/bindings/core/v8/binding_security.cc +++ b/third_party/blink/renderer/bindings/core/v8/binding_security.cc
@@ -70,8 +70,6 @@ } // namespace void BindingSecurity::Init() { - BindingSecurityForPlatform::SetShouldAllowAccessToV8ContextWithExceptionState( - ShouldAllowAccessToV8Context); BindingSecurityForPlatform:: SetShouldAllowAccessToV8ContextWithErrorReportOption( ShouldAllowAccessToV8Context); @@ -239,33 +237,6 @@ bool BindingSecurity::ShouldAllowAccessTo( const LocalDOMWindow* accessing_window, const DOMWindow* target, - ExceptionState& exception_state) { - DCHECK(target); - - // TODO(https://crbug.com/723057): This is intended to match the legacy - // behavior of when access checks revolved around Frame pointers rather than - // DOMWindow pointers. This prevents web-visible behavior changes, since the - // previous implementation had to follow the back pointer to the Frame, and - // would have to early return when it was null. - if (!target->GetFrame()) - return false; - bool can_access = CanAccessWindow(accessing_window, target, exception_state); - - if (!can_access && accessing_window) { - UseCounter::Count(accessing_window->document(), - WebFeature::kCrossOriginPropertyAccess); - if (target->opener() == accessing_window) { - UseCounter::Count(accessing_window->document(), - WebFeature::kCrossOriginPropertyAccessFromOpener); - } - } - - return can_access; -} - -bool BindingSecurity::ShouldAllowAccessTo( - const LocalDOMWindow* accessing_window, - const DOMWindow* target, ErrorReportOption reporting_option) { DCHECK(target); @@ -294,35 +265,6 @@ bool BindingSecurity::ShouldAllowAccessTo( const LocalDOMWindow* accessing_window, const Location* target, - ExceptionState& exception_state) { - DCHECK(target); - - // TODO(https://crbug.com/723057): This is intended to match the legacy - // behavior of when access checks revolved around Frame pointers rather than - // DOMWindow pointers. This prevents web-visible behavior changes, since the - // previous implementation had to follow the back pointer to the Frame, and - // would have to early return when it was null. - if (!target->DomWindow()->GetFrame()) - return false; - - bool can_access = - CanAccessWindow(accessing_window, target->DomWindow(), exception_state); - - if (!can_access && accessing_window) { - UseCounter::Count(accessing_window->document(), - WebFeature::kCrossOriginPropertyAccess); - if (target->DomWindow()->opener() == accessing_window) { - UseCounter::Count(accessing_window->document(), - WebFeature::kCrossOriginPropertyAccessFromOpener); - } - } - - return can_access; -} - -bool BindingSecurity::ShouldAllowAccessTo( - const LocalDOMWindow* accessing_window, - const Location* target, ErrorReportOption reporting_option) { DCHECK(target); @@ -352,16 +294,6 @@ bool BindingSecurity::ShouldAllowAccessTo( const LocalDOMWindow* accessing_window, const Node* target, - ExceptionState& exception_state) { - if (!target) - return false; - return CanAccessWindow(accessing_window, target->GetDocument().domWindow(), - exception_state); -} - -bool BindingSecurity::ShouldAllowAccessTo( - const LocalDOMWindow* accessing_window, - const Node* target, ErrorReportOption reporting_option) { if (!target) return false;
diff --git a/third_party/blink/renderer/bindings/core/v8/binding_security.h b/third_party/blink/renderer/bindings/core/v8/binding_security.h index 4272af790..c628127 100644 --- a/third_party/blink/renderer/bindings/core/v8/binding_security.h +++ b/third_party/blink/renderer/bindings/core/v8/binding_security.h
@@ -67,17 +67,11 @@ // DOMWindow static bool ShouldAllowAccessTo(const LocalDOMWindow* accessing_window, const DOMWindow* target, - ExceptionState&); - static bool ShouldAllowAccessTo(const LocalDOMWindow* accessing_window, - const DOMWindow* target, ErrorReportOption); // Location static bool ShouldAllowAccessTo(const LocalDOMWindow* accessing_window, const Location* target, - ExceptionState&); - static bool ShouldAllowAccessTo(const LocalDOMWindow* accessing_window, - const Location* target, ErrorReportOption); // Checks if the caller (|accessing_window|) is allowed to access the JS @@ -93,9 +87,6 @@ // Node static bool ShouldAllowAccessTo(const LocalDOMWindow* accessing_window, const Node* target, - ExceptionState&); - static bool ShouldAllowAccessTo(const LocalDOMWindow* accessing_window, - const Node* target, ErrorReportOption); // These overloads should be used only when checking a general access from
diff --git a/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc index e558b22b..c99d16a 100644 --- a/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc +++ b/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
@@ -10,6 +10,7 @@ #include "base/memory/ptr_util.h" #include "third_party/blink/renderer/core/animation/path_interpolation_functions.h" #include "third_party/blink/renderer/core/css/css_path_value.h" +#include "third_party/blink/renderer/core/css/css_value_list.h" #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/core/style/shape_clip_path_operation.h" @@ -54,7 +55,9 @@ builder.SetD(std::move(path)); return; case CSSPropertyID::kOffsetPath: - builder.SetOffsetPath(ShapeOffsetPathOperation::Create(std::move(path))); + // TODO(sakhapov): handle coord box. + builder.SetOffsetPath(ShapeOffsetPathOperation::Create( + std::move(path), CoordBox::kBorderBox)); return; case CSSPropertyID::kClipPath: builder.SetClipPath(ShapeClipPathOperation::Create(std::move(path))); @@ -132,10 +135,15 @@ const CSSValue& value, const StyleResolverState*, ConversionCheckers&) const { - auto* path_value = DynamicTo<cssvalue::CSSPathValue>(value); - if (!path_value) + const cssvalue::CSSPathValue* path_value = nullptr; + if (const auto* list = DynamicTo<CSSValueList>(value)) { + path_value = DynamicTo<cssvalue::CSSPathValue>(list->First()); + } else { + path_value = DynamicTo<cssvalue::CSSPathValue>(value); + } + if (!path_value) { return nullptr; - + } return PathInterpolationFunctions::ConvertValue( path_value->GetStylePath(), PathInterpolationFunctions::kForceAbsolute); }
diff --git a/third_party/blink/renderer/core/animation/css_ray_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_ray_interpolation_type.cc index e7fd786..3fe1fd7 100644 --- a/third_party/blink/renderer/core/animation/css_ray_interpolation_type.cc +++ b/third_party/blink/renderer/core/animation/css_ray_interpolation_type.cc
@@ -9,6 +9,7 @@ #include "base/memory/ptr_util.h" #include "third_party/blink/renderer/core/css/basic_shape_functions.h" +#include "third_party/blink/renderer/core/css/css_value_list.h" #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/core/style/shape_offset_path_operation.h" @@ -127,10 +128,12 @@ StyleResolverState& state) const { const auto& ray_non_interpolable_value = To<CSSRayNonInterpolableValue>(*non_interpolable_value); + // TODO(sakhapov): handle coord box. state.StyleBuilder().SetOffsetPath(ShapeOffsetPathOperation::Create( StyleRay::Create(To<InterpolableNumber>(interpolable_value).Value(), ray_non_interpolable_value.Mode().Size(), - ray_non_interpolable_value.Mode().Contain()))); + ray_non_interpolable_value.Mode().Contain()), + CoordBox::kBorderBox)); } void CSSRayInterpolationType::Composite( @@ -213,10 +216,17 @@ const StyleResolverState* state, ConversionCheckers&) const { DCHECK(state); - if (!value.IsRayValue()) + scoped_refptr<BasicShape> shape = nullptr; + if (const auto* list = DynamicTo<CSSValueList>(value)) { + if (list->First().IsRayValue()) { + shape = BasicShapeForValue(*state, list->First()); + } + } else if (value.IsRayValue()) { + shape = BasicShapeForValue(*state, value); + } + if (!shape) { return nullptr; - - scoped_refptr<BasicShape> shape = BasicShapeForValue(*state, value); + } return CreateValue(To<StyleRay>(*shape).Angle(), RayMode(To<StyleRay>(*shape))); }
diff --git a/third_party/blink/renderer/core/css/css_primitive_value_mappings.h b/third_party/blink/renderer/core/css/css_primitive_value_mappings.h index 2b52bf15..439b608 100644 --- a/third_party/blink/renderer/core/css/css_primitive_value_mappings.h +++ b/third_party/blink/renderer/core/css/css_primitive_value_mappings.h
@@ -1662,6 +1662,53 @@ } template <> +inline CoordBox CSSIdentifierValue::ConvertTo() const { + switch (GetValueID()) { + case CSSValueID::kContentBox: + return CoordBox::kContentBox; + case CSSValueID::kPaddingBox: + return CoordBox::kPaddingBox; + case CSSValueID::kBorderBox: + return CoordBox::kBorderBox; + case CSSValueID::kFillBox: + return CoordBox::kFillBox; + case CSSValueID::kStrokeBox: + return CoordBox::kStrokeBox; + case CSSValueID::kViewBox: + return CoordBox::kViewBox; + default: + break; + } + NOTREACHED(); + return CoordBox::kBorderBox; +} + +template <> +inline CSSIdentifierValue::CSSIdentifierValue(CoordBox coord_box) + : CSSValue(kIdentifierClass) { + switch (coord_box) { + case CoordBox::kContentBox: + value_id_ = CSSValueID::kContentBox; + break; + case CoordBox::kPaddingBox: + value_id_ = CSSValueID::kPaddingBox; + break; + case CoordBox::kBorderBox: + value_id_ = CSSValueID::kBorderBox; + break; + case CoordBox::kFillBox: + value_id_ = CSSValueID::kFillBox; + break; + case CoordBox::kStrokeBox: + value_id_ = CSSValueID::kStrokeBox; + break; + case CoordBox::kViewBox: + value_id_ = CSSValueID::kViewBox; + break; + } +} + +template <> inline TextUnderlinePosition CSSIdentifierValue::ConvertTo() const { switch (GetValueID()) { case CSSValueID::kAuto:
diff --git a/third_party/blink/renderer/core/css/css_value_keywords.json5 b/third_party/blink/renderer/core/css/css_value_keywords.json5 index caf359b..ed0bda78 100644 --- a/third_party/blink/renderer/core/css/css_value_keywords.json5 +++ b/third_party/blink/renderer/core/css/css_value_keywords.json5
@@ -1386,6 +1386,9 @@ "ray", "sides", + // coord-box + "stroke-box", + // math functions // https://drafts.csswg.org/css-values-4/#math "calc",
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc index d4fc41e..5cc8589b 100644 --- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc +++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -3646,6 +3646,13 @@ CSSValueID::kBorderBox>(range); } +// https://drafts.csswg.org/css-box-4/#typedef-coord-box +CSSIdentifierValue* ConsumeCoordBox(CSSParserTokenRange& range) { + return ConsumeIdent<CSSValueID::kContentBox, CSSValueID::kPaddingBox, + CSSValueID::kBorderBox, CSSValueID::kFillBox, + CSSValueID::kStrokeBox, CSSValueID::kViewBox>(range); +} + void AddProperty(CSSPropertyID resolved_property, CSSPropertyID current_shorthand, const CSSValue& value, @@ -6552,29 +6559,53 @@ CSSValue* ConsumeOffsetPath(CSSParserTokenRange& range, const CSSParserContext& context) { - CSSValue* value = nullptr; + CSSValue* offset_path = nullptr; + CSSValue* coord_box = nullptr; + + if (CSSValue* none = ConsumeIdent<CSSValueID::kNone>(range)) { + return none; + } + if (RuntimeEnabledFeatures::CSSOffsetPathCoordBoxEnabled()) { + coord_box = ConsumeCoordBox(range); + } + const CSSValueID function_id = range.Peek().FunctionId(); if (RuntimeEnabledFeatures::CSSOffsetPathRayEnabled() && function_id == CSSValueID::kRay) { - value = ConsumeRay(range, context); + offset_path = ConsumeRay(range, context); } - if (!value && IsBasicShapeSupportedByOffsetPath(function_id)) { - value = ConsumeBasicShape(range, context, AllowPathValue::kAllow, - AllowBasicShapeRectValue::kAllow, - AllowBasicShapeXYWHValue::kAllow); + if (!offset_path && IsBasicShapeSupportedByOffsetPath(function_id)) { + offset_path = ConsumeBasicShape(range, context, AllowPathValue::kAllow, + AllowBasicShapeRectValue::kAllow, + AllowBasicShapeXYWHValue::kAllow); } - if (!value && RuntimeEnabledFeatures::CSSOffsetPathUrlEnabled()) { - value = ConsumeUrl(range, context); + if (!offset_path && RuntimeEnabledFeatures::CSSOffsetPathUrlEnabled()) { + offset_path = ConsumeUrl(range, context); } - if (!value) { - value = ConsumePathOrNone(range); + if (!offset_path) { + offset_path = ConsumePathFunction(range); + } + + if (!coord_box && RuntimeEnabledFeatures::CSSOffsetPathCoordBoxEnabled()) { + coord_box = ConsumeCoordBox(range); + } + + if (!offset_path && !coord_box) { + return nullptr; + } + + CSSValueList* list = CSSValueList::CreateSpaceSeparated(); + if (offset_path) { + list->Append(*offset_path); + } + if (coord_box) { + list->Append(*coord_box); } // Count when we receive a valid path other than 'none'. - if (value && !value->IsIdentifierValue()) { - context.Count(WebFeature::kCSSOffsetInEffect); - } - return value; + context.Count(WebFeature::kCSSOffsetInEffect); + + return list; } CSSValue* ConsumePathOrNone(CSSParserTokenRange& range) {
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc index 9d2e9d7..edd6868 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -57,6 +57,7 @@ #include "third_party/blink/renderer/core/layout/layout_box.h" #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/style/computed_style.h" +#include "third_party/blink/renderer/core/style/coord_box_offset_path_operation.h" #include "third_party/blink/renderer/core/style/grid_area.h" #include "third_party/blink/renderer/core/style/reference_clip_path_operation.h" #include "third_party/blink/renderer/core/style/reference_offset_path_operation.h" @@ -5660,12 +5661,33 @@ if (operation) { if (const auto* shape_operation = DynamicTo<ShapeOffsetPathOperation>(operation)) { - return ValueForBasicShape(style, &shape_operation->GetBasicShape()); + CSSValueList* list = CSSValueList::CreateSpaceSeparated(); + CSSValue* shape = + ValueForBasicShape(style, &shape_operation->GetBasicShape()); + list->Append(*shape); + CoordBox coord_box = shape_operation->GetCoordBox(); + if (coord_box != CoordBox::kBorderBox) { + list->Append(*CSSIdentifierValue::Create(coord_box)); + } + return list; + } + if (const auto* coord_box_operation = + DynamicTo<CoordBoxOffsetPathOperation>(operation)) { + CSSValueList* list = CSSValueList::CreateSpaceSeparated(); + CoordBox coord_box = coord_box_operation->GetCoordBox(); + list->Append(*CSSIdentifierValue::Create(coord_box)); + return list; } const auto& reference_operation = To<ReferenceOffsetPathOperation>(*operation); + CSSValueList* list = CSSValueList::CreateSpaceSeparated(); AtomicString url = reference_operation.Url(); - return MakeGarbageCollected<cssvalue::CSSURIValue>(url); + list->Append(*MakeGarbageCollected<cssvalue::CSSURIValue>(url)); + CoordBox coord_box = reference_operation.GetCoordBox(); + if (coord_box != CoordBox::kBorderBox) { + list->Append(*CSSIdentifierValue::Create(coord_box)); + } + return list; } return CSSIdentifierValue::Create(CSSValueID::kNone); }
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc index ef40b2b..eb3a365 100644 --- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc +++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -68,6 +68,9 @@ #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/web_feature.h" #include "third_party/blink/renderer/core/style/anchor_specifier_value.h" +#include "third_party/blink/renderer/core/style/computed_style_constants.h" +#include "third_party/blink/renderer/core/style/coord_box_offset_path_operation.h" +#include "third_party/blink/renderer/core/style/offset_path_operation.h" #include "third_party/blink/renderer/core/style/reference_clip_path_operation.h" #include "third_party/blink/renderer/core/style/reference_offset_path_operation.h" #include "third_party/blink/renderer/core/style/scoped_css_name.h" @@ -2458,26 +2461,52 @@ return nullptr; } +namespace { + +scoped_refptr<OffsetPathOperation> ConvertOffsetPathValueToOperation( + StyleResolverState& state, + const CSSValue& value, + CoordBox coord_box) { + if (value.IsRayValue() || value.IsBasicShapeValue()) { + return ShapeOffsetPathOperation::Create(BasicShapeForValue(state, value), + coord_box); + } + if (auto* path_value = DynamicTo<cssvalue::CSSPathValue>(value)) { + return ShapeOffsetPathOperation::Create(path_value->GetStylePath(), + coord_box); + } + const auto& url_value = To<cssvalue::CSSURIValue>(value); + SVGResource* resource = + state.GetElementStyleResources().GetSVGResourceFromValue( + CSSPropertyID::kOffsetPath, url_value); + return ReferenceOffsetPathOperation::Create(url_value.ValueForSerialization(), + resource, coord_box); +} + +} // namespace + scoped_refptr<OffsetPathOperation> StyleBuilderConverter::ConvertOffsetPath( StyleResolverState& state, const CSSValue& value) { - if (value.IsRayValue() || value.IsBasicShapeValue()) { - return ShapeOffsetPathOperation::Create(BasicShapeForValue(state, value)); + if (value.IsIdentifierValue()) { + DCHECK(To<CSSIdentifierValue>(value).GetValueID() == CSSValueID::kNone); + // none: The element does not have an offset transform. + return nullptr; } - if (auto* path_value = DynamicTo<cssvalue::CSSPathValue>(value)) { - return ShapeOffsetPathOperation::Create(path_value->GetStylePath()); + const auto& list = To<CSSValueList>(value); + if (const auto* identifier = DynamicTo<CSSIdentifierValue>(list.First())) { + // If <offset-path> is omitted, it defaults to inset(0 round X), + // where X is the value of border-radius on the element that + // establishes the containing block for this element. + return CoordBoxOffsetPathOperation::Create( + identifier->ConvertTo<CoordBox>()); } - if (const auto* url_value = DynamicTo<cssvalue::CSSURIValue>(value)) { - SVGResource* resource = - state.GetElementStyleResources().GetSVGResourceFromValue( - CSSPropertyID::kOffsetPath, *url_value); - return ReferenceOffsetPathOperation::Create( - url_value->ValueForSerialization(), resource); - } - auto* identifier_value = DynamicTo<CSSIdentifierValue>(value); - DCHECK(identifier_value && - identifier_value->GetValueID() == CSSValueID::kNone); - return nullptr; + // If <coord-box> is omitted, it defaults to border-box. + CoordBox coord_box = + list.length() == 2 + ? To<CSSIdentifierValue>(list.Last()).ConvertTo<CoordBox>() + : CoordBox::kBorderBox; + return ConvertOffsetPathValueToOperation(state, list.First(), coord_box); } scoped_refptr<BasicShape> StyleBuilderConverter::ConvertObjectViewBox(
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h index a4e692cee..6dc5a12 100644 --- a/third_party/blink/renderer/core/editing/markers/document_marker_controller.h +++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller.h
@@ -180,8 +180,9 @@ const Text&, DocumentMarker::MarkerTypes = DocumentMarker::MarkerTypes::All()) const; DocumentMarkerVector Markers() const; - DocumentMarkerVector CustomHighlightMarkersNotOverlapping(const Text&) const; + DocumentMarkerVector ComputeMarkersToPaint(const Text&) const; + DocumentMarkerVector CustomHighlightMarkersNotOverlapping(const Text&) const; bool PossiblyHasTextMatchMarkers() const; Vector<gfx::Rect> LayoutRectsForTextMatchMarkers();
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc index a48d039..e3d2f13 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.cc +++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -2163,15 +2163,17 @@ // This is usually, but not necessarily the same as 'this'. LocalDOMWindow* entered_window = EnteredDOMWindow(isolate); - if (!IsCurrentlyDisplayedInFrame()) + if (!IsCurrentlyDisplayedInFrame() || !entered_window->GetFrame()) { return nullptr; + } // If the bindings implementation is 100% correct, the current realm and the // entered realm should be same origin-domain. However, to be on the safe // side and add some defense in depth, we'll check against the entry realm // as well here. - if (!BindingSecurity::ShouldAllowAccessTo(entered_window, this, - exception_state)) { + if (!BindingSecurity::ShouldAllowAccessTo( + entered_window, this, + BindingSecurity::ErrorReportOption::kDoNotReport)) { // Trigger DCHECK() failure, while gracefully failing on release builds. NOTREACHED(); UseCounter::Count(GetExecutionContext(), @@ -2179,9 +2181,6 @@ return nullptr; } - if (!entered_window->GetFrame()) - return nullptr; - UseCounter::Count(*entered_window, WebFeature::kDOMWindowOpen); entered_window->CountUseOnlyInCrossOriginIframe( WebFeature::kDOMWindowOpenCrossOriginIframe); @@ -2310,15 +2309,17 @@ LocalDOMWindow* entered_window = EnteredDOMWindow(isolate); DCHECK(isSecureContext()); - if (!IsCurrentlyDisplayedInFrame()) + if (!IsCurrentlyDisplayedInFrame() || !entered_window->GetFrame()) { return nullptr; + } // If the bindings implementation is 100% correct, the current realm and the // entered realm should be same origin-domain. However, to be on the safe // side and add some defense in depth, we'll check against the entry realm // as well here. - if (!BindingSecurity::ShouldAllowAccessTo(entered_window, this, - exception_state)) { + if (!BindingSecurity::ShouldAllowAccessTo( + entered_window, this, + BindingSecurity::ErrorReportOption::kDoNotReport)) { // Trigger DCHECK() failure, while gracefully failing on release builds. NOTREACHED(); UseCounter::Count(GetExecutionContext(), @@ -2326,9 +2327,6 @@ return nullptr; } - if (!entered_window->GetFrame()) - return nullptr; - FrameLoadRequest frame_request(entered_window, ResourceRequest(KURL(g_empty_string))); frame_request.SetPictureInPictureWindowOptions(options);
diff --git a/third_party/blink/renderer/core/html/lazy_load_image_observer.cc b/third_party/blink/renderer/core/html/lazy_load_image_observer.cc index 5470cfa..4b4f57b 100644 --- a/third_party/blink/renderer/core/html/lazy_load_image_observer.cc +++ b/third_party/blink/renderer/core/html/lazy_load_image_observer.cc
@@ -231,8 +231,6 @@ void LazyLoadImageObserver::StartMonitoringVisibility( Document* root_document, HTMLImageElement* image_element) { - DCHECK(RuntimeEnabledFeatures::LazyImageVisibleLoadTimeMetricsEnabled()); - VisibleLoadTimeMetrics& visible_load_time_metrics = image_element->EnsureVisibleLoadTimeMetrics(); if (!visible_load_time_metrics.time_when_first_visible.is_null()) { @@ -251,7 +249,6 @@ } void LazyLoadImageObserver::OnLoadFinished(HTMLImageElement* image_element) { - DCHECK(RuntimeEnabledFeatures::LazyImageVisibleLoadTimeMetricsEnabled()); VisibleLoadTimeMetrics& visible_load_time_metrics = image_element->EnsureVisibleLoadTimeMetrics();
diff --git a/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc b/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc index 04203dc..23818244 100644 --- a/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc +++ b/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
@@ -447,10 +447,6 @@ EXPECT_FALSE(GetDocument().IsUseCounted( WebFeature::kLazyLoadImageLoadingAttributeEager)); } - - private: - ScopedLazyImageVisibleLoadTimeMetricsForTest - scoped_lazy_image_visible_load_time_metrics_for_test_ = true; }; TEST_F(LazyLoadImagesTest, LoadAllImagesIfPrinting) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc index 221de77..e22dd752 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc
@@ -221,7 +221,8 @@ PhysicalSize(one_em, line_height)); } -PhysicalRect LayoutNGTextCombine::RecalcContentsInkOverflow() const { +PhysicalRect LayoutNGTextCombine::RecalcContentsInkOverflow( + const NGInlineCursor& cursor) const { const ComputedStyle& style = Parent()->StyleRef(); DCHECK(style.GetFont().GetFontDescription().IsVerticalBaseline()); @@ -232,11 +233,10 @@ if (style.HasAppliedTextDecorations()) { // |LayoutNGTextCombine| does not support decorating box, as it is not // supported in vertical flow and text-combine is only for vertical flow. - const LayoutRect decoration_rect = - NGInkOverflow::ComputeTextDecorationOverflow( - style, style.GetFont(), - /* offset_in_container */ PhysicalOffset(), ink_overflow, - /* inline_context */ nullptr); + const LayoutRect decoration_rect = NGInkOverflow::ComputeDecorationOverflow( + cursor, style, style.GetFont(), + /* offset_in_container */ PhysicalOffset(), ink_overflow, + /* inline_context */ nullptr); ink_overflow.Unite(decoration_rect); }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.h b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.h index 70ad54f4..924da37 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.h +++ b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.h
@@ -14,6 +14,7 @@ class AffineTransform; class LayoutText; class NGFragmentItem; +class NGInlineCursor; // The layout object for the element having "text-combine-upright:all" in // vertical writing mode, e.g. <i style="text-upright:all"><b>12</b>34<i>. @@ -66,7 +67,7 @@ const PhysicalOffset& inline_root_offset) const; // Returns ink overflow for text decorations and emphasis mark. - PhysicalRect RecalcContentsInkOverflow() const; + PhysicalRect RecalcContentsInkOverflow(const NGInlineCursor&) const; void ResetLayout(); void SetScaleX(float new_scale_x);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc index 561d087..93bd865 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -861,7 +861,7 @@ if (Type() == kSvgText) { ink_overflow_type_ = static_cast<unsigned>(ink_overflow_.SetSvgTextInkOverflow( - InkOverflowType(), paint_info, Style(), ScaledFont(), + InkOverflowType(), cursor, paint_info, Style(), ScaledFont(), SvgFragmentData()->rect, SvgScalingFactor(), SvgFragmentData()->length_adjust_scale, BuildSvgTransformForBoundingBox(), self_and_contents_rect_out)); @@ -873,8 +873,9 @@ inline_context); ink_overflow_type_ = static_cast<unsigned>(ink_overflow_.SetTextInkOverflow( - InkOverflowType(), paint_info, Style(), RectInContainerFragment(), - inline_context, self_and_contents_rect_out)); + InkOverflowType(), cursor, paint_info, Style(), + RectInContainerFragment(), inline_context, + self_and_contents_rect_out)); return; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc index fcf05e2..4aa7e059 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
@@ -5,10 +5,16 @@ #include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h" #include "build/chromeos_buildflags.h" +#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h" #include "third_party/blink/renderer/core/layout/geometry/logical_rect.h" #include "third_party/blink/renderer/core/layout/geometry/writing_mode_converter.h" +#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h" #include "third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h" +#include "third_party/blink/renderer/core/paint/highlight_painting_utils.h" +#include "third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h" +#include "third_party/blink/renderer/core/paint/ng/ng_inline_paint_context.h" #include "third_party/blink/renderer/core/paint/text_decoration_info.h" +#include "third_party/blink/renderer/core/style/applied_text_decoration.h" #include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/platform/transforms/affine_transform.h" #include "third_party/blink/renderer/platform/wtf/size_assertions.h" @@ -349,6 +355,7 @@ NGInkOverflow::Type NGInkOverflow::SetTextInkOverflow( Type type, + const NGInlineCursor& cursor, const NGTextFragmentPaintInfo& text_info, const ComputedStyle& style, const PhysicalRect& rect_in_container, @@ -356,8 +363,9 @@ PhysicalRect* ink_overflow_out) { CheckType(type); DCHECK(type == Type::kNotSet || type == Type::kInvalidated); - absl::optional<PhysicalRect> ink_overflow = ComputeTextInkOverflow( - text_info, style, style.GetFont(), rect_in_container, inline_context); + absl::optional<PhysicalRect> ink_overflow = + ComputeTextInkOverflow(cursor, text_info, style, style.GetFont(), + rect_in_container, inline_context); if (!ink_overflow) { *ink_overflow_out = {PhysicalOffset(), rect_in_container.size}; return Reset(type); @@ -369,6 +377,7 @@ NGInkOverflow::Type NGInkOverflow::SetSvgTextInkOverflow( Type type, + const NGInlineCursor& cursor, const NGTextFragmentPaintInfo& text_info, const ComputedStyle& style, const Font& scaled_font, @@ -388,9 +397,10 @@ : PhysicalSize(LayoutUnit(rect.width()), LayoutUnit(rect.height() / length_adjust_scale)); // No |inline_context| because the decoration box is not supported for SVG. - absl::optional<PhysicalRect> ink_overflow = ComputeTextInkOverflow( - text_info, style, scaled_font, PhysicalRect(PhysicalOffset(), item_size), - /* inline_context */ nullptr); + absl::optional<PhysicalRect> ink_overflow = + ComputeTextInkOverflow(cursor, text_info, style, scaled_font, + PhysicalRect(PhysicalOffset(), item_size), + /* inline_context */ nullptr); const bool needs_transform = scaling_factor != 1.0f || !transform.IsIdentity(); PhysicalSize unscaled_size = PhysicalSize::FromSizeFRound(rect.size()); @@ -435,6 +445,7 @@ // static absl::optional<PhysicalRect> NGInkOverflow::ComputeTextInkOverflow( + const NGInlineCursor& cursor, const NGTextFragmentPaintInfo& text_info, const ComputedStyle& style, const Font& scaled_font, @@ -457,11 +468,11 @@ // Following effects, such as shadows, operate on the text decorations, // so compute text decoration overflow first. - if (style.HasAppliedTextDecorations() && scaled_font.PrimaryFont()) { - LayoutRect decoration_rect = ComputeTextDecorationOverflow( - style, scaled_font, rect_in_container.offset, ink_overflow, - inline_context); - ink_overflow.Unite(decoration_rect); + absl::optional<LayoutRect> decoration_rect = ComputeDecorationOverflow( + cursor, style, scaled_font, rect_in_container.offset, ink_overflow, + inline_context); + if (decoration_rect) { + ink_overflow.Unite(decoration_rect.value()); } if (style.GetTextEmphasisMark() != TextEmphasisMark::kNone) { @@ -521,33 +532,83 @@ } // static -LayoutRect NGInkOverflow::ComputeTextDecorationOverflow( +LayoutRect NGInkOverflow::ComputeDecorationOverflow( + const NGInlineCursor& cursor, + const ComputedStyle& style, + const Font& scaled_font, + const PhysicalOffset& container_offset, + const LayoutRect& ink_overflow, + const NGInlinePaintContext* inline_context) { + LayoutRect accumulated_bound; + if (!scaled_font.PrimaryFont()) { + return accumulated_bound; + } + // Text decoration from the fragment's style. + if (style.HasAppliedTextDecorations()) { + accumulated_bound = ComputeAppliedDecorationOverflow( + style, scaled_font, container_offset, ink_overflow, inline_context); + } + + bool do_spelling_grammar = + RuntimeEnabledFeatures::CSSSpellingGrammarErrorsEnabled() || + RuntimeEnabledFeatures::CSSPaintingForSpellingGrammarErrorsEnabled(); + + if (do_spelling_grammar) { + // To extract decorations due to markers, we need a fragment item and a + // node. Ideally we would use cursor.Current().GetNode() but that's const + // and the style functions we need to access pseudo styles take non-const + // nodes. + const NGFragmentItem* fragment_item = cursor.CurrentItem(); + if (!fragment_item->IsText() || fragment_item->IsGeneratedText()) { + return accumulated_bound; + } + const LayoutObject* layout_object = cursor.CurrentMutableLayoutObject(); + DCHECK(layout_object); + Text* text_node = DynamicTo<Text>(layout_object->GetNode()); + // ::first-letter passes the IsGeneratedText check but has no text node. + if (!text_node) { + return accumulated_bound; + } + + DocumentMarkerController& controller = text_node->GetDocument().Markers(); + + DocumentMarkerVector spelling_markers = controller.MarkersFor( + *text_node, DocumentMarker::MarkerTypes::Spelling()); + LayoutRect spelling_bound = ComputeSpellingOrGrammarOverflow( + spelling_markers, DocumentMarker::kSpelling, fragment_item, text_node, + style, scaled_font, container_offset, ink_overflow, inline_context); + accumulated_bound.Unite(spelling_bound); + + DocumentMarkerVector grammar_markers = controller.MarkersFor( + *text_node, DocumentMarker::MarkerTypes::Grammar()); + LayoutRect grammar_bound = ComputeSpellingOrGrammarOverflow( + grammar_markers, DocumentMarker::kGrammar, fragment_item, text_node, + style, scaled_font, container_offset, ink_overflow, inline_context); + accumulated_bound.Unite(grammar_bound); + } + return accumulated_bound; +} + +LayoutRect NGInkOverflow::ComputeAppliedDecorationOverflow( const ComputedStyle& style, const Font& scaled_font, const PhysicalOffset& offset_in_container, const LayoutRect& ink_overflow, - const NGInlinePaintContext* inline_context) { - DCHECK(style.HasAppliedTextDecorations()); - // Ideally we should pass MinimumThickness1(false) if this function is - // called for NGFragmentItem::kSvgText. However it requires to add arguments - // to some functions. - // We pass MinimumThickness1(true) even for kSvgText. it's acceptable - // because it just makes the resultant ink overflow slightly larger. - const MinimumThickness1 kMinimumThicknessIsOne(true); + const NGInlinePaintContext* inline_context, + const AppliedTextDecoration* decoration_override) { + DCHECK(style.HasAppliedTextDecorations() || decoration_override); + // SVGText is currently the only reason we use decoration_override, + // so use it as a proxy for determining minimum thickness. + const MinimumThickness1 kMinimumThicknessIsOne(!decoration_override); TextDecorationInfo decoration_info( offset_in_container, ink_overflow.Width(), style, inline_context, - /* selection_text_decoration */ absl::nullopt, /* decoration_override */ - nullptr, &scaled_font, kMinimumThicknessIsOne); + /* selection_text_decoration */ absl::nullopt, decoration_override, + &scaled_font, kMinimumThicknessIsOne); NGTextDecorationOffset decoration_offset(decoration_info.TargetStyle(), style); - const Vector<AppliedTextDecoration, 1>& decorations = - style.AppliedTextDecorations(); - gfx::RectF accumulated_bound; - for (wtf_size_t applied_decoration_index = 0; - applied_decoration_index < decorations.size(); - ++applied_decoration_index) { - decoration_info.SetDecorationIndex(applied_decoration_index); + for (wtf_size_t i = 0; i < decoration_info.AppliedDecorationCount(); i++) { + decoration_info.SetDecorationIndex(i); if (decoration_info.HasUnderline()) { decoration_info.SetUnderlineLineData(decoration_offset); accumulated_bound.Union(decoration_info.Bounds()); @@ -560,10 +621,62 @@ decoration_info.SetLineThroughLineData(); accumulated_bound.Union(decoration_info.Bounds()); } + if (decoration_info.HasSpellingError() || + decoration_info.HasGrammarError()) { + decoration_info.SetSpellingOrGrammarErrorLineData(decoration_offset); + accumulated_bound.Union(decoration_info.Bounds()); + } } // Adjust the container coordinate system to the local coordinate system. accumulated_bound -= gfx::Vector2dF(offset_in_container); return EnclosingLayoutRect(accumulated_bound); } +LayoutRect NGInkOverflow::ComputeSpellingOrGrammarOverflow( + const DocumentMarkerVector& markers, + const DocumentMarker::MarkerType type, + const NGFragmentItem* fragment_item, + Text* text_node, + const ComputedStyle& style, + const Font& scaled_font, + const PhysicalOffset& offset_in_container, + const LayoutRect& ink_overflow, + const NGInlinePaintContext* inline_context) { + LayoutRect accumulated_bound; + auto pseudo_style = + fragment_item->Type() == NGFragmentItem::kSvgText + ? nullptr + : HighlightPaintingUtils::HighlightPseudoStyle( + text_node, style, NGHighlightPainter::PseudoFor(type)); + for (auto marker : markers) { + const unsigned marker_start_offset = + NGHighlightPainter::GetTextContentOffset(*text_node, + marker->StartOffset()); + const unsigned marker_end_offset = NGHighlightPainter::GetTextContentOffset( + *text_node, marker->EndOffset()); + if (marker_start_offset > fragment_item->EndOffset() || + marker_end_offset < fragment_item->StartOffset()) { + return LayoutRect(); + } + LayoutRect decoration_bound; + if (pseudo_style) { + decoration_bound = ComputeAppliedDecorationOverflow( + *pseudo_style, scaled_font, offset_in_container, ink_overflow, + inline_context); + } else { + const AppliedTextDecoration synthesised{ + NGHighlightPainter::LineFor(type), + {}, + NGHighlightPainter::ColorFor(type), + {}, + {}}; + decoration_bound = ComputeAppliedDecorationOverflow( + style, scaled_font, offset_in_container, ink_overflow, inline_context, + &synthesised); + } + accumulated_bound.Unite(decoration_bound); + } + return accumulated_bound; +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h index 4f6c25a9..aa9c4883 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h +++ b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h
@@ -10,15 +10,20 @@ #include "build/build_config.h" #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/editing/markers/document_marker.h" #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h" namespace blink { class AffineTransform; +class AppliedTextDecoration; class ComputedStyle; class Font; +class NGFragmentItem; +class NGInlineCursor; class NGInlinePaintContext; struct NGTextFragmentPaintInfo; +class Text; // Represents an ink-overflow rectangle. Used for: // - Objects without children, such as text runs. @@ -115,6 +120,7 @@ // Compute and set ink overflow for text. Type SetTextInkOverflow(Type type, + const NGInlineCursor& cursor, const NGTextFragmentPaintInfo& text_info, const ComputedStyle& style, const PhysicalRect& rect_in_container, @@ -125,6 +131,7 @@ // |rect| represents scaled rectangle, and |*ink_overflow_out| will store // unscaled rectangle. Type SetSvgTextInkOverflow(Type type, + const NGInlineCursor& cursor, const NGTextFragmentPaintInfo& text_info, const ComputedStyle& style, const Font& scaled_font, @@ -135,6 +142,7 @@ PhysicalRect* ink_overflow_out); static absl::optional<PhysicalRect> ComputeTextInkOverflow( + const NGInlineCursor& cursor, const NGTextFragmentPaintInfo& text_info, const ComputedStyle& style, const Font& scaled_font, @@ -150,12 +158,15 @@ const LayoutRect& ink_overflow); // Returns ink-overflow with text decoration overflow in logical direction. - // Note: |style| should have applied text decorations and |ink_overflow| - // should be in logical direction. - static LayoutRect ComputeTextDecorationOverflow( + // |inline_context| may be null. + // Note: |ink_overflow| should be in logical direction. + // Returns ink-overflow with text decoration, markers and highlights + // overflow in the logical direction. + static LayoutRect ComputeDecorationOverflow( + const NGInlineCursor& cursor, const ComputedStyle& style, const Font& scaled_font, - const PhysicalOffset& offset_in_container, + const PhysicalOffset& container_offset, const LayoutRect& ink_overflow, const NGInlinePaintContext* inline_context); @@ -172,6 +183,25 @@ #endif private: + static LayoutRect ComputeAppliedDecorationOverflow( + const ComputedStyle& style, + const Font& scaled_font, + const PhysicalOffset& offset_in_container, + const LayoutRect& ink_overflow, + const NGInlinePaintContext* inline_context, + const AppliedTextDecoration* decoration_override = nullptr); + + static LayoutRect ComputeSpellingOrGrammarOverflow( + const DocumentMarkerVector& markers, + const DocumentMarker::MarkerType type, + const NGFragmentItem* fragment_item, + Text* node, + const ComputedStyle& style, + const Font& scaled_font, + const PhysicalOffset& offset_in_container, + const LayoutRect& ink_overflow, + const NGInlinePaintContext* inline_context); + PhysicalRect FromOutsets(const PhysicalSize& size) const; void CheckType(Type type) const;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc index 7102347..9024c7b 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -1216,8 +1216,13 @@ // text. const auto* const text_combine = DynamicTo<LayoutNGTextCombine>(GetLayoutObject()); - if (UNLIKELY(text_combine)) - contents_rect.Unite(text_combine->RecalcContentsInkOverflow()); + if (UNLIKELY(text_combine)) { + // Reset the cursor for text combine to provide a current item for + // decorations. + NGInlineCursor text_combine_cursor(*this, *items); + contents_rect.Unite( + text_combine->RecalcContentsInkOverflow(text_combine_cursor)); + } // Even if this turned out to be an inline formatting context with // fragment items (handled above), we need to handle floating descendants.
diff --git a/third_party/blink/renderer/core/loader/lazy_image_helper.cc b/third_party/blink/renderer/core/loader/lazy_image_helper.cc index 468d40ea..da32c40 100644 --- a/third_party/blink/renderer/core/loader/lazy_image_helper.cc +++ b/third_party/blink/renderer/core/loader/lazy_image_helper.cc
@@ -87,11 +87,9 @@ // static void LazyImageHelper::StartMonitoringVisibilityMetrics( HTMLImageElement* html_image) { - Document* document = GetRootDocumentOrNull(html_image); - if (document && - RuntimeEnabledFeatures::LazyImageVisibleLoadTimeMetricsEnabled()) { - document->EnsureLazyLoadImageObserver().StartMonitoringVisibility( - document, html_image); + if (Document* root_document = GetRootDocumentOrNull(html_image)) { + root_document->EnsureLazyLoadImageObserver().StartMonitoringVisibility( + root_document, html_image); } } @@ -101,22 +99,21 @@ return; } + Document* root_document = GetRootDocumentOrNull(image_element); + if (!root_document) { + return; + } + if (ImageResourceContent* content = image_element->CachedImage()) { int64_t response_size = content->GetResponse().EncodedDataLength(); IMAGE_BYTES_HISTOGRAM("Blink.LazyLoadedImage.Size", response_size); - if (Document* document = GetRootDocumentOrNull(image_element)) { - if (!document->LoadEventFinished()) { - IMAGE_BYTES_HISTOGRAM("Blink.LazyLoadedImageBeforeDocumentOnLoad.Size", - response_size); - } + if (!root_document->LoadEventFinished()) { + IMAGE_BYTES_HISTOGRAM("Blink.LazyLoadedImageBeforeDocumentOnLoad.Size", + response_size); } } - if (!RuntimeEnabledFeatures::LazyImageVisibleLoadTimeMetricsEnabled()) - return; - if (Document* document = GetRootDocumentOrNull(image_element)) { - document->EnsureLazyLoadImageObserver().OnLoadFinished(image_element); - } + root_document->EnsureLazyLoadImageObserver().OnLoadFinished(image_element); } } // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc index bfc60f7..091b2f6 100644 --- a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc +++ b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
@@ -25,6 +25,8 @@ #include "base/test/scoped_feature_list.h" #include "base/uuid.h" #include "build/build_config.h" +#include "cc/animation/animation_host.h" +#include "cc/animation/keyframe_effect.h" #include "cc/base/features.h" #include "cc/input/main_thread_scrolling_reason.h" #include "cc/layers/scrollbar_layer_base.h" @@ -57,6 +59,7 @@ #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/testing/sim/sim_request.h" #include "third_party/blink/renderer/core/testing/sim/sim_test.h" +#include "third_party/blink/renderer/platform/animation/compositor_animation.h" #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h" #include "third_party/blink/renderer/platform/graphics/test/fake_gles2_interface.h" #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h" @@ -2722,6 +2725,95 @@ EXPECT_EQ(100, box->ScrolledContentOffset().top); } +TEST_P(ScrollingSimTest, ScrollTimelineActiveAtBoundary) { + String kUrl = "https://example.com/test.html"; + SimRequest request(kUrl, "text/html"); + LoadURL(kUrl); + + request.Complete(R"HTML( + <style> + #s { overflow-y: scroll; width: 300px; height: 200px; + position: relative; background: white; } + #sp { width: 100px; height: 1000px; } + #align { width: 100%; height: 20px; position: absolute; background: blue; + will-change: transform; animation: a linear 10s; + animation-timeline: scroll(); } + @keyframes a { + 0% { transform: translateY(0); } + 100% { transform: translateY(800px); } + } + </style> + <div id=s><div id=sp><div id=align></div>hello</div></div> + )HTML"); + + cc::AnimationHost* impl_host = + static_cast<cc::AnimationHost*>(GetLayerTreeHostImpl()->mutator_host()); + + // First frame: Initial commit creates the cc::Animation etc. + Compositor().BeginFrame(); + + blink::Animation* animation = + GetDocument().getElementById("align")->getAnimations()[0]; + cc::Animation* cc_animation = + animation->GetCompositorAnimation()->CcAnimation(); + cc::ElementId element_id = cc_animation->element_id(); + + gfx::KeyframeModel* keyframe_model_main = + cc_animation->GetKeyframeModel(cc::TargetProperty::TRANSFORM); + cc::KeyframeEffect* keyframe_effect = + impl_host->GetElementAnimationsForElementIdForTesting(element_id) + ->FirstKeyframeEffectForTesting(); + gfx::KeyframeModel* keyframe_model_impl = + keyframe_effect->keyframe_models()[0].get(); + + EXPECT_EQ(gfx::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY, + keyframe_model_impl->run_state()); + + // Activate the timeline (see ScrollTimeline::IsActive), so that it will be + // ticked during the next LTHI::Animate. + impl_host->PromoteScrollTimelinesPendingToActive(); + + // Second frame: LTHI::Animate transitions to RunState::STARTING. Pass + // raster=true to also reach LTHI::UpdateAnimationState, which transitions + // STARTING -> RUNNING. + Compositor().BeginFrame(0.016, /* raster */ true); + EXPECT_EQ(gfx::KeyframeModel::RUNNING, keyframe_model_impl->run_state()); + + // Scroll to the end. + GetDocument().getElementById("s")->setScrollTop(800); + + // Third frame: LTHI::Animate transitions RUNNING -> PAUSED. Then main frame + // LayerTreeHost::ApplyMutatorEvents dispatches AnimationEvent::STARTED and + // resets KeyframeModel::needs_synchronized_start_time_. + Compositor().BeginFrame(); + EXPECT_EQ(gfx::KeyframeModel::PAUSED, keyframe_model_impl->run_state()); + + // Verify that KeyframeModel::CalculatePhase returns ACTIVE for the case of + // local_time == active_after_boundary_time. + base::TimeTicks max = base::TimeTicks() + base::Seconds(100); + EXPECT_TRUE(keyframe_model_main->HasActiveTime(max)); + EXPECT_TRUE(keyframe_model_impl->HasActiveTime(max)); + + // Try reversed playbackRate, and verify that we are also ACTIVE in the case + // local_time == before_active_boundary_time. + animation->setPlaybackRate(-1); + GetDocument().getElementById("s")->setScrollTop(0); + Compositor().BeginFrame(0.016, /* raster */ true); + Compositor().BeginFrame(); + + cc_animation = animation->GetCompositorAnimation()->CcAnimation(); + keyframe_model_main = + cc_animation->GetKeyframeModel(cc::TargetProperty::TRANSFORM); + keyframe_effect = + impl_host->GetElementAnimationsForElementIdForTesting(element_id) + ->FirstKeyframeEffectForTesting(); + keyframe_model_impl = keyframe_effect->keyframe_models()[0].get(); + + EXPECT_EQ(gfx::KeyframeModel::PAUSED, keyframe_model_impl->run_state()); + EXPECT_TRUE(keyframe_model_main->HasActiveTime(base::TimeTicks())); + EXPECT_TRUE(keyframe_model_impl->HasActiveTime(base::TimeTicks())); +} + // Pre-scroll-unification, ensures that ScrollBegin and ScrollUpdate cause // layout and ScrollEnd does not. Post unification, Blink will not handle these // events but ensure that a unification main-thread-hit-test does cause layout.
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc index c565b31..39a1ede 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.cc
@@ -40,42 +40,6 @@ using HighlightDecoration = NGHighlightOverlay::HighlightDecoration; using HighlightPart = NGHighlightOverlay::HighlightPart; -DocumentMarkerVector ComputeMarkersToPaint(Node* node) { - // TODO(yoichio): Handle first-letter - auto* text_node = DynamicTo<Text>(node); - if (!text_node) - return DocumentMarkerVector(); - - DocumentMarkerController& document_marker_controller = - node->GetDocument().Markers(); - return document_marker_controller.ComputeMarkersToPaint(*text_node); -} - -DocumentMarkerVector MarkersFor(Node* node, DocumentMarker::MarkerType type) { - // TODO(crbug.com/17528) handle ::first-letter - const auto* text_node = DynamicTo<Text>(node); - if (!text_node) - return DocumentMarkerVector(); - - DocumentMarkerController& controller = node->GetDocument().Markers(); - - if (type == DocumentMarker::MarkerType::kCustomHighlight) - return controller.CustomHighlightMarkersNotOverlapping(*text_node); - return controller.MarkersFor(*text_node, DocumentMarker::MarkerTypes{type}); -} - -unsigned GetTextContentOffset(const Text& text, unsigned offset) { - // TODO(yoichio): Sanitize DocumentMarker around text length. - const Position position(text, std::min(offset, text.length())); - const NGOffsetMapping* const offset_mapping = - NGOffsetMapping::GetFor(position); - DCHECK(offset_mapping); - const absl::optional<unsigned>& ng_offset = - offset_mapping->GetTextContentOffset(position); - DCHECK(ng_offset.has_value()); - return ng_offset.value(); -} - // ClampOffset modifies |offset| fixed in a range of |text_fragment| start/end // offsets. // |offset| points not each character but each span between character. @@ -299,18 +263,6 @@ return false; } -PseudoId PseudoFor(DocumentMarker::MarkerType type) { - switch (type) { - case DocumentMarker::kSpelling: - return kPseudoIdSpellingError; - case DocumentMarker::kGrammar: - return kPseudoIdGrammarError; - default: - NOTREACHED(); - return {}; - } -} - HighlightLayerType LayerFor(DocumentMarker::MarkerType type) { switch (type) { case DocumentMarker::kSpelling: @@ -323,30 +275,6 @@ } } -TextDecorationLine LineFor(DocumentMarker::MarkerType type) { - switch (type) { - case DocumentMarker::kSpelling: - return TextDecorationLine::kSpellingError; - case DocumentMarker::kGrammar: - return TextDecorationLine::kGrammarError; - default: - NOTREACHED(); - return {}; - } -} - -Color ColorFor(DocumentMarker::MarkerType type) { - switch (type) { - case DocumentMarker::kSpelling: - return LayoutTheme::GetTheme().PlatformSpellingMarkerUnderlineColor(); - case DocumentMarker::kGrammar: - return LayoutTheme::GetTheme().PlatformGrammarMarkerUnderlineColor(); - default: - NOTREACHED(); - return {}; - } -} - } // namespace NGHighlightPainter::SelectionPaintState::SelectionPaintState( @@ -524,12 +452,20 @@ // not derive its content from the Text node (e.g. ellipsis, soft hyphens). // TODO(crbug.com/17528) handle ::first-letter if (!fragment_item_.IsGeneratedText()) { - markers_ = ComputeMarkersToPaint(node_); - if (RuntimeEnabledFeatures::HighlightOverlayPaintingEnabled()) { - target_ = MarkersFor(node_, DocumentMarker::kTextFragment); - spelling_ = MarkersFor(node_, DocumentMarker::kSpelling); - grammar_ = MarkersFor(node_, DocumentMarker::kGrammar); - custom_ = MarkersFor(node_, DocumentMarker::kCustomHighlight); + const auto* text_node = DynamicTo<Text>(node_); + if (text_node) { + DocumentMarkerController& controller = node_->GetDocument().Markers(); + markers_ = controller.ComputeMarkersToPaint(*text_node); + if (text_node && + RuntimeEnabledFeatures::HighlightOverlayPaintingEnabled()) { + target_ = controller.MarkersFor( + *text_node, DocumentMarker::MarkerTypes::TextFragment()); + spelling_ = controller.MarkersFor( + *text_node, DocumentMarker::MarkerTypes::Spelling()); + grammar_ = controller.MarkersFor( + *text_node, DocumentMarker::MarkerTypes::Grammar()); + custom_ = controller.CustomHighlightMarkersNotOverlapping(*text_node); + } } } @@ -1064,6 +1000,56 @@ } } +unsigned NGHighlightPainter::GetTextContentOffset(const Text& text, + unsigned offset) { + // TODO(yoichio): Sanitize DocumentMarker around text length. + const Position position(text, std::min(offset, text.length())); + const NGOffsetMapping* const offset_mapping = + NGOffsetMapping::GetFor(position); + DCHECK(offset_mapping); + const absl::optional<unsigned>& ng_offset = + offset_mapping->GetTextContentOffset(position); + DCHECK(ng_offset.has_value()); + return ng_offset.value(); +} + +PseudoId NGHighlightPainter::PseudoFor(DocumentMarker::MarkerType type) { + switch (type) { + case DocumentMarker::kSpelling: + return kPseudoIdSpellingError; + case DocumentMarker::kGrammar: + return kPseudoIdGrammarError; + default: + NOTREACHED(); + return {}; + } +} + +TextDecorationLine NGHighlightPainter::LineFor( + DocumentMarker::MarkerType type) { + switch (type) { + case DocumentMarker::kSpelling: + return TextDecorationLine::kSpellingError; + case DocumentMarker::kGrammar: + return TextDecorationLine::kGrammarError; + default: + NOTREACHED(); + return {}; + } +} + +Color NGHighlightPainter::ColorFor(DocumentMarker::MarkerType type) { + switch (type) { + case DocumentMarker::kSpelling: + return LayoutTheme::GetTheme().PlatformSpellingMarkerUnderlineColor(); + case DocumentMarker::kGrammar: + return LayoutTheme::GetTheme().PlatformGrammarMarkerUnderlineColor(); + default: + NOTREACHED(); + return {}; + } +} + PhysicalRect NGHighlightPainter::RectInWritingModeSpace( const NGHighlightOverlay::HighlightRange& range) { const StringView text = cursor_.CurrentText();
diff --git a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h index 03c596f..24124c6 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h +++ b/third_party/blink/renderer/core/paint/ng/ng_highlight_painter.h
@@ -196,6 +196,14 @@ bool paint_marker_backgrounds, absl::optional<AffineTransform> rotation); + // Return the text content offset for a particular fragment offset. + static unsigned GetTextContentOffset(const Text& text, unsigned offset); + + // Query various style pieces for the given marker type + static PseudoId PseudoFor(DocumentMarker::MarkerType type); + static TextDecorationLine LineFor(DocumentMarker::MarkerType type); + static Color ColorFor(DocumentMarker::MarkerType type); + SelectionPaintState* Selection() { return selection_; } private:
diff --git a/third_party/blink/renderer/core/style/build.gni b/third_party/blink/renderer/core/style/build.gni index a6618fb7..58c8d7c 100644 --- a/third_party/blink/renderer/core/style/build.gni +++ b/third_party/blink/renderer/core/style/build.gni
@@ -22,6 +22,7 @@ "computed_style_constants.h", "content_data.cc", "content_data.h", + "coord_box_offset_path_operation.h", "counter_directives.cc", "counter_directives.h", "cursor_data.h",
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc index edd5532..4cde86d 100644 --- a/third_party/blink/renderer/core/style/computed_style.cc +++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -63,6 +63,7 @@ #include "third_party/blink/renderer/core/style/computed_style_constants.h" #include "third_party/blink/renderer/core/style/computed_style_initial_values.h" #include "third_party/blink/renderer/core/style/content_data.h" +#include "third_party/blink/renderer/core/style/coord_box_offset_path_operation.h" #include "third_party/blink/renderer/core/style/cursor_data.h" #include "third_party/blink/renderer/core/style/reference_offset_path_operation.h" #include "third_party/blink/renderer/core/style/shadow_list.h" @@ -76,6 +77,7 @@ #include "third_party/blink/renderer/core/style/style_ray.h" #include "third_party/blink/renderer/core/svg/svg_element.h" #include "third_party/blink/renderer/core/svg/svg_geometry_element.h" +#include "third_party/blink/renderer/core/svg/svg_length_context.h" #include "third_party/blink/renderer/platform/fonts/font.h" #include "third_party/blink/renderer/platform/fonts/font_selector.h" #include "third_party/blink/renderer/platform/geometry/length_functions.h" @@ -1442,11 +1444,26 @@ namespace { gfx::SizeF GetReferenceBoxSize(const LayoutBox* box, - const gfx::RectF& bounding_box) { + const gfx::RectF& bounding_box, + CoordBox coord_box) { if (box) { + // In SVG contexts, all values behave as view-box. + if (box->IsSVG()) { + return SVGLengthContext(To<SVGElement>(box->GetNode())).ResolveViewport(); + } if (const LayoutBlock* containing_block = box->ContainingBlock()) { - // TODO(sakhapov): return based on <coord-box>. - return gfx::SizeF(containing_block->BorderBoxRect().Size()); + // https://drafts.csswg.org/css-box-4/#typedef-coord-box + switch (coord_box) { + case CoordBox::kFillBox: + case CoordBox::kContentBox: + return gfx::SizeF(containing_block->PhysicalContentBoxSize()); + case CoordBox::kPaddingBox: + return gfx::SizeF(containing_block->PhysicalPaddingBoxRect().size); + case CoordBox::kViewBox: + case CoordBox::kStrokeBox: + case CoordBox::kBorderBox: + return gfx::SizeF(containing_block->BorderBoxRect().Size()); + } } } return bounding_box.size(); @@ -1478,17 +1495,15 @@ PointAndTangent ComputedStyle::CalculatePointAndTangentOnBasicShape( const BasicShape& shape, const LayoutBox* box, - const gfx::RectF& bounding_box) const { + const gfx::PointF starting_point, + const gfx::SizeF reference_box_size) const { Path path; - const gfx::SizeF reference_box_size = GetReferenceBoxSize(box, bounding_box); if (const auto* circle_or_ellipse = DynamicTo<BasicShapeWithCenterAndRadii>(shape); circle_or_ellipse && !circle_or_ellipse->HasExplicitCenter()) { // If circle() or ellipse() is used, and an explicit center position is not // given, they default to using the offset starting position, rather than // their standard default. - const gfx::PointF starting_point = - GetStartingPointOfThePath(box, OffsetPosition(), reference_box_size); circle_or_ellipse->GetPathFromCenter( path, starting_point, gfx::RectF(reference_box_size), EffectiveZoom()); } else { @@ -1509,10 +1524,8 @@ PointAndTangent ComputedStyle::CalculatePointAndTangentOnRay( const StyleRay& ray, const LayoutBox* box, - const gfx::RectF& bounding_box) const { - const gfx::SizeF reference_box_size = GetReferenceBoxSize(box, bounding_box); - const gfx::PointF starting_point = - GetStartingPointOfThePath(box, OffsetPosition(), reference_box_size); + const gfx::PointF starting_point, + const gfx::SizeF reference_box_size) const { float ray_length = ray.CalculateRayPathLength(starting_point, reference_box_size); if (ray.Contain() && box) { @@ -1565,6 +1578,7 @@ const LengthPoint& anchor = OffsetAnchor(); const StyleOffsetRotation& rotate = OffsetRotate(); + CoordBox coord_box = offset_path->GetCoordBox(); float origin_shift_x = 0; float origin_shift_y = 0; @@ -1581,9 +1595,13 @@ } PointAndTangent path_position; - if (const auto* shape = DynamicTo<ShapeOffsetPathOperation>(offset_path)) { - const BasicShape& basic_shape = - To<ShapeOffsetPathOperation>(offset_path)->GetBasicShape(); + if (const auto* shape_operation = + DynamicTo<ShapeOffsetPathOperation>(offset_path)) { + const BasicShape& basic_shape = shape_operation->GetBasicShape(); + const gfx::SizeF reference_box_size = + GetReferenceBoxSize(box, bounding_box, coord_box); + const gfx::PointF starting_point = + GetStartingPointOfThePath(box, OffsetPosition(), reference_box_size); switch (basic_shape.GetType()) { case BasicShape::kStylePathType: { const StylePath& path = To<StylePath>(basic_shape); @@ -1592,7 +1610,8 @@ } case BasicShape::kStyleRayType: { const StyleRay& ray = To<StyleRay>(basic_shape); - path_position = CalculatePointAndTangentOnRay(ray, box, bounding_box); + path_position = CalculatePointAndTangentOnRay(ray, box, starting_point, + reference_box_size); break; } case BasicShape::kBasicShapeCircleType: @@ -1601,18 +1620,39 @@ case BasicShape::kBasicShapeXYWHType: case BasicShape::kBasicShapeRectType: case BasicShape::kBasicShapePolygonType: { - path_position = CalculatePointAndTangentOnBasicShape(basic_shape, box, - bounding_box); + path_position = CalculatePointAndTangentOnBasicShape( + basic_shape, box, starting_point, reference_box_size); break; } } + } else if (const auto* coord_box_operation = + DynamicTo<CoordBoxOffsetPathOperation>(offset_path)) { + if (box && box->ContainingBlock()) { + const gfx::SizeF reference_box_size = + GetReferenceBoxSize(box, bounding_box, coord_box); + const gfx::PointF starting_point = + GetStartingPointOfThePath(box, OffsetPosition(), reference_box_size); + scoped_refptr<BasicShapeInset> inset = BasicShapeInset::Create(); + inset->SetTop(Length::Fixed(0)); + inset->SetBottom(Length::Fixed(0)); + inset->SetLeft(Length::Fixed(0)); + inset->SetRight(Length::Fixed(0)); + const ComputedStyle& style = box->ContainingBlock()->StyleRef(); + inset->SetTopLeftRadius(style.BorderTopLeftRadius()); + inset->SetTopRightRadius(style.BorderTopRightRadius()); + inset->SetBottomRightRadius(style.BorderBottomRightRadius()); + inset->SetBottomLeftRadius(style.BorderBottomLeftRadius()); + path_position = CalculatePointAndTangentOnBasicShape( + *inset, box, starting_point, reference_box_size); + } } else { - const auto* url = DynamicTo<ReferenceOffsetPathOperation>(offset_path); - if (!url->Resource()) { + const auto* url_operation = + DynamicTo<ReferenceOffsetPathOperation>(offset_path); + if (!url_operation->Resource()) { return; } const auto* target = - DynamicTo<SVGGeometryElement>(url->Resource()->Target()); + DynamicTo<SVGGeometryElement>(url_operation->Resource()->Target()); Path path; if (!target || !target->GetComputedStyle()) { // Failure to find a shape should be equivalent to a "m0,0" path.
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h index 650dee3..c3bff2b 100644 --- a/third_party/blink/renderer/core/style/computed_style.h +++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -2649,11 +2649,13 @@ PointAndTangent CalculatePointAndTangentOnBasicShape( const BasicShape& shape, const LayoutBox* box, - const gfx::RectF& bounding_box) const; + const gfx::PointF starting_point, + const gfx::SizeF reference_box_size) const; PointAndTangent CalculatePointAndTangentOnRay( const StyleRay& ray, const LayoutBox* box, - const gfx::RectF& bounding_box) const; + const gfx::PointF starting_point, + const gfx::SizeF reference_box_size) const; PointAndTangent CalculatePointAndTangentOnPath(const Path& path) const; bool ScrollAnchorDisablingPropertyChanged(const ComputedStyle& other,
diff --git a/third_party/blink/renderer/core/style/computed_style_constants.h b/third_party/blink/renderer/core/style/computed_style_constants.h index 42aea77c..a82bdcb 100644 --- a/third_party/blink/renderer/core/style/computed_style_constants.h +++ b/third_party/blink/renderer/core/style/computed_style_constants.h
@@ -416,6 +416,15 @@ }; enum class TimelineScroller { kNearest, kRoot, kSelf }; +enum class CoordBox { + kContentBox, + kPaddingBox, + kBorderBox, + kFillBox, + kStrokeBox, + kViewBox +}; + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COMPUTED_STYLE_CONSTANTS_H_
diff --git a/third_party/blink/renderer/core/style/coord_box_offset_path_operation.h b/third_party/blink/renderer/core/style/coord_box_offset_path_operation.h new file mode 100644 index 0000000..aa6e517c --- /dev/null +++ b/third_party/blink/renderer/core/style/coord_box_offset_path_operation.h
@@ -0,0 +1,38 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COORD_BOX_OFFSET_PATH_OPERATION_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_COORD_BOX_OFFSET_PATH_OPERATION_H_ + +#include "third_party/blink/renderer/core/style/offset_path_operation.h" + +namespace blink { + +class CoordBoxOffsetPathOperation final : public OffsetPathOperation { + public: + static scoped_refptr<CoordBoxOffsetPathOperation> Create(CoordBox coord_box) { + return base::AdoptRef(new CoordBoxOffsetPathOperation(coord_box)); + } + + bool IsEqualAssumingSameType(const OffsetPathOperation& o) const override { + return true; + } + + OperationType GetType() const override { return kCoordBox; } + + private: + explicit CoordBoxOffsetPathOperation(CoordBox coord_box) + : OffsetPathOperation(coord_box) {} +}; + +template <> +struct DowncastTraits<CoordBoxOffsetPathOperation> { + static bool AllowFrom(const OffsetPathOperation& op) { + return op.GetType() == OffsetPathOperation::kCoordBox; + } +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_COORD_BOX_SHAPE_OFFSET_PATH_OPERATION_H_
diff --git a/third_party/blink/renderer/core/style/offset_path_operation.h b/third_party/blink/renderer/core/style/offset_path_operation.h index f702cf15..6cd4826 100644 --- a/third_party/blink/renderer/core/style/offset_path_operation.h +++ b/third_party/blink/renderer/core/style/offset_path_operation.h
@@ -5,6 +5,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_OFFSET_PATH_OPERATION_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_OFFSET_PATH_OPERATION_H_ +#include "third_party/blink/renderer/core/style/computed_style_constants.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" namespace blink { @@ -13,14 +14,15 @@ USING_FAST_MALLOC(OffsetPathOperation); public: - enum OperationType { kReference, kShape }; + enum OperationType { kReference, kShape, kCoordBox }; OffsetPathOperation(const OffsetPathOperation&) = delete; OffsetPathOperation& operator=(const OffsetPathOperation&) = delete; virtual ~OffsetPathOperation() = default; bool operator==(const OffsetPathOperation& o) const { - return IsSameType(o) && IsEqualAssumingSameType(o); + return IsSameType(o) && IsEqualAssumingSameType(o) && + coord_box_ == o.coord_box_; } bool operator!=(const OffsetPathOperation& o) const { return !(*this == o); } @@ -29,9 +31,13 @@ return o.GetType() == GetType(); } + CoordBox GetCoordBox() const { return coord_box_; } + protected: - OffsetPathOperation() = default; + explicit OffsetPathOperation(CoordBox coord_box) : coord_box_(coord_box) {} virtual bool IsEqualAssumingSameType(const OffsetPathOperation& o) const = 0; + + CoordBox coord_box_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/style/reference_offset_path_operation.h b/third_party/blink/renderer/core/style/reference_offset_path_operation.h index a7c5f51..7d31fe2d 100644 --- a/third_party/blink/renderer/core/style/reference_offset_path_operation.h +++ b/third_party/blink/renderer/core/style/reference_offset_path_operation.h
@@ -16,10 +16,10 @@ class ReferenceOffsetPathOperation final : public OffsetPathOperation { public: - static scoped_refptr<ReferenceOffsetPathOperation> Create( - const AtomicString& url, - SVGResource* resource) { - return base::AdoptRef(new ReferenceOffsetPathOperation(url, resource)); + static scoped_refptr<ReferenceOffsetPathOperation> + Create(const AtomicString& url, SVGResource* resource, CoordBox coord_box) { + return base::AdoptRef( + new ReferenceOffsetPathOperation(url, resource, coord_box)); } bool IsEqualAssumingSameType(const OffsetPathOperation& o) const override { @@ -44,8 +44,10 @@ const AtomicString& Url() const { return url_; } private: - ReferenceOffsetPathOperation(const String& url, SVGResource* resource) - : resource_(resource), url_(url) {} + ReferenceOffsetPathOperation(const String& url, + SVGResource* resource, + CoordBox coord_box) + : OffsetPathOperation(coord_box), resource_(resource), url_(url) {} Persistent<SVGResource> resource_; AtomicString url_;
diff --git a/third_party/blink/renderer/core/style/shape_offset_path_operation.h b/third_party/blink/renderer/core/style/shape_offset_path_operation.h index f64f041..c21f8bb 100644 --- a/third_party/blink/renderer/core/style/shape_offset_path_operation.h +++ b/third_party/blink/renderer/core/style/shape_offset_path_operation.h
@@ -14,8 +14,10 @@ class ShapeOffsetPathOperation final : public OffsetPathOperation { public: static scoped_refptr<ShapeOffsetPathOperation> Create( - scoped_refptr<BasicShape> shape) { - return base::AdoptRef(new ShapeOffsetPathOperation(std::move(shape))); + scoped_refptr<BasicShape> shape, + CoordBox coord_box) { + return base::AdoptRef( + new ShapeOffsetPathOperation(std::move(shape), coord_box)); } bool IsEqualAssumingSameType(const OffsetPathOperation& o) const override { @@ -28,8 +30,8 @@ const BasicShape& GetBasicShape() const { return *shape_; } private: - explicit ShapeOffsetPathOperation(scoped_refptr<BasicShape> shape) - : shape_(std::move(shape)) { + ShapeOffsetPathOperation(scoped_refptr<BasicShape> shape, CoordBox coord_box) + : OffsetPathOperation(coord_box), shape_(std::move(shape)) { DCHECK(shape_); }
diff --git a/third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.cc b/third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.cc index 509029d..236e2fb 100644 --- a/third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.cc +++ b/third_party/blink/renderer/modules/mediastream/webaudio_media_stream_audio_sink.cc
@@ -104,6 +104,9 @@ if (fifo_->frames() + audio_bus.frames() <= fifo_->max_frames()) { fifo_->Push(&audio_bus); + TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("mediastream"), + "WebAudioMediaStreamAudioSink fifo space", this, + fifo_->max_frames() - fifo_->frames()); } else { // This can happen if the data in FIFO is too slowly consumed or // WebAudio stops consuming data. @@ -163,6 +166,9 @@ lock_.AssertAcquired(); if (fifo_->frames() >= audio_bus->frames()) { fifo_->Consume(audio_bus, 0, audio_bus->frames()); + TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("mediastream"), + "WebAudioMediaStreamAudioSink fifo space", this, + fifo_->max_frames() - fifo_->frames()); } else { audio_bus->Zero(); TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("mediastream"),
diff --git a/third_party/blink/renderer/platform/bindings/binding_security_for_platform.cc b/third_party/blink/renderer/platform/bindings/binding_security_for_platform.cc index 0c4b1a43..2a233dd 100644 --- a/third_party/blink/renderer/platform/bindings/binding_security_for_platform.cc +++ b/third_party/blink/renderer/platform/bindings/binding_security_for_platform.cc
@@ -7,10 +7,6 @@ namespace blink { BindingSecurityForPlatform:: - ShouldAllowAccessToV8ContextWithExceptionStateFunction - BindingSecurityForPlatform:: - should_allow_access_to_v8context_with_exception_state_ = nullptr; -BindingSecurityForPlatform:: ShouldAllowAccessToV8ContextWithErrorReportOptionFunction BindingSecurityForPlatform:: should_allow_access_to_v8context_with_error_report_option_ = @@ -25,15 +21,6 @@ bool BindingSecurityForPlatform::ShouldAllowAccessToV8Context( v8::Local<v8::Context> accessing_context, v8::MaybeLocal<v8::Context> target_context, - ExceptionState& exception_state) { - return (*should_allow_access_to_v8context_with_exception_state_)( - accessing_context, target_context, exception_state); -} - -// static -bool BindingSecurityForPlatform::ShouldAllowAccessToV8Context( - v8::Local<v8::Context> accessing_context, - v8::MaybeLocal<v8::Context> target_context, ErrorReportOption reporting_option) { return (*should_allow_access_to_v8context_with_error_report_option_)( accessing_context, target_context, reporting_option); @@ -61,15 +48,6 @@ // static void BindingSecurityForPlatform:: - SetShouldAllowAccessToV8ContextWithExceptionState( - ShouldAllowAccessToV8ContextWithExceptionStateFunction func) { - DCHECK(!should_allow_access_to_v8context_with_exception_state_); - DCHECK(func); - should_allow_access_to_v8context_with_exception_state_ = func; -} - -// static -void BindingSecurityForPlatform:: SetShouldAllowAccessToV8ContextWithErrorReportOption( ShouldAllowAccessToV8ContextWithErrorReportOptionFunction func) { DCHECK(!should_allow_access_to_v8context_with_error_report_option_);
diff --git a/third_party/blink/renderer/platform/bindings/binding_security_for_platform.h b/third_party/blink/renderer/platform/bindings/binding_security_for_platform.h index b2bfb90..eec96d3 100644 --- a/third_party/blink/renderer/platform/bindings/binding_security_for_platform.h +++ b/third_party/blink/renderer/platform/bindings/binding_security_for_platform.h
@@ -11,7 +11,6 @@ namespace blink { -class ExceptionState; struct WrapperTypeInfo; // BindingSecurityForPlatform provides utility functions that determine access @@ -28,14 +27,9 @@ kReport, }; - // These overloads should be used only when checking a general access from - // one context to another context. For access to a receiver object or - // returned object, you should use BindingSecurity::ShouldAllowAccessTo - // family. - static bool ShouldAllowAccessToV8Context( - v8::Local<v8::Context> accessing_context, - v8::MaybeLocal<v8::Context> target_context, - ExceptionState&); + // This should be used only when checking a general access from one context to + // another context. For access to a receiver object or returned object, you + // should use BindingSecurity::ShouldAllowAccessTo family. static bool ShouldAllowAccessToV8Context( v8::Local<v8::Context> accessing_context, v8::MaybeLocal<v8::Context> target_context, @@ -57,10 +51,6 @@ v8::Local<v8::Value> cross_context_exception); private: - using ShouldAllowAccessToV8ContextWithExceptionStateFunction = - bool (*)(v8::Local<v8::Context> accessing_context, - v8::MaybeLocal<v8::Context> target_context, - ExceptionState&); using ShouldAllowAccessToV8ContextWithErrorReportOptionFunction = bool (*)(v8::Local<v8::Context> accessing_context, v8::MaybeLocal<v8::Context> target_context, @@ -75,8 +65,6 @@ const WrapperTypeInfo* wrapper_type_info, v8::Local<v8::Value> cross_context_exception); - static void SetShouldAllowAccessToV8ContextWithExceptionState( - ShouldAllowAccessToV8ContextWithExceptionStateFunction); static void SetShouldAllowAccessToV8ContextWithErrorReportOption( ShouldAllowAccessToV8ContextWithErrorReportOptionFunction); static void SetShouldAllowWrapperCreationOrThrowException( @@ -84,8 +72,6 @@ static void SetRethrowWrapperCreationException( RethrowWrapperCreationExceptionFunction); - static ShouldAllowAccessToV8ContextWithExceptionStateFunction - should_allow_access_to_v8context_with_exception_state_; static ShouldAllowAccessToV8ContextWithErrorReportOptionFunction should_allow_access_to_v8context_with_error_report_option_; static ShouldAllowWrapperCreationOrThrowExceptionFunction
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5 index 980338f..cf80aa8 100644 --- a/third_party/blink/renderer/platform/runtime_enabled_features.json5 +++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -976,6 +976,11 @@ base_feature: "none", }, { + name: "CSSOffsetPathCoordBox", + status: "experimental", + base_feature: "none", + }, + { name: "CSSOffsetPathRay", status: "experimental", base_feature: "none", @@ -2075,11 +2080,6 @@ base_feature: "none", }, { - name: "LazyImageVisibleLoadTimeMetrics", - base_feature: "none", - public: true, - }, - { name: "LazyInitializeMediaControls", base_feature: "none", public: true,
diff --git a/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py b/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py index 16c1eef..e3422d0 100644 --- a/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py +++ b/third_party/blink/tools/blinkpy/web_tests/controllers/manager.py
@@ -599,15 +599,6 @@ failing_results_path, callback='ADD_RESULTS') - # Write out the JSON files suitable for other tools to process. - # As the output can be quite large (as there are 60k+ tests) we also - # support only outputting the failing results. - if self._options.json_failing_test_results: - # FIXME(tansell): Make sure this includes an *unexpected* results - # (IE Passing when expected to be failing.) - json_results_generator.write_json( - self._filesystem, summarized_failing_results, - self._options.json_failing_test_results) if self._options.json_test_results: json_results_generator.write_json(self._filesystem, summarized_full_results,
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py b/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py index 6e41ddb..1a3d4be 100644 --- a/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py +++ b/third_party/blink/tools/blinkpy/web_tests/run_web_tests.py
@@ -243,12 +243,6 @@ optparse.make_option( '--write-run-histories-to', help='Path to write the JSON test run histories.'), - # FIXME(tansell): Remove this option if nobody is found who needs it. - optparse.make_option( - '--json-failing-test-results', - help= - 'Path to write the JSON test results for only *failing* tests.' - ), optparse.make_option( '--no-show-results', dest='show_results',
diff --git a/third_party/blink/tools/blinkpy/web_tests/run_web_tests_unittest.py b/third_party/blink/tools/blinkpy/web_tests/run_web_tests_unittest.py index 0ad0bc8..dcd939d 100644 --- a/third_party/blink/tools/blinkpy/web_tests/run_web_tests_unittest.py +++ b/third_party/blink/tools/blinkpy/web_tests/run_web_tests_unittest.py
@@ -174,10 +174,6 @@ def test_basic(self): options, args = parse_args( - extra_args=[ - '--json-failing-test-results', - '/tmp/json_failing_test_results.json' - ], tests_included=True) logging_stream = StringIO() host = MockHost() @@ -2334,20 +2330,6 @@ host=host) self._check_json_test_results(host, details) - def test_json_failing_test_results(self): - host = MockHost() - details, _, _ = logging_run( - ['--json-failing-test-results', '/tmp/json_failing_results.json'], - host=host) - self.assertEqual(details.exit_code, 0) - self.assertTrue( - host.filesystem.exists('/tmp/json_failing_results.json')) - json_failing_test_results = host.filesystem.read_text_file( - '/tmp/json_failing_results.json') - self.assertEqual( - json.loads(json_failing_test_results), - details.summarized_failing_results) - def test_no_default_expectations(self): self.assertFalse( passing_run([
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 95b912f..4753eb8 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2920,6 +2920,10 @@ crbug.com/626703 [ Win ] virtual/partitioned-cookies/http/tests/inspector-protocol/network/disabled-cache-navigation.js [ Failure ] # ====== New tests from wpt-importer added here ====== +crbug.com/626703 external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001-ref.html [ Failure ] +crbug.com/626703 external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001.html [ Failure ] +crbug.com/626703 external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002.html [ Failure ] +crbug.com/626703 external/wpt/preload/modulepreload-as.html [ Failure Timeout ] crbug.com/626703 [ Mac13 ] virtual/fenced-frame-mparch/external/wpt/fenced-frame/background-sync.https.html [ Timeout ] crbug.com/626703 [ Mac13 ] virtual/pending-beacon/external/wpt/pending-beacon/pending_beacon-sendonhidden.tentative.https.window.html [ Timeout ] crbug.com/626703 [ Mac13 ] virtual/prefetch/external/wpt/speculation-rules/prefetch/out-of-document-rule-set.https.html?include=RelativeUrlForCandidate [ Timeout ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index e726727b..352a82f 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -3823,7 +3823,14 @@ {} ] ] - } + }, + "infinite-duration-crash.html": [ + "dba53d66b7ac7bddcdc444dfd470cd37345f6a4d", + [ + null, + {} + ] + ] }, "css-typed-om": { "perspective-typed-arithmetic-crash.html": [ @@ -5497,7 +5504,7 @@ ] ], "popover-hide-crash.html": [ - "3e0c694976cd3798ffd319129c6b4494f5ee4267", + "db491e961e13fba979472748f84378ae6b0391bf", [ null, {} @@ -18256,6 +18263,32 @@ {} ] ], + "transform-002-print.html": [ + "3ab37bf5bd867dac5518a64569af2dcefc797e13", + [ + null, + [ + [ + "/css/printing/transform-002-print-ref.html", + "==" + ] + ], + {} + ] + ], + "transform-003-print.html": [ + "c8effbb8f35c80bed2fa64f8853e62bd12589fbb", + [ + null, + [ + [ + "/css/printing/transform-003-print-ref.html", + "==" + ] + ], + {} + ] + ], "transition-in-media-print.tentative.html": [ "54bac1f48124a27689dc2f614003d462fe2dd477", [ @@ -84615,6 +84648,19 @@ {} ] ], + "order-of-images.htm": [ + "9f165fb9b5aacf8f71043fd45ebbafecfacb619e", + [ + null, + [ + [ + "/css/css-backgrounds/reference/order-of-images-ref.html", + "==" + ] + ], + {} + ] + ], "scroll-positioned-multiple-background-images.html": [ "a9ca550ce3dea2626de05bf31437a0a19aeedbce", [ @@ -85299,6 +85345,32 @@ {} ] ], + "abspos-in-opacity-002.html": [ + "e6d61eacd1af3e34111013a44afca09d92fe1418", + [ + null, + [ + [ + "/css/reference/ref-filled-greenish-100px-square.html", + "==" + ] + ], + {} + ] + ], + "abspos-in-opacity-003.html": [ + "13a1b31add5cb2c755dc6d36ee8e74a27de8a001", + [ + null, + [ + [ + "/css/reference/ref-filled-greenish-100px-square.html", + "==" + ] + ], + {} + ] + ], "abspos-inside-relpos-inside-monolithic.html": [ "879097f3fc2a7c933a1c2bea460beed1f6bc5e2b", [ @@ -85546,6 +85618,19 @@ {} ] ], + "block-max-height-004.html": [ + "4ceb23a80bf0beb9032ee7567e034e27360157b1", + [ + null, + [ + [ + "/css/css-break/block-max-height-004-ref.html", + "==" + ] + ], + {} + ] + ], "block-min-height-001.html": [ "47ceff763195d254b22dd8739e1a46b0168df50f", [ @@ -95203,6 +95288,71 @@ {} ] ], + "transform-012.html": [ + "4156aff6298fffe862fe109f4693124cda6ec5db", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "transform-013.html": [ + "31cce10b52f38c4960d1d265e07fd1b363d20ae0", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "transform-014.html": [ + "16fc15d760d4afa95d7488d22e334f1cd809ef45", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "transform-015.html": [ + "676c291b6ef89e6d25e09447f624bc7889b34ac4", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "transform-016.html": [ + "5a10d860c3feaa787db420b0fec4f5bfaaa6fa96", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "truncated-margin-at-fragmentainer-end-001.html": [ "cfb8590f9026194020afaea854f1d4d9fc570b49", [ @@ -122084,6 +122234,19 @@ {} ] ], + "percentage-padding-003.html": [ + "ee84f1570efb877843384b923e8a28ee58537f70", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "percentage-size-subitems-001.html": [ "70f3953052a3a770c6cd15ee169607a00fc452b0", [ @@ -135670,6 +135833,32 @@ {} ] ], + "subgrid-no-items-on-edges-001.html": [ + "e2fe1a366e5cb013842f5730fda4a94cab2ae92b", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], + "subgrid-no-items-on-edges-002.html": [ + "a2c73b188437434cfd4cb6943f5781413c6ff3a0", + [ + null, + [ + [ + "/css/reference/ref-filled-green-100px-square.xht", + "==" + ] + ], + {} + ] + ], "subgrid-stretch.html": [ "321e12d2a3ba6d1bab3623c385153b2375c1b441", [ @@ -135752,6 +135941,19 @@ }, "css-highlight-api": { "painting": { + "css-highlight-painting-underline-offset-001.html": [ + "14b238ce1700fc9e1fe1ea3745b0a818d5c615c1", + [ + null, + [ + [ + "/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001-ref.html", + "==" + ] + ], + {} + ] + ], "custom-highlight-painting-001.html": [ "82b61ec6de07c4d45796785f3e7b559e64a6deab", [ @@ -135792,7 +135994,7 @@ ] ], "custom-highlight-painting-004-2.html": [ - "044cdb5d649e3b173511cd82705ffef9eb5044a2", + "0a612d66d1e13449590cfc1144b34e7ce17b6f6e", [ null, [ @@ -135801,11 +136003,27 @@ "==" ] ], - {} + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 88 + ], + [ + 0, + 1 + ] + ] + ] + ] + } ] ], "custom-highlight-painting-004.html": [ - "b67c30b70972fb22ba20b902b21a118ca58bbb1f", + "320617f8d1f8918b4db8515dd34fda6d33d32260", [ null, [ @@ -135814,7 +136032,23 @@ "==" ] ], - {} + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 255 + ], + [ + 0, + 110 + ] + ] + ] + ] + } ] ], "custom-highlight-painting-005.html": [ @@ -136338,7 +136572,7 @@ ] ], "custom-highlight-painting-text-decoration-001.html": [ - "df6e5dd32cc9260743ab096acf3bb13cf8f9abfb", + "72201e6e782362df53765264188b0f7e96fdd927", [ null, [ @@ -136347,7 +136581,23 @@ "==" ] ], - {} + { + "fuzzy": [ + [ + null, + [ + [ + 0, + 255 + ], + [ + 0, + 27 + ] + ] + ] + ] + } ] ], "custom-highlight-painting-text-decoration-dynamic-001.html": [ @@ -142160,6 +142410,32 @@ ] }, "text-box-trim": { + "text-box-trim-half-leading-block-box-001-ref.html": [ + "4fc498a27bded7e4e870a055128f003383792bee", + [ + null, + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-001-ref.html", + "==" + ] + ], + {} + ] + ], + "text-box-trim-half-leading-block-box-001.html": [ + "9ad9ffc3fc68184745549c4759ea9534fc174527", + [ + null, + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-001-ref.html", + "==" + ] + ], + {} + ] + ], "text-box-trim-half-leading-inline-box-001.html": [ "4316301bd1bff7e58862700c6b7511914d14d21f", [ @@ -142172,6 +142448,19 @@ ], {} ] + ], + "text-box-trim-half-leading-inline-box-002.html": [ + "3e679f6ce89bfab53583b6a1f052b6635ab998b8", + [ + null, + [ + [ + "/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-001-ref.html", + "==" + ] + ], + {} + ] ] } }, @@ -258009,7 +258298,7 @@ ] ], "image-compositing-change.html": [ - "592720a82a266c72a507a8651a0dd85ab428663a", + "658c2ad39ea343e40de9aaf64dcb7c75b346ae6b", [ null, [ @@ -258018,7 +258307,23 @@ "==" ] ], - {} + { + "fuzzy": [ + [ + null, + [ + [ + 150, + 150 + ], + [ + 296, + 296 + ] + ] + ] + ] + } ] ], "image-compositing-large-scale-change.html": [ @@ -271610,11 +271915,11 @@ "support": { ".cache": { "gitignore2.json": [ - "ae71786e96f4f32e9c08bc2eee776cc4820a2be9", + "d86d580327d519e4ac55e7929403843926162de4", [] ], "mtime.json": [ - "b7f7703c77b481009e1fcdf93ad11846059cfe1f", + "39ab88d6b5d2033166587324b31fb2e7105ee5bc", [] ] }, @@ -272279,7 +272584,7 @@ }, "generateKey": { "failures.js": [ - "c39e4d211cbdf466efd59a2cf822b4aa8a50f896", + "e0f0279a69bb885eb30cbe086796c281db0245bb", [] ], "failures_AES-CBC.https.any-expected.txt": [ @@ -272489,19 +272794,19 @@ [] ], "okp_importKey_failures.js": [ - "a5cc08a01e9fc1c23c7c8cced51ba02be60b66d3", + "ebdb73616d658146152ebddb3fbd27eaf8b49c26", [] ], "okp_importKey_failures_Ed448.https.any-expected.txt": [ - "3eeace1215df3783e1d8f3c32f84af73d413dc01", + "713ec4281caa279ea8895c09df0de3c956c555a4", [] ], "okp_importKey_failures_Ed448.https.any.js.ini": [ - "c013a559341111ac497376413f9c308b8db04cea", + "a910d32a91ae69cdc0ea3464abb664505030890f", [] ], "okp_importKey_failures_Ed448.https.any.worker-expected.txt": [ - "3eeace1215df3783e1d8f3c32f84af73d413dc01", + "713ec4281caa279ea8895c09df0de3c956c555a4", [] ], "okp_importKey_failures_X25519.https.any.js.ini": [ @@ -272509,27 +272814,27 @@ [] ], "okp_importKey_failures_X448.https.any-expected.txt": [ - "82c88882d7094f8e29347965376f6b072fc3cc0d", + "be7bbd5c91a5eb12911317d010f0a27a87de2709", [] ], "okp_importKey_failures_X448.https.any.js.ini": [ - "2e5655dbd5a65dde23f9eeb529325a4e167e5e8e", + "580fbf95375dd0a4f0f6687b40c620a7a051e6a0", [] ], "okp_importKey_failures_X448.https.any.worker-expected.txt": [ - "82c88882d7094f8e29347965376f6b072fc3cc0d", + "be7bbd5c91a5eb12911317d010f0a27a87de2709", [] ], "symmetric_importKey.https.any-expected.txt": [ - "c864d227f16c940b274671df92b0c3fa945ab44b", + "ffc5ab04deeee60dbf50967ce6693fb146c12ca5", [] ], "symmetric_importKey.https.any.js.ini": [ - "5758e94cc0648cfc0b8bd3462cf0ecaee0fb9714", + "6064f9ce4295201f322a495a31b269666bcf857a", [] ], "symmetric_importKey.https.any.worker-expected.txt": [ - "c864d227f16c940b274671df92b0c3fa945ab44b", + "ffc5ab04deeee60dbf50967ce6693fb146c12ca5", [] ], "symmetric_importKey.https.worker-expected.txt": [ @@ -279113,7 +279418,7 @@ [] ], "fedcm-mock.js": [ - "cb48bdb27e846f50019741f33826586df377f75a", + "16a72b1d2c3ced916368c50c096376a319ea7a4c", [] ], "fedcm-mojojs-helper.js": [ @@ -280395,6 +280700,10 @@ "3b90043555f70f41e32bb507e60cfbbfeecb4f02", [] ], + "border-applies-to-004.xht.ini": [ + "555871803c8815bba285f2873a55b768e7d02ceb", + [] + ], "border-bottom-001-ref.xht": [ "bab394736d3f9e394d32f2cc189514d0523bc8ef", [] @@ -289155,6 +289464,10 @@ "fe2ac8bdb1994fe6bd36ba85d7c71f49b7d7cf89", [] ], + "order-of-images-ref.html": [ + "a704cd4f93bb012525bdb2639aba7322bbd18ebd", + [] + ], "ref-filled-black-96px-square.xht": [ "7309746e54f73c9d0f978d1986b6df40e950793b", [] @@ -290238,6 +290551,10 @@ "40ecf750be0f316b52eadfd533822ce4d675d07e", [] ], + "block-max-height-004-ref.html": [ + "74a2ed73c17bc57d1541e2821b23aca578e97d4e", + [] + ], "block-min-height-001-ref.html": [ "492a9a19ae2d992f01e79700dff51f2d09397095", [] @@ -294547,8 +294864,16 @@ [] ], "parsing": { + "display-computed-expected.txt": [ + "be7e588e91ff5fb54c30bc5d2604fb025b85066a", + [] + ], + "display-computed.html.ini": [ + "0a161b08949ccc44553b177f7da6fc86b3d5e957", + [] + ], "display-valid-expected.txt": [ - "e62ae15baec2ac7406a9587c663a43d83ec114f9", + "2bcfde845904e116b6a707bf55bbf3a478069430", [] ], "display-valid.html.ini": [ @@ -297202,7 +297527,7 @@ ], "animations": { "font-size-adjust-interpolation-expected.txt": [ - "b09962cfc9987472d98f372fe4aa2c075a8c17fd", + "58fe3c7440937f2f5584afa4b80880c99605ed62", [] ], "font-size-adjust-interpolation.html.ini": [ @@ -298368,7 +298693,7 @@ [] ], "font-size-adjust-computed-expected.txt": [ - "a55a7e8b60cb70bbc30df698b721a4c2285dafe4", + "8e9fe24a64cd8657ce2a08c1915101ce569b3d85", [] ], "font-size-adjust-computed.html.ini": [ @@ -298376,7 +298701,7 @@ [] ], "font-size-adjust-valid-expected.txt": [ - "c54f42c39db6dc98ec663399a17c9ec5e120ea2a", + "0100ee3f8327b83fe373ac6401c971e685d75383", [] ], "font-size-adjust-valid.html.ini": [ @@ -306997,6 +307322,14 @@ [] ], "painting": { + "css-highlight-painting-underline-offset-001-ref.html": [ + "3d01bccf55dd9c20e361551bc924d5c9353c503e", + [] + ], + "css-highlight-painting-underline-offset-001.html.ini": [ + "d896e9be56260e2279d1a49c63df8d3c1b3ae586", + [] + ], "custom-highlight-painting-001-ref.html": [ "b058789f6de04c017dec9a37d8955485dcd6b7e9", [] @@ -309061,6 +309394,14 @@ ] }, "text-box-trim": { + "text-box-trim-half-leading-block-box-001-ref.html.ini": [ + "5d664236c793141cfd7225a284c8d7ce8c707677", + [] + ], + "text-box-trim-half-leading-block-box-001.html.ini": [ + "7881a9ce377ba07ae3260056da8d6d3bbf904841", + [] + ], "text-box-trim-half-leading-inline-box-001-ref.html": [ "4824309291df136db30d79b4a9dddc115f48b117", [] @@ -309068,6 +309409,14 @@ "text-box-trim-half-leading-inline-box-001.html.ini": [ "8cf8c09698c9bb5e5335e29c4038394136beb29a", [] + ], + "text-box-trim-half-leading-inline-box-002-ref.html": [ + "4ae48240456e67573be05586b89c9dba67d36477", + [] + ], + "text-box-trim-half-leading-inline-box-002.html.ini": [ + "d9f0acbe27198d86a0930c20aa6978a4c80680ca", + [] ] } }, @@ -314462,10 +314811,6 @@ "de372b7314e09d0b0a4df946bdaf320bf526dd81", [] ], - "register-property-syntax-parsing-expected.txt": [ - "68d3c6be68d3f1c2505407198bc84a32ff04f09d", - [] - ], "register-property-syntax-parsing.html.ini": [ "d167c0fafdc95ffe170b6db2b89b8fb7c011b365", [] @@ -318153,7 +318498,7 @@ [] ], "min-content-negative-margin-crash.html.ini": [ - "4b10df0223c3040ef26aa6cb11a12189e5ade033", + "fc03201a2e519872f038f27bab9ee8d549c691f1", [] ], "nested-flexbox-image-percentage-max-height-computes-as-none-ref.html": [ @@ -328503,6 +328848,10 @@ "ff428f0d2fb4cb85deecd123c54dcef65c487207", [] ], + "kind-of-widget-fallback-color-input-border-block-end-width-001.html.ini": [ + "78b229dcac3e34517f5037669f98b570d73d9e0b", + [] + ], "kind-of-widget-fallback-color-input-border-block-start-color-001.html.ini": [ "795ca976371b89fd021359a386742ef7d5da6133", [] @@ -328571,6 +328920,10 @@ "0365a439f6c48c80cc4dff57d132833c014609cf", [] ], + "kind-of-widget-fallback-input-button-background-attachment-001.html.ini": [ + "164827018276eaaa79d49de563b5d8647602c4a8", + [] + ], "kind-of-widget-fallback-input-button-background-origin-001.html.ini": [ "c8c5d4bcfd0e3c15615900ace6af3b50627c69f6", [] @@ -328596,7 +328949,7 @@ [] ], "kind-of-widget-fallback-input-button-border-image-slice-001.html.ini": [ - "0a20afb2697cc9400db86034f04255907e996f1a", + "33ab63083b4362b433eacf5e7d422cd4ab6f9d2f", [] ], "kind-of-widget-fallback-input-button-border-image-width-001.html.ini": [ @@ -328656,7 +329009,7 @@ [] ], "kind-of-widget-fallback-input-reset-border-image-outset-001.html.ini": [ - "70fbacf048827134451d579d246a600a42a5c92c", + "d83716391ed3ef9e94640e68194ec8a130af462c", [] ], "kind-of-widget-fallback-input-reset-border-image-repeat-001.html.ini": [ @@ -328711,6 +329064,14 @@ "133535d0d1baac683a2500f6d12aa1e02cbfc8e4", [] ], + "kind-of-widget-fallback-input-search-background-size-001.html.ini": [ + "cb2594e7e946bb82e5dedd29901af13160cbee21", + [] + ], + "kind-of-widget-fallback-input-search-border-block-end-width-001.html.ini": [ + "01b12488a5a9b1a3900b8a88af5aa28f09582a51", + [] + ], "kind-of-widget-fallback-input-search-border-bottom-color-001.html.ini": [ "1300857824c48d4b0ebf80fcdf47724a83fab327", [] @@ -328756,7 +329117,7 @@ [] ], "kind-of-widget-fallback-input-search-border-left-color-001.html.ini": [ - "bf0310aa0e5e64d939d6e2ec0c29af224aae68ba", + "6bf00173c2e811dabc9996e7eff8c0636ad8a2f6", [] ], "kind-of-widget-fallback-input-search-border-left-style-001.html.ini": [ @@ -328875,6 +329236,10 @@ "e77afe1815439c7122c23490781221f94231750b", [] ], + "kind-of-widget-fallback-input-search-text-border-right-width-001.html.ini": [ + "944c86cf9235ef95134961375aa25896d55b35fb", + [] + ], "kind-of-widget-fallback-input-search-text-border-start-end-radius-001.html.ini": [ "6f8eb451f388a015e2dc7762d35cf9cca7c9c692", [] @@ -337206,10 +337571,6 @@ "c5f8ec74e8782e095f9ac5eacc241f0fb8d5de88", [] ], - "offset-path-url.html.ini": [ - "fb7b890b1ace0c8fc297af4e659d3c109d9d2f5d", - [] - ], "offset-rotate-ref.html": [ "ec22768e96a1cd1efab206781b985cec8f006686", [] @@ -337228,7 +337589,7 @@ [] ], "offset-path-parsing-valid-expected.txt": [ - "b6ce3f099f91af71a74493008577f9d866c1d9e0", + "3a594855afea4fa9c3f0a44352fdcc883f5cb436", [] ], "offset-path-parsing-valid.html.ini": [ @@ -337396,6 +337757,14 @@ "45c3abf1810a55dc760058bf5fcc3064f3bac188", [] ], + "transform-002-print-ref.html": [ + "7204e1d65712ce4e4b8680184b976b8982b6a981", + [] + ], + "transform-003-print-ref.html": [ + "766c415a1be21e6ebf9022a0826a1e865688fcb8", + [] + ], "transition-in-media-print-ref.html": [ "2f25c06131e9372512e23ab9ff8428c594f74391", [] @@ -337474,6 +337843,10 @@ "05c223561c945bf4697d57a55287522965061d10", [] ], + "ref-filled-greenish-100px-square.html": [ + "bff74d4c9cf2356d9ea01ebb5f5a3a9650ebd6e7", + [] + ], "ref-nothing-below.xht": [ "c87db8094bd4bbb7ba5f18816730fd40c198149d", [] @@ -338551,10 +338924,6 @@ "1ed6da59582b3c6cad43768def8136b36af496c4", [] ], - "range-and-constructors-expected.txt": [ - "46ca349dd203e17082054a64f256a09563ac093a", - [] - ], "range-and-constructors.html.ini": [ "2b3bf9b81dc721d78ed10d1ccb4ccdabe72d00db", [] @@ -347586,6 +347955,14 @@ "b8fe518737eedf1a8e129d6af5a54d85a484b5e0", [] ], + "fetch-ad-auction-headers-insecure-context.tentative.http-expected.txt": [ + "76c9302351fd9bc4b93f907a67dbf1241ce0f0f8", + [] + ], + "fetch-ad-auction-headers-insecure-context.tentative.http.html.ini": [ + "b1bc8a1a71b612b1eb1c86b331c33ace391421f3", + [] + ], "join-leave-ad-interest-group.https.sub.window-expected.txt": [ "64032ff143d233cc678ea0bbe8d5900807dfc71c", [] @@ -347627,6 +348004,10 @@ "9a97d45bd1247cd6c566f4f3cfb5b7e6d40876e8", [] ], + "empty.html": [ + "0e76edd65b7baf5316fc9d0c4da59a3502e4c27a", + [] + ], "fenced-frame.sub.py": [ "c29bb6fecccf5dc47ef82e4dc2fda4991b993f85", [] @@ -349474,6 +349855,10 @@ "4237ac12f12247d6c962cbf1833e049af11dcb9c", [] ], + "fullscreen-reordering.html.ini": [ + "69921cad9cfc6e22af88aacaa21d67baba24b439", + [] + ], "historical-expected.txt": [ "a93464001f4af9011755328c52c0eefddd927285", [] @@ -354936,7 +355321,7 @@ [] ], "offscreencanvas.transfer.to.imagebitmap.w.html.ini": [ - "9dedda4d27bef98745331adea4951fa2f8d2bab9", + "6db111198f8ce28b56f9082ac3163ff51ea35d2c", [] ], "offscreencanvas.transferrable-expected.txt": [ @@ -364178,18 +364563,6 @@ "04899f6b8f4c110c47cb0fb16ca0d5c4ebc8b2c2", [] ], - "image-loading-lazy-expected.txt": [ - "699127e6bb3b93a9db6355d7d50110129ee2a8e9", - [] - ], - "image-loading-lazy-move-document-expected.txt": [ - "19b93ec6269d92ec8ecee15adc11d1947239dd27", - [] - ], - "image-loading-lazy-move-document.html.ini": [ - "684c578b2eca5f492e945e48fd922262f337b389", - [] - ], "image-loading-lazy-multiple-times-expected.txt": [ "4f7c4f2cb3497108feba281dc2bf5f276c8372fd", [] @@ -364218,10 +364591,6 @@ "2b9575dae23528d058c38401346b0a72ce17697b", [] ], - "image-loading-lazy.html.ini": [ - "9e9875ac304247fb95d208cd27254b021b8ba6a7", - [] - ], "image-loading-subpixel-clip-ref.html": [ "f841dba31bd255b17afa8a1c7129b6998294c154", [] @@ -365542,7 +365911,7 @@ [] ], "popover-focus.html.ini": [ - "7e6b73d9a0cb9d9d2c9ba68b315c5f9895df3b80", + "c23330fadfada377337ddc684b28fd91a708b52b", [] ], "popover-hidden-display-ref.html": [ @@ -365587,7 +365956,7 @@ [] ], "popover-utils.js": [ - "39de6aa99b1fc810f5025f6c2d0e50780b4c6130", + "aa69b7d41ae032330dc20a9e565e0b1ff9c53058", [] ] } @@ -378691,6 +379060,18 @@ "83670cd86e34c3cbf3b465428b8ff6848d51f534", [] ], + "modulepreload-as.html.ini": [ + "e0355a2de0d2cc13ca79a236097178f36be67e63", + [] + ], + "modulepreload-expected.txt": [ + "1cef0afff4d423bc95ea3e824f0c0fda7b3c9559", + [] + ], + "modulepreload.html.ini": [ + "fe059ec2a207db9a8e068259a49e867599cb4e91", + [] + ], "onerror-event-expected.txt": [ "aa88efb3eb7fc97636a54832b4ce6f414d883571", [] @@ -381223,11 +381604,11 @@ [] ], "header-delay.h2.py": [ - "be29e52b0e836ca0228b9e51cd22c31a0bb4c899", + "27b6fd5bfbb70445454ed7ec0735b662b4c15091", [] ], "header-delay.py": [ - "a47a63e9814a78bd06e2f55922de27fe073da45f", + "631f7855f86bb64df6e84306de0ed5562d913f56", [] ], "iframe-TAO-crossorigin-port.sub.html": [ @@ -382065,6 +382446,10 @@ "6610f7a5a7e503c2deab83a7cde3979222898abc", [] ], + "scroll-timeline-default-print.tentative.html.ini": [ + "6da54aee0f4437b2c8fb28a7a3fa3b55f3d48cbd", + [] + ], "scroll-timeline-specified-scroller-ref.html": [ "d2f2d8f73d71f84c0c1111e6f923929acdb22a3a", [] @@ -386750,8 +387135,12 @@ "a220b7b72f1467d05a18fc9961a5b21e09b8b852", [] ], + "prefetch.https-expected.txt": [ + "e0a8051c9e629eec1a311af429d4fdfb3b1b2e94", + [] + ], "prefetch.https.html.ini": [ - "a47b266d5ef050f92d24af9351aa02cc9599f2b4", + "ef1c0dd1379e3c0798d3b598ca84bffd4ffa3aa0", [] ], "referrer-policy-from-rules.html.ini": [ @@ -393304,7 +393693,7 @@ [] ], "full-cycle-test.https.any.js.ini": [ - "2bbc8fa93e6ad1d6a0afb80722b3c68d0b5e60d8", + "36fa0f322f5301750fb242b83ffb54e2b2850c3c", [] ], "h264.annexb": [ @@ -415681,7 +416070,7 @@ ], "import_export": { "ec_importKey.https.any.js": [ - "c70583bf12eba9afdf641ebb0c13f38d75d86e3b", + "25defa369c1d31430fd44a0afdd4455773d606a1", [ "WebCryptoAPI/import_export/ec_importKey.https.any.html", { @@ -415971,7 +416360,7 @@ ] ], "rsa_importKey.https.any.js": [ - "41d25da89c6505f9e0408cff72a2bb1b9d884266", + "5582b2f506b067d38dda13af286a87dcb507d7b4", [ "WebCryptoAPI/import_export/rsa_importKey.https.any.html", { @@ -416014,7 +416403,7 @@ ] ], "symmetric_importKey.https.any.js": [ - "404b66ac0022acd81ed803c9054969fbb3a02111", + "a9ce9be0a1becf95a3d199a6a1ac18da67a4f173", [ "WebCryptoAPI/import_export/symmetric_importKey.https.any.html", { @@ -441906,7 +442295,7 @@ ] ], "at-container-style-parsing.html": [ - "b49205824b542069db8959dfbccdcdfa6ae627c9", + "36fda2e36630d2330e84da0edc571983f9d07790", [ null, {} @@ -442515,7 +442904,7 @@ ] ], "style-container-for-shadow-dom.html": [ - "c3ac961de2d9b15ecc8a266a0eb9f22b93e0b08f", + "b8bea097504713207f7e77bf8eba5ea6e80735a2", [ null, {} @@ -443187,7 +443576,7 @@ ], "parsing": { "display-computed.html": [ - "e0d08a0045866df281a3f97f174c4b318e72f34c", + "b8c7b5e47eaa242eefff4b983d96d21c71f7a998", [ null, {} @@ -443201,7 +443590,7 @@ ] ], "display-valid.html": [ - "ecd57511422eeb4ea64f65bd832d41b6f1f3f6a7", + "9501a6e2ba7cb195c8254355bafcaa0842d0ad23", [ null, {} @@ -455748,6 +456137,38 @@ ] ] }, + "css-scroll-snap-2": { + "parsing": { + "scroll-start-computed.html": [ + "dd8a5e280f2b5e7664d557a2cb5406f00d28dd61", + [ + null, + {} + ] + ], + "scroll-start-invalid.html": [ + "01dbbc4858062a574b3cf5c485d1eafd204d7225", + [ + null, + {} + ] + ], + "scroll-start-shorthand.html": [ + "22e206ec627012b7672341638690e76e1df9956d", + [ + null, + {} + ] + ], + "scroll-start-valid.html": [ + "c472979543992628ba27bbbf8cceb1f06ade0a53", + [ + null, + {} + ] + ] + } + }, "css-scrollbars": { "auto-scrollbar-inline-children.html": [ "149cf942fe625af24de8623baab3e68fed581738", @@ -463956,7 +464377,7 @@ ] ], "display.html": [ - "7a90b1c07cd45638c6e521fe901e512a31a6ded0", + "b650431d84350f7c293a1cfee82fa79f57fb01b9", [ null, {} @@ -472557,7 +472978,7 @@ ] ], "range-and-constructors.html": [ - "d17c3b71480aa9dd2a75ccbc2cccfd362060eb3c", + "cc5142485164cc7d12e1a00e4fe9c0f47b2725d4", [ null, {} @@ -509072,6 +509493,20 @@ } ] ], + "fetch-ad-auction-headers-insecure-context.tentative.http.html": [ + "d3bdb8017579414aee39ad672519ff029f9d0827", + [ + null, + {} + ] + ], + "fetch-ad-auction-headers.tentative.https.html": [ + "7b2a2c2ba4a2f037874a0647180a4eb7e06e772d", + [ + null, + {} + ] + ], "insecure-context.window.js": [ "9016277b73139d050e3d688c3f21cb40048464e2", [ @@ -511288,6 +511723,15 @@ } ] ], + "fullscreen-reordering.html": [ + "1a286c32c770342d3a6026545dde5213925e2292", + [ + null, + { + "testdriver": true + } + ] + ], "historical.html": [ "8b3e3c03e9cb7e9f247c9d9f2cfe0f752218122f", [ @@ -554160,7 +554604,7 @@ ] ], "child-sequential-focus.html": [ - "1b4dd30230054571e395958820c1c184d8e19659", + "bc787202cf53522188238b9bc7db6537a7533100", [ null, {} @@ -554925,13 +555369,6 @@ {} ] ], - "popover-dialog-initial-focus.html": [ - "47b2252bf5f26bc5bd122b9e57035992da65855a", - [ - null, - {} - ] - ], "popover-document-open.html": [ "80ac86acedab246d5ceff8b54d57feb7e957d642", [ @@ -554963,7 +555400,7 @@ ] ], "popover-focus.html": [ - "df7c046e003a8e70481e124e6441e246043970cd", + "98bb065de7b8b894c803d9e6f0d5145515e207bb", [ null, { @@ -555009,7 +555446,7 @@ ] ], "popover-light-dismiss.html": [ - "4411d0b7e381b95960d25a5fbbda7682af1db263", + "d7d1edd3a4b1fa655f971c69cf4d77b64926dc1b", [ null, { @@ -567681,7 +568118,7 @@ ] ], "image-src-change.html": [ - "e0701a2169b3860af4441a2562402bda284db34f", + "33213a570ed3187269f53053def945a4c03017a9", [ null, {} @@ -569420,8 +569857,8 @@ } ] ], - "loaf-source-location-bound.html": [ - "8e8019104af2052eeb8617ba31ad174b99ddd636", + "loaf-source-location.html": [ + "ffda00020717cf87684ba0a8331100778592f619", [ null, { @@ -583768,8 +584205,22 @@ {} ] ], + "modulepreload-as.html": [ + "dd946e454a1fe1833dbe37164105f028795facba", + [ + null, + {} + ] + ], + "modulepreload-sri.html": [ + "ea32a6a302525240573deb75b6e3f16b96b5e1eb", + [ + null, + {} + ] + ], "modulepreload.html": [ - "0e4b6923e32e83ac3b8f3018537352aa120df6c5", + "bcd18c890fa836c500c86a7e5afb5c17a9f82f42", [ null, {} @@ -597479,17 +597930,21 @@ ] ], "interim-response-times.h2.html": [ - "850ee7cb5f539b76ddfd9c1489915fa9ddaf7215", + "4b1ca93ff7bd621fc1495c1030c1ebd3730b497c", [ null, - {} + { + "timeout": "long" + } ] ], "interim-response-times.html": [ - "b922590d5d32c2b3899d82e4ea9297d54b6c7cc2", + "a4d03f599ee5a756af07212423f79e758ab617fc", [ null, - {} + { + "timeout": "long" + } ] ], "link-sequence-of-events.html": [ @@ -600448,7 +600903,7 @@ ] ], "scroll-timeline-shorthand.tentative.html": [ - "dd1e6e12a98d285855699c7a4eba73164c4a4444", + "68e1cc955f5239075cf283ceac3938c42143a9e4", [ null, {} @@ -600616,7 +601071,7 @@ ] ], "view-timeline-shorthand.tentative.html": [ - "0ab0f21ff6ce802d882d80f1944e5932b5ac3e69", + "f19b9e6ac21bd0a825f7e944ec9eea747897d09a", [ null, {} @@ -608681,6 +609136,51 @@ {} ] ], + "initiators-a-element.sub.https.html": [ + "bac5eb7cb794e094799b9b42a2edc536d245d2ef", + [ + "speculation-rules/prefetch/initiators-a-element.sub.https.html?cross-site", + { + "timeout": "long" + } + ], + [ + "speculation-rules/prefetch/initiators-a-element.sub.https.html?same-site", + { + "timeout": "long" + } + ] + ], + "initiators-iframe-location-href.sub.https.html": [ + "9d6702d4b752adc2186d986347e4c9d273e154ca", + [ + "speculation-rules/prefetch/initiators-iframe-location-href.sub.https.html?cross-site", + { + "timeout": "long" + } + ], + [ + "speculation-rules/prefetch/initiators-iframe-location-href.sub.https.html?same-site", + { + "timeout": "long" + } + ] + ], + "initiators-window-open.sub.https.html": [ + "f786df077dbfe1c3856aeb576ec005484e505c63", + [ + "speculation-rules/prefetch/initiators-window-open.sub.https.html?cross-site", + { + "timeout": "long" + } + ], + [ + "speculation-rules/prefetch/initiators-window-open.sub.https.html?same-site", + { + "timeout": "long" + } + ] + ], "invalid-rules.https.html": [ "573f3c0b0f91fe001371b54e1c357ec11a815579", [ @@ -608971,7 +609471,7 @@ ] ], "prefetch-traverse-reload.sub.html": [ - "3f1312ed1222ad78b9f752e190f75e3275929c60", + "ec6a7cd92615799a6b9789726955334a9818d15e", [ null, { @@ -609300,7 +609800,7 @@ ] ], "prefetch.https.html": [ - "48de5adca13e0aa64312f006531bcb8633aba255", + "2a1553b3d94bb7ebc0c8d9792416fc112ff1d40c", [ null, { @@ -673680,13 +674180,6 @@ {} ] ], - "order-of-images.htm": [ - "3ae03636d19d38f89ead6d942eb809b7b5e0e662", - [ - null, - {} - ] - ], "ttwf-css3background-border-color-shorthand-missing-bottom.htm": [ "b7bccd77af49810bdd83d4cdf9ec5b7126967283", [
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures.js index c39e4d21..e0f0279a 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/generateKey/failures.js
@@ -204,7 +204,7 @@ }); - // The last thing that should be checked is an empty usages (for secret keys). + // The last thing that should be checked is empty usages (disallowed for secret and private keys). testVectors.forEach(function(vector) { var name = vector.name;
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js index c70583b..25defa36 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/ec_importKey.https.any.js
@@ -85,13 +85,13 @@ }); // Next, test private keys - allValidUsages(vector.privateUsages, []).forEach(function(usages) { - ['pkcs8', 'jwk'].forEach(function(format) { - var algorithm = {name: vector.name, namedCurve: curve}; - var data = keyData[curve]; - + ['pkcs8', 'jwk'].forEach(function(format) { + var algorithm = {name: vector.name, namedCurve: curve}; + var data = keyData[curve]; + allValidUsages(vector.privateUsages, []).forEach(function(usages) { testFormat(format, algorithm, data, curve, usages, extractable); }); + testEmptyUsages(format, algorithm, data, curve, extractable); }); }); @@ -136,6 +136,21 @@ }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, compressed, keyData, algorithm, extractable, usages)); } + // Test importKey with a given key format and other parameters but with empty usages. + // Should fail with SyntaxError + function testEmptyUsages(format, algorithm, data, keySize, extractable) { + const keyData = data[format]; + const usages = []; + promise_test(function(test) { + return subtle.importKey(format, keyData, algorithm, extractable, usages). + then(function(key) { + assert_unreached("importKey succeeded but should have failed with SyntaxError"); + }, function(err) { + assert_equals(err.name, "SyntaxError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, "Empty Usages: " + keySize.toString() + " bits " + parameterString(format, false, keyData, algorithm, extractable, usages)); + } + // Helper methods follow:
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures.js index a5cc08a..ebdb7361 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures.js
@@ -132,6 +132,19 @@ }); }); + // Algorithms normalize okay, but usages bad (empty). + // Should fail due to SyntaxError + testVectors.forEach(function(vector) { + var name = vector.name; + validKeyData.filter((test) => test.format === 'pkcs8' || (test.format === 'jwk' && test.data.d)).forEach(function(test) { + allAlgorithmSpecifiersFor(name).forEach(function(algorithm) { + [true, false].forEach(function(extractable) { + testError(test.format, algorithm, test.data, name, [/* Empty usages */], extractable, "SyntaxError", "Empty usages"); + }); + }); + }); + }); + // Algorithms normalize okay, usages ok. The length of the key must thouw a DataError exception. testVectors.forEach(function(vector) { var name = vector.name;
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any-expected.txt index 3eeace12..713ec42 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 244 tests; 0 PASS, 244 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 248 tests; 0 PASS, 248 FAIL, 0 TIMEOUT, 0 NOTRUN. FAIL Bad usages: importKey(spki, {name: Ed448}, true, [encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(spki, {name: Ed448}, false, [encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(spki, {name: Ed448}, true, [verify, encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" @@ -210,6 +210,10 @@ FAIL Bad usages: importKey(jwk (public) , {name: Ed448}, false, [verify, deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(jwk (public) , {name: Ed448}, true, [verify, verify, deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(jwk (public) , {name: Ed448}, false, [verify, verify, deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(pkcs8, {name: Ed448}, true, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(pkcs8, {name: Ed448}, false, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(jwk(private), {name: Ed448}, true, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(jwk(private), {name: Ed448}, false, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: Ed448}, true, [verify]) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: Ed448}, false, [verify]) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: Ed448}, true, [verify, verify]) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError"
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js.ini b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js.ini index c013a55..a910d32 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js.ini +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.js.ini
@@ -689,6 +689,18 @@ [Bad usages: importKey(spki, {name: Ed448}, true, [wrapKey\])] expected: FAIL + [Empty usages: importKey(jwk(private), {name: Ed448}, false, [\])] + expected: FAIL + + [Empty usages: importKey(jwk(private), {name: Ed448}, true, [\])] + expected: FAIL + + [Empty usages: importKey(pkcs8, {name: Ed448}, false, [\])] + expected: FAIL + + [Empty usages: importKey(pkcs8, {name: Ed448}, true, [\])] + expected: FAIL + [Invalid key pair: importKey(jwk(private), {name: Ed448}, true, [sign, sign\])] expected: FAIL @@ -1423,6 +1435,18 @@ [Bad usages: importKey(spki, {name: Ed448}, true, [wrapKey\])] expected: FAIL + [Empty usages: importKey(jwk(private), {name: Ed448}, false, [\])] + expected: FAIL + + [Empty usages: importKey(jwk(private), {name: Ed448}, true, [\])] + expected: FAIL + + [Empty usages: importKey(pkcs8, {name: Ed448}, false, [\])] + expected: FAIL + + [Empty usages: importKey(pkcs8, {name: Ed448}, true, [\])] + expected: FAIL + [Invalid key pair: importKey(jwk(private), {name: Ed448}, true, [sign, sign\])] expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.worker-expected.txt index 3eeace12..713ec42 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_Ed448.https.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 244 tests; 0 PASS, 244 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 248 tests; 0 PASS, 248 FAIL, 0 TIMEOUT, 0 NOTRUN. FAIL Bad usages: importKey(spki, {name: Ed448}, true, [encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(spki, {name: Ed448}, false, [encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(spki, {name: Ed448}, true, [verify, encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" @@ -210,6 +210,10 @@ FAIL Bad usages: importKey(jwk (public) , {name: Ed448}, false, [verify, deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(jwk (public) , {name: Ed448}, true, [verify, verify, deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(jwk (public) , {name: Ed448}, false, [verify, verify, deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(pkcs8, {name: Ed448}, true, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(pkcs8, {name: Ed448}, false, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(jwk(private), {name: Ed448}, true, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(jwk(private), {name: Ed448}, false, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: Ed448}, true, [verify]) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: Ed448}, false, [verify]) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: Ed448}, true, [verify, verify]) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError"
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any-expected.txt index 82c8888..be7bbd5 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 212 tests; 0 PASS, 212 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 216 tests; 0 PASS, 216 FAIL, 0 TIMEOUT, 0 NOTRUN. FAIL Bad usages: importKey(spki, {name: X448}, true, [encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(spki, {name: X448}, false, [encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(spki, {name: X448}, true, [decrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" @@ -168,6 +168,10 @@ FAIL Bad usages: importKey(jwk (public) , {name: X448}, false, [deriveKey]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(jwk (public) , {name: X448}, true, [deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(jwk (public) , {name: X448}, false, [deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(pkcs8, {name: X448}, true, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(pkcs8, {name: X448}, false, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(jwk(private), {name: X448}, true, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(jwk(private), {name: X448}, false, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: X448}, true, []) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: X448}, false, []) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError" FAIL Bad key length: importKey(pkcs8, {name: X448}, true, [deriveKey]) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError"
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js.ini b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js.ini index 2e5655d..580fbf95 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js.ini +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.js.ini
@@ -569,6 +569,18 @@ [Bad usages: importKey(spki, {name: X448}, true, [wrapKey\])] expected: FAIL + [Empty usages: importKey(jwk(private), {name: X448}, false, [\])] + expected: FAIL + + [Empty usages: importKey(jwk(private), {name: X448}, true, [\])] + expected: FAIL + + [Empty usages: importKey(pkcs8, {name: X448}, false, [\])] + expected: FAIL + + [Empty usages: importKey(pkcs8, {name: X448}, true, [\])] + expected: FAIL + [Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveBits, deriveKey\])] expected: FAIL @@ -1207,6 +1219,18 @@ [Bad usages: importKey(spki, {name: X448}, true, [wrapKey\])] expected: FAIL + [Empty usages: importKey(jwk(private), {name: X448}, false, [\])] + expected: FAIL + + [Empty usages: importKey(jwk(private), {name: X448}, true, [\])] + expected: FAIL + + [Empty usages: importKey(pkcs8, {name: X448}, false, [\])] + expected: FAIL + + [Empty usages: importKey(pkcs8, {name: X448}, true, [\])] + expected: FAIL + [Invalid key pair: importKey(jwk(private), {name: X448}, true, [deriveBits, deriveKey\])] expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.worker-expected.txt index 82c8888..be7bbd5 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/okp_importKey_failures_X448.https.any.worker-expected.txt
@@ -1,5 +1,5 @@ This is a testharness.js-based test. -Found 212 tests; 0 PASS, 212 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 216 tests; 0 PASS, 216 FAIL, 0 TIMEOUT, 0 NOTRUN. FAIL Bad usages: importKey(spki, {name: X448}, true, [encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(spki, {name: X448}, false, [encrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(spki, {name: X448}, true, [decrypt]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" @@ -168,6 +168,10 @@ FAIL Bad usages: importKey(jwk (public) , {name: X448}, false, [deriveKey]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(jwk (public) , {name: X448}, true, [deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad usages: importKey(jwk (public) , {name: X448}, false, [deriveBits]) assert_equals: Bad usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(pkcs8, {name: X448}, true, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(pkcs8, {name: X448}, false, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(jwk(private), {name: X448}, true, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" +FAIL Empty usages: importKey(jwk(private), {name: X448}, false, []) assert_equals: Empty usages not supported. expected "SyntaxError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: X448}, true, []) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError" FAIL Bad key length: importKey(spki, {name: X448}, false, []) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError" FAIL Bad key length: importKey(pkcs8, {name: X448}, true, [deriveKey]) assert_equals: Bad key length not supported. expected "DataError" but got "NotSupportedError"
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.any.js index 41d25da..5582b2f 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/rsa_importKey.https.any.js
@@ -92,13 +92,13 @@ }); // Next, test private keys - allValidUsages(vector.privateUsages, []).forEach(function(usages) { - ['pkcs8', 'jwk'].forEach(function(format) { - var algorithm = {name: vector.name, hash: hash}; - var data = keyData[size]; - + ['pkcs8', 'jwk'].forEach(function(format) { + var algorithm = {name: vector.name, hash: hash}; + var data = keyData[size]; + allValidUsages(vector.privateUsages, []).forEach(function(usages) { testFormat(format, algorithm, data, size, usages, extractable); }); + testEmptyUsages(format, algorithm, data, size, extractable); }); }); }); @@ -135,6 +135,20 @@ }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData[format], algorithm, extractable, usages)); } + // Test importKey with a given key format and other parameters but with empty usages. + // Should fail with SyntaxError + function testEmptyUsages(format, algorithm, keyData, keySize, extractable) { + const usages = []; + promise_test(function(test) { + return subtle.importKey(format, keyData[format], algorithm, extractable, usages). + then(function(key) { + assert_unreached("importKey succeeded but should have failed with SyntaxError"); + }, function(err) { + assert_equals(err.name, "SyntaxError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, "Empty Usages: " + keySize.toString() + " bits " + parameterString(format, keyData, algorithm, extractable, usages)); + } + // Helper methods follow:
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any-expected.txt index c864d22..ffc5ab04 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any-expected.txt
@@ -1,238 +1,316 @@ This is a testharness.js-based test. -Found 234 tests; 186 PASS, 48 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 312 tests; 248 PASS, 64 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, []) +PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, []) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, []) FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, []) +PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, []) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, []) +PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, []) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, []) FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, []) +PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, []) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, []) +PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, []) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, []) FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, []) +PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, []) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [wrapKey]) -PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [wrapKey]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) -PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [wrapKey]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey, wrapKey]) -PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) -PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, []) +PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [wrapKey]) +PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [unwrapKey]) +PASS Empty Usages: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, []) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [wrapKey]) +PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [unwrapKey]) +PASS Empty Usages: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, []) FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [unwrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [unwrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [wrapKey]) -PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [wrapKey]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) -PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [wrapKey]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey, wrapKey]) -PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) -PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, []) +PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [wrapKey]) +PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [unwrapKey]) +PASS Empty Usages: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, []) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [wrapKey]) +PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [unwrapKey]) +PASS Empty Usages: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) +PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, []) +PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) +PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) +PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) +PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, []) +PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) +PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) +PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) +PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, []) +PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) +PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) +PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) +PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, []) +PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) +PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) +PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveBits]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey, deriveBits]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveBits]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey, deriveBits]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveBits]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey, deriveBits]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveBits]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey, deriveBits]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveBits]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey, deriveBits]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveBits]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey, deriveBits]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, []) Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.js b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.js index 404b66ac..a9ce9be 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.js +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.js
@@ -41,17 +41,18 @@ } rawKeyData.forEach(function(keyData) { - // Generate all combinations of valid usages for testing - allValidUsages(vector.legalUsages, []).forEach(function(usages) { - // Try each legal value of the extractable parameter - vector.extractable.forEach(function(extractable) { - vector.formats.forEach(function(format) { - var data = keyData; - if (format === "jwk") { - data = jwkData(keyData, algorithm); - } + // Try each legal value of the extractable parameter + vector.extractable.forEach(function(extractable) { + vector.formats.forEach(function(format) { + var data = keyData; + if (format === "jwk") { + data = jwkData(keyData, algorithm); + } + // Generate all combinations of valid usages for testing + allValidUsages(vector.legalUsages, []).forEach(function(usages) { testFormat(format, algorithm, data, keyData.length * 8, usages, extractable); }); + testEmptyUsages(format, algorithm, data, keyData.length * 8, extractable); }); }); @@ -90,6 +91,20 @@ }, "Good parameters: " + keySize.toString() + " bits " + parameterString(format, keyData, algorithm, extractable, usages)); } + // Test importKey with a given key format and other parameters but with empty usages. + // Should fail with SyntaxError + function testEmptyUsages(format, algorithm, keyData, keySize, extractable) { + const usages = []; + promise_test(function(test) { + return subtle.importKey(format, keyData, algorithm, extractable, usages). + then(function(key) { + assert_unreached("importKey succeeded but should have failed with SyntaxError"); + }, function(err) { + assert_equals(err.name, "SyntaxError", "Should throw correct error, not " + err.name + ": " + err.message); + }); + }, "Empty Usages: " + keySize.toString() + " bits " + parameterString(format, keyData, algorithm, extractable, usages)); + } + // Helper methods follow:
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.js.ini b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.js.ini index 5758e94..6064f9c 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.js.ini +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.js.ini
@@ -1,4 +1,52 @@ [symmetric_importKey.https.any.html] + [Empty Usages: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [\])] + expected: FAIL + [Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt\])] expected: FAIL @@ -145,6 +193,54 @@ [symmetric_importKey.https.any.worker.html] + [Empty Usages: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [\])] + expected: FAIL + + [Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [\])] + expected: FAIL + [Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt\])] expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.worker-expected.txt index c864d22..ffc5ab04 100644 --- a/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.worker-expected.txt +++ b/third_party/blink/web_tests/external/wpt/WebCryptoAPI/import_export/symmetric_importKey.https.any.worker-expected.txt
@@ -1,238 +1,316 @@ This is a testharness.js-based test. -Found 234 tests; 186 PASS, 48 FAIL, 0 TIMEOUT, 0 NOTRUN. +Found 312 tests; 248 PASS, 64 FAIL, 0 TIMEOUT, 0 NOTRUN. PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, []) +PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, true, []) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128CTR, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CTR}, false, []) FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CTR}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, true, []) +PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, true, []) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [encrypt]) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CTR}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256CTR, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CTR}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, []) +PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, true, []) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128CBC, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-CBC}, false, []) FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-CBC}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, true, []) +PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, true, []) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [encrypt]) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-CBC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256CBC, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-CBC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) -PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, []) +PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, true, []) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [encrypt]) +PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, [decrypt]) +PASS Empty Usages: 128 bits (jwk, {alg: A128GCM, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-GCM}, false, []) FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, [decrypt]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-GCM}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) -PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, true, []) +PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, true, []) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [encrypt]) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, [decrypt]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-GCM}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [encrypt]) +PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [decrypt, encrypt]) PASS Good parameters: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, [decrypt]) +PASS Empty Usages: 256 bits (jwk, {alg: A256GCM, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-GCM}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [wrapKey]) -PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [wrapKey]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) -PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [wrapKey]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey, wrapKey]) -PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) -PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) -PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, []) +PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [wrapKey]) +PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, [unwrapKey]) +PASS Empty Usages: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, true, []) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) +PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [wrapKey]) +PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, [unwrapKey]) +PASS Empty Usages: 128 bits (jwk, {alg: A128KW, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {name: AES-KW}, false, []) FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code -FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, [unwrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, true, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" +FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code FAIL Good parameters: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, [unwrapKey]) assert_unreached: Threw an unexpected error: OperationError: 192-bit AES keys are not supported Reached unreachable code +FAIL Empty Usages: 192 bits (jwk, {alg: A192KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {name: AES-KW}, false, []) assert_equals: Should throw correct error, not OperationError: 192-bit AES keys are not supported expected "SyntaxError" but got "OperationError" PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [wrapKey]) -PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [wrapKey]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) -PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [wrapKey]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey, wrapKey]) -PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) -PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) -PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, [unwrapKey]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, true, []) +PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [wrapKey]) +PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [unwrapKey, wrapKey]) PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, [unwrapKey]) +PASS Empty Usages: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, true, []) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [wrapKey]) +PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, [unwrapKey]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: AES-KW}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [wrapKey]) +PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [unwrapKey, wrapKey]) PASS Good parameters: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, [unwrapKey]) +PASS Empty Usages: 256 bits (jwk, {alg: A256KW, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {name: AES-KW}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) +PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-1, name: HMAC}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, []) +PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) +PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-1, name: HMAC}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-1, name: HMAC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [sign]) +PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (jwk, {alg: HS1, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-1, name: HMAC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) +PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-256, name: HMAC}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, []) +PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) +PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-256, name: HMAC}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-256, name: HMAC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [sign]) +PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (jwk, {alg: HS256, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-256, name: HMAC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) +PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-384, name: HMAC}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, []) +PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) +PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-384, name: HMAC}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-384, name: HMAC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [sign]) +PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (jwk, {alg: HS384, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-384, name: HMAC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, []) +PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) +PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 128 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEA, kty: oct}, {hash: SHA-512, name: HMAC}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, []) +PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) +PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 192 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY, kty: oct}, {hash: SHA-512, name: HMAC}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) -PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {hash: SHA-512, name: HMAC}, false, []) +PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [sign]) +PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify, sign]) PASS Good parameters: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, [verify]) +PASS Empty Usages: 256 bits (jwk, {alg: HS512, k: AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyA, kty: oct}, {hash: SHA-512, name: HMAC}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveBits]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey, deriveBits]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveBits]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey, deriveBits]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveBits]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey, deriveBits]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, [deriveKey]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: HKDF}, false, []) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveBits]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey, deriveBits]) PASS Good parameters: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey]) +PASS Empty Usages: 128 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, []) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveBits]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey, deriveBits]) PASS Good parameters: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey]) +PASS Empty Usages: 192 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, []) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveBits]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey, deriveBits]) PASS Good parameters: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, [deriveKey]) +PASS Empty Usages: 256 bits (raw, {0: 1, 1: 2, 10: 11, 11: 12, 12: 13, 13: 14, 14: 15, 15: 16, 16: 17, 17: 18, 18: 19, 19: 20, 2: 3, 20: 21, 21: 22, 22: 23, 23: 24, 24: 25, 25: 26, 26: 27, 27: 28, 28: 29, 29: 30, 3: 4, 30: 31, 31: 32, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, {name: PBKDF2}, false, []) Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/borders/border-applies-to-004.xht.ini b/third_party/blink/web_tests/external/wpt/css/CSS2/borders/border-applies-to-004.xht.ini new file mode 100644 index 0000000..55587180 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/CSS2/borders/border-applies-to-004.xht.ini
@@ -0,0 +1,3 @@ +[border-applies-to-004.xht] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/order-of-images.htm b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/order-of-images.htm index 3ae03636..9f165fb9 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/order-of-images.htm +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/order-of-images.htm
@@ -1,9 +1,10 @@ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> - <title>CSS Test: Order of images</title> + <title>CSS Backgrounds Test: Order of multiple overlapping background images</title> <link rel="author" title="Microsoft" href="http://www.microsoft.com/" /> <link rel="help" href="http://www.w3.org/TR/css3-background/#the-background-image" /> + <link rel="match" href="reference/order-of-images-ref.html" /> <meta name="assert" content="Background images are listed in order, with the first image being rendered on top of all the other images, and so on." /> <style type="text/css"> div @@ -20,4 +21,4 @@ <p>Test passes if a blue box overlaps an orange box, which overlaps a black box.</p> <div></div> </body> -</html> \ No newline at end of file +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/order-of-images-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/order-of-images-ref.html new file mode 100644 index 0000000..a704cd4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/order-of-images-ref.html
@@ -0,0 +1,49 @@ +<!DOCTYPE html> + + <meta charset="UTF-8"> + + <title>CSS Reftest Reference</title> + + <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/"> + + <style> + div + { + height: 100px; + position: relative; + width: 100px; + } + + div#outer-black + { + background-color: black; + left: 90px; + top: 90px; + } + + div#middle-orange + { + background-color: orange; + bottom: 30px; + right: 30px; + } + + div#inner-blue + { + background-color: blue; + bottom: 30px; + right: 30px; + } + </style> + + <p>Test passes if a blue box overlaps an orange box, which overlaps a black box. + + <div id="outer-black"> + + <div id="middle-orange"> + + <div id="inner-blue"></div> + + </div> + + </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/block-max-height-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-break/block-max-height-004-ref.html new file mode 100644 index 0000000..74a2ed7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-break/block-max-height-004-ref.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> + <title>CSS Reference: max-height block fragmentation</title> + <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com"> + <link rel="author" title="Mozilla" href="https://www.mozilla.org/"> + <style> + .multicol { + height: 30px; + width: 100px; + column-width: 30px; + column-fill: auto; + border: 2px solid orange; + } + .block { + display: block; + background: teal; + border: 5px solid black; + border-top-width: 0; + height: 40px; + } + .child { + display: block; + width: 50%; + height: 80px; + } + img.child { background: salmon; } + div.child { background: purple; } + </style> + + <div class="multicol"> + <main class="block"> + <img src="" class="child"><div class="child"></div> + </main> + </div> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/block-max-height-004.html b/third_party/blink/web_tests/external/wpt/css/css-break/block-max-height-004.html new file mode 100644 index 0000000..4ceb23a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-break/block-max-height-004.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html> + <title>CSS Test: max-height block fragmentation</title> + <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com"> + <link rel="author" title="Mozilla" href="https://www.mozilla.org/"> + <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id="> + <link rel="help" href="https://drafts.csswg.org/css-break"> + <link rel="match" href="block-max-height-004-ref.html"> + + <style> + .multicol { + height: 30px; + width: 100px; + column-width: 30px; + column-fill: auto; + border: 2px solid orange; + } + .block { + display: block; + background: teal; + border: 5px solid black; + border-top-width: 0; + max-height: 40px; + } + .child { + display: block; + width: 50%; + height: 80px; + } + img.child { background: salmon; } + div.child { background: purple; } + </style> + + <div class="multicol"> + <main class="block"> + <img src="" class="child"><div class="child"></div> + </main> + </div> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed.html.ini b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed.html.ini new file mode 100644 index 0000000..0a161b0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-display/parsing/display-computed.html.ini
@@ -0,0 +1,96 @@ +[display-computed.html] + [Property display value 'block ruby'] + expected: FAIL + + [Property display value 'flex run-in'] + expected: FAIL + + [Property display value 'flow list-item run-in'] + expected: FAIL + + [Property display value 'flow run-in list-item'] + expected: FAIL + + [Property display value 'flow run-in'] + expected: FAIL + + [Property display value 'flow-root list-item run-in'] + expected: FAIL + + [Property display value 'flow-root run-in list-item'] + expected: FAIL + + [Property display value 'flow-root run-in'] + expected: FAIL + + [Property display value 'grid run-in'] + expected: FAIL + + [Property display value 'inline ruby'] + expected: FAIL + + [Property display value 'list-item flow run-in'] + expected: FAIL + + [Property display value 'list-item flow-root run-in'] + expected: FAIL + + [Property display value 'list-item run-in flow'] + expected: FAIL + + [Property display value 'list-item run-in flow-root'] + expected: FAIL + + [Property display value 'list-item run-in'] + expected: FAIL + + [Property display value 'ruby block'] + expected: FAIL + + [Property display value 'ruby inline'] + expected: FAIL + + [Property display value 'ruby run-in'] + expected: FAIL + + [Property display value 'ruby'] + expected: FAIL + + [Property display value 'run-in flex'] + expected: FAIL + + [Property display value 'run-in flow list-item'] + expected: FAIL + + [Property display value 'run-in flow'] + expected: FAIL + + [Property display value 'run-in flow-root list-item'] + expected: FAIL + + [Property display value 'run-in flow-root'] + expected: FAIL + + [Property display value 'run-in grid'] + expected: FAIL + + [Property display value 'run-in list-item flow'] + expected: FAIL + + [Property display value 'run-in list-item flow-root'] + expected: FAIL + + [Property display value 'run-in list-item'] + expected: FAIL + + [Property display value 'run-in ruby'] + expected: FAIL + + [Property display value 'run-in table'] + expected: FAIL + + [Property display value 'run-in'] + expected: FAIL + + [Property display value 'table run-in'] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001.html.ini new file mode 100644 index 0000000..d896e9b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-highlight-api/painting/css-highlight-painting-underline-offset-001.html.ini
@@ -0,0 +1,2 @@ +[css-highlight-painting-underline-offset-001.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001-ref.html new file mode 100644 index 0000000..4fc498a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001-ref.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Reference for trimming block-boxes at their first/last formatted lines</title> +<link rel="help" href="https://drafts.csswg.org/css-inline-3/#leading-trim"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<link rel="match" href="text-box-trim-half-leading-inline-box-001-ref.html"> + +<style> +.div-parent { + outline: 1px solid orange; + font-family: Ahem; + font-size: 20px; + line-height: 1; + text-box-trim: both; +} +</style> + +<div class ="div-parent""> + <div id="d1"></div> + <div id="d2">Testline1<br><br><br>Testline2<br><br><br>Testline3</div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001-ref.html.ini b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001-ref.html.ini new file mode 100644 index 0000000..5d66423 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001-ref.html.ini
@@ -0,0 +1,2 @@ +[text-box-trim-half-leading-block-box-001-ref.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001.html b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001.html new file mode 100644 index 0000000..9ad9ffc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<title>Tests block boxes's edges are trimmed at text-over/text-under baselines of their first/last formatted lines</title> +<link rel="help" href="https://drafts.csswg.org/css-inline-3/#leading-trim"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<link rel="match" href="text-box-trim-half-leading-inline-box-001-ref.html"> + +<style> +.div-parent { + outline: 1px solid orange; + font-family: Ahem; + font-size: 20px; + line-height: 3; + text-box-trim: both; +} +</style> + +<div class ="div-parent""> + <div id="d1"></div> + <div id="d2">Testline1<br>Testline2<br>Testline3</div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001.html.ini new file mode 100644 index 0000000..7881a9ce --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-block-box-001.html.ini
@@ -0,0 +1,2 @@ +[text-box-trim-half-leading-block-box-001.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002-ref.html new file mode 100644 index 0000000..4ae48240 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002-ref.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<title>Reference for trimming multi-line text in inline boxes</title> +<link rel="help" href="https://drafts.csswg.org/css-inline-3/#leading-trim"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> + +<style> +div { + border: 1px solid orange; + font-size: 20px; + line-height: 1; +} + +span { + border: 1px solid blue; + font-family: Ahem; + font-size: 20px; + line-height: 1; +} +</style> + +<div> + <span>Testline1<br><br><br>TestLine2<br><br><br>TestLine3</span> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002.html b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002.html new file mode 100644 index 0000000..3e679f6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<title>Tests inline boxes with multi-line text are trimmed at text-over/text-under baselines</title> +<link rel="help" href="https://drafts.csswg.org/css-inline-3/#leading-trim"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<link rel="match" href="text-box-trim-half-leading-inline-box-001-ref.html"> + +<style> +div { + border: 1px solid orange; + font-size: 20px; + line-height: 1; +} + +span { + border: 1px solid blue; + font-family: Ahem; + font-size: 20px; + line-height: 3; + text-box-trim: both; +} +</style> + +<div> + <span>Testline1<br>TestLine2<br>TestLine3</span> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002.html.ini b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002.html.ini new file mode 100644 index 0000000..d9f0acbe --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-inline/text-box-trim/text-box-trim-half-leading-inline-box-002.html.ini
@@ -0,0 +1,2 @@ +[text-box-trim-half-leading-inline-box-002.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/min-content-negative-margin-crash.html.ini b/third_party/blink/web_tests/external/wpt/css/css-sizing/min-content-negative-margin-crash.html.ini index 4b10df0..fc03201 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-sizing/min-content-negative-margin-crash.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/min-content-negative-margin-crash.html.ini
@@ -1,3 +1,4 @@ [min-content-negative-margin-crash.html] expected: + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): TIMEOUT if (product == "content_shell") and (os == "mac") and (port == "mac11"): TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/infinite-duration-crash.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/infinite-duration-crash.html new file mode 100644 index 0000000..dba53d6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/infinite-duration-crash.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<style> + * { + transition: all ease-out, linear 2733ms background, all calc(2s / 0) steps(706573049); + } +</style> +<script> + document.addEventListener("DOMContentLoaded", () => { + const style = document.createElement("style") + document.head.appendChild(style) + const selection = window.getSelection() + style.sheet.insertRule(`* { background-clip: padding-box, padding-box, border-box, content-box; }`, 0) + selection.selectAllChildren(style) + style.sheet.disabled = true + }) +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-block-end-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-block-end-width-001.html.ini new file mode 100644 index 0000000..78b229dc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-color-input-border-block-end-width-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-color-input-border-block-end-width-001.html] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-background-attachment-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-background-attachment-001.html.ini new file mode 100644 index 0000000..1648270 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-background-attachment-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-input-button-background-attachment-001.html] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-image-slice-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-image-slice-001.html.ini index 0a20afb..33ab630 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-image-slice-001.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-button-border-image-slice-001.html.ini
@@ -1,3 +1,4 @@ [kind-of-widget-fallback-input-button-border-image-slice-001.html] expected: if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-image-outset-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-image-outset-001.html.ini index 70fbacf..d837163 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-image-outset-001.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-reset-border-image-outset-001.html.ini
@@ -1,3 +1,4 @@ [kind-of-widget-fallback-input-reset-border-image-outset-001.html] expected: if (product == "content_shell") and (os == "linux"): FAIL + if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-size-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-size-001.html.ini new file mode 100644 index 0000000..cb2594e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-background-size-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-input-search-background-size-001.html] + expected: + if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-block-end-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-block-end-width-001.html.ini new file mode 100644 index 0000000..01b12488 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-block-end-width-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-input-search-border-block-end-width-001.html] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-left-color-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-left-color-001.html.ini index bf0310aa..6bf0017 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-left-color-001.html.ini +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-border-left-color-001.html.ini
@@ -1,4 +1,5 @@ [kind-of-widget-fallback-input-search-border-left-color-001.html] expected: + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL if (product == "content_shell") and (os == "win") and (port == "win11"): FAIL if (product == "content_shell") and (os == "linux"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-border-right-width-001.html.ini b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-border-right-width-001.html.ini new file mode 100644 index 0000000..944c86c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-ui/compute-kind-widget-generated/kind-of-widget-fallback-input-search-text-border-right-width-001.html.ini
@@ -0,0 +1,3 @@ +[kind-of-widget-fallback-input-search-text-border-right-width-001.html] + expected: + if (product == "content_shell") and (os == "win") and (port == "win10.20h2"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-001-ref.html b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-001-ref.html new file mode 100644 index 0000000..5a9b5c0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-001-ref.html
@@ -0,0 +1,26 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Motion Path test: <coord-box> <border-box></title> +<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com"> + +<style> +#outer { + top: 100px; + left: 100px; + position: relative; + border-radius: 50%; + border: 5px solid black; + width: 600px; + height: 400px; +} +#box { + background-color: green; + transform: translate(483.441px, 19.1699px) rotate(37.2267deg); + width: 100px; + height: 100px; +} +</style> + +<div id="outer"> + <div id="box"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-001.html b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-001.html new file mode 100644 index 0000000..d90ddcf --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-001.html
@@ -0,0 +1,30 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Motion Path test ref: <coord-box> <border-box></title> +<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com"> +<link rel="match" href="offset-path-coord-box-001-ref.html"> +<link rel="help" href="https://drafts.fxtf.org/motion/#valdef-offset-path-coord-box"> + +<style> +#outer { + top: 100px; + left: 100px; + position: relative; + border-radius: 50%; + border: 5px solid black; + width: 600px; + height: 400px; +} +#box { + background-color: green; + position: relative; + offset-path: border-box; + offset-distance: 15%; + width: 100px; + height: 100px; +} +</style> + +<div id="outer"> + <div id="box"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-002-ref.html b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-002-ref.html new file mode 100644 index 0000000..4bd0025 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-002-ref.html
@@ -0,0 +1,25 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Motion Path test: <coord-box> <padding-box></title> +<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com"> + +<style> +#outer { + top: 100px; + left: 100px; + position: relative; + border: 5px solid black; + width: 600px; + height: 400px; +} +#box { + background-color: green; + transform: translate(250px, -50px); + width: 100px; + height: 100px; +} +</style> + +<div id="outer"> + <div id="box"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-002.html b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-002.html new file mode 100644 index 0000000..40499053 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-002.html
@@ -0,0 +1,29 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Motion Path test ref: <coord-box> <padding-box></title> +<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com"> +<link rel="match" href="offset-path-coord-box-002-ref.html"> +<link rel="help" href="https://drafts.fxtf.org/motion/#valdef-offset-path-coord-box"> + +<style> +#outer { + top: 100px; + left: 100px; + position: relative; + border: 5px solid black; + width: 600px; + height: 400px; +} +#box { + background-color: green; + position: relative; + offset-path: padding-box; + offset-distance: 15%; + width: 100px; + height: 100px; +} +</style> + +<div id="outer"> + <div id="box"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-003-ref.html b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-003-ref.html new file mode 100644 index 0000000..b8a7ea3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-003-ref.html
@@ -0,0 +1,26 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Motion Path test: <coord-box> <content-box></title> +<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com"> + +<style> +#outer { + top: 100px; + left: 100px; + position: relative; + border: 5px solid black; + padding: 10px; + width: 600px; + height: 400px; +} +#box { + background-color: green; + transform: translate(250px, -50px); + width: 100px; + height: 100px; +} +</style> + +<div id="outer"> + <div id="box"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-003.html b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-003.html new file mode 100644 index 0000000..99972fa --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/motion/offset-path-coord-box-003.html
@@ -0,0 +1,30 @@ +<!doctype html> +<meta charset="utf-8"> +<title>CSS Motion Path test ref: <coord-box> <content-box></title> +<link rel="author" title="Daniil Sakhapov" href="sakhapov@google.com"> +<link rel="match" href="offset-path-coord-box-003-ref.html"> +<link rel="help" href="https://drafts.fxtf.org/motion/#valdef-offset-path-coord-box"> + +<style> +#outer { + top: 100px; + left: 100px; + position: relative; + border: 5px solid black; + padding: 10px; + width: 600px; + height: 400px; +} +#box { + background-color: green; + position: relative; + offset-path: content-box; + offset-distance: 15%; + width: 100px; + height: 100px; +} +</style> + +<div id="outer"> + <div id="box"></div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-path-parsing-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-path-parsing-valid-expected.txt index 3a59485..1236ae3f 100644 --- a/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-path-parsing-valid-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/motion/parsing/offset-path-parsing-valid-expected.txt
@@ -22,7 +22,7 @@ PASS e.style['offset-path'] = "url(\"http://www.example.com/index.html#polyline1\")" should set the property value PASS e.style['offset-path'] = "circle(100px)" should set the property value FAIL e.style['offset-path'] = "margin-box" should set the property value assert_not_equals: property should be set got disallowed value "" -FAIL e.style['offset-path'] = "inset(10% 20% 30% 40%) border-box" should set the property value assert_not_equals: property should be set got disallowed value "" -FAIL e.style['offset-path'] = "fill-box ellipse(50% 60%)" should set the property value assert_not_equals: property should be set got disallowed value "" +PASS e.style['offset-path'] = "inset(10% 20% 30% 40%) border-box" should set the property value +FAIL e.style['offset-path'] = "fill-box ellipse(50% 60%)" should set the property value assert_equals: serialization should be canonical expected "ellipse(50% 60%) fill-box" but got "ellipse(50% 60% at 50% 50%) fill-box" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/fledge/tentative/fetch-ad-auction-headers-insecure-context.tentative.http.html.ini b/third_party/blink/web_tests/external/wpt/fledge/tentative/fetch-ad-auction-headers-insecure-context.tentative.http.html.ini new file mode 100644 index 0000000..b1bc8a1a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fledge/tentative/fetch-ad-auction-headers-insecure-context.tentative.http.html.ini
@@ -0,0 +1,3 @@ +[fetch-ad-auction-headers-insecure-context.tentative.http.html] + [test fetch(<url>, {adAuctionHeaders: true}) in insecure context] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/fullscreen/api/fullscreen-reordering.html.ini b/third_party/blink/web_tests/external/wpt/fullscreen/api/fullscreen-reordering.html.ini new file mode 100644 index 0000000..69921cad --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/fullscreen/api/fullscreen-reordering.html.ini
@@ -0,0 +1,6 @@ +[fullscreen-reordering.html] + expected: + if product == "chrome": TIMEOUT + [Requesting fullscreen on A, then B, then A] + expected: + if product == "chrome": TIMEOUT
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html.ini b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html.ini index 9dedda4..6db11119 100644 --- a/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html.ini +++ b/third_party/blink/web_tests/external/wpt/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.transfer.to.imagebitmap.w.html.ini
@@ -1,6 +1,6 @@ [offscreencanvas.transfer.to.imagebitmap.w.html] expected: - if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [OK, ERROR] + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): ERROR [Test that transferToImageBitmap returns an ImageBitmap with correct width and height in a worker] expected: if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-compositing-change.html.ini b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-compositing-change.html.ini new file mode 100644 index 0000000..30b696b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-img-element/image-compositing-change.html.ini
@@ -0,0 +1,2 @@ +[image-compositing-change.html] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-focus.html.ini b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-focus.html.ini index 7e6b73d..c23330f 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-focus.html.ini +++ b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-focus.html.ini
@@ -1,4 +1,12 @@ [popover-focus.html] + [Popover focus test: Opening dialogs as popovers should use dialog initial focus algorithm.] + expected: + if product == "chrome": FAIL + + [Popover focus test: Opening dialogs as popovers which have autofocus should focus the dialog.] + expected: + if product == "chrome": FAIL + [Popover focus test: autofocus child] expected: if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html index 3e0c6949..db491e9 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-hide-crash.html
@@ -1,5 +1,5 @@ <!DOCTYPE html> -<html class='reftest-wait'> +<html> <meta charset='utf-8' /> <title>Popover hide crash test</title> <link rel='author' href="mailto:cathiechen@iglaia.com">
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss.html b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss.html index 4411d0b..d7d1edd3 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss.html +++ b/third_party/blink/web_tests/external/wpt/html/semantics/popovers/popover-light-dismiss.html
@@ -9,6 +9,7 @@ <script src="/resources/testdriver.js"></script> <script src="/resources/testdriver-actions.js"></script> <script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/declarative-shadow-dom-polyfill.js"></script> <script src="resources/popover-utils.js"></script> <button id=b1t popovertarget='p1'>Popover 1</button> @@ -340,6 +341,7 @@ </template> </my-element> <script> + polyfill_declarative_shadow_dom(document.querySelector('#myElement')); const button7 = document.querySelector('#myElement').shadowRoot.querySelector('#b7'); const popover7 = document.querySelector('#myElement').shadowRoot.querySelector('#p7'); const inside7 = document.querySelector('#myElement').shadowRoot.querySelector('#inside7');
diff --git a/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html b/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html new file mode 100644 index 0000000..dd946e4 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html
@@ -0,0 +1,67 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="modulepreload" href="resources/module1.js?empty-string" as="" data-as=""> +<link rel="modulepreload" href="resources/module1.js?audio" as="audio" data-as="audio"> +<link rel="modulepreload" href="resources/module1.js?audioworklet" as="audioworklet" data-as="audioworklet"> +<link rel="modulepreload" href="resources/module1.js?document" as="document" data-as="document"> +<link rel="modulepreload" href="resources/module1.js?embed" as="embed" data-as="embed"> +<link rel="modulepreload" href="resources/module1.js?font" as="font" data-as="font"> +<link rel="modulepreload" href="resources/module1.js?frame" as="frame" data-as="frame"> +<link rel="modulepreload" href="resources/module1.js?iframe" as="iframe" data-as="iframe"> +<link rel="modulepreload" href="resources/module1.js?image" as="image" data-as="image"> +<link rel="modulepreload" href="resources/module1.js?manifest" as="manifest" data-as="manifest"> +<link rel="modulepreload" href="resources/module1.js?object" as="object" data-as="object"> +<link rel="modulepreload" href="resources/module1.js?paintworklet" as="paintworklet" data-as="paintworklet"> +<link rel="modulepreload" href="resources/module1.js?report" as="report" data-as="report"> +<link rel="modulepreload" href="resources/module1.js?script" as="script" data-as="script"> +<link rel="modulepreload" href="resources/module1.js?serviceworker" as="serviceworker" data-as="serviceworker"> +<link rel="modulepreload" href="resources/module1.js?sharedworker" as="sharedworker" data-as="sharedworker"> +<link rel="modulepreload" href="resources/module1.js?style" as="style" data-as="style"> +<link rel="modulepreload" href="resources/module1.js?track" as="track" data-as="track"> +<link rel="modulepreload" href="resources/module1.js?video" as="video" data-as="video"> +<link rel="modulepreload" href="resources/module1.js?webidentity" as="webidentity" data-as="webidentity"> +<link rel="modulepreload" href="resources/module1.js?worker" as="worker" data-as="worker"> +<link rel="modulepreload" href="resources/module1.js?xslt" as="xslt" data-as="xslt"> +<link rel="modulepreload" href="resources/module1.js?fetch" as="fetch" data-as="fetch"> +<link rel="modulepreload" href="resources/module1.js?invalid-dest" as="invalid-dest" data-as="invalid-dest"> +<link rel="modulepreload" href="resources/module1.js?iMaGe" as="iMaGe" data-as="iMaGe"> +<link rel="modulepreload" href="resources/module1.js?sCrIpT" as="sCrIpT" data-as="sCrIpT"> +<body> +<script> + // compared to modulepreload.html, this tests behavior when elements are + // initially on an HTML page instead of being added by JS + + const scriptLikes = [ + 'audioworklet', + 'paintworklet', + 'script', + 'serviceworker', + 'sharedworker', + 'worker', + ]; + + const goodAsValues = ['', 'invalid-dest', 'sCrIpT', ...scriptLikes]; + + for (const link of document.querySelectorAll('link')) { + const asValue = link.dataset.as; // don't depend on "as" attribute reflection + const good = goodAsValues.includes(asValue); + + // promise tests are queued sequentially, so create the promise here to + // ensure we don't miss the error event + const promise = new Promise((resolve, reject) => { + link.onload = good ? resolve : reject; + link.onerror = good ? reject : resolve; + }); + + promise_test(() => promise.then(() => { + const downloads = performance + .getEntriesByName(new URL(link.href, location.href)) + .filter(entry => entry.transferSize > 0) + .length; + assert_equals(downloads, good ? 1 : 0); + + }), `Modulepreload with as="${asValue}"`); + } +</script>
diff --git a/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html.ini b/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html.ini new file mode 100644 index 0000000..e0355a2d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/preload/modulepreload-as.html.ini
@@ -0,0 +1,210 @@ +[modulepreload-as.html] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac11"): [OK, TIMEOUT] + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): ERROR + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [OK, ERROR, TIMEOUT] + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): ERROR + if (product == "content_shell") and (os == "mac") and (port == "mac12"): [OK, ERROR, TIMEOUT] + if (product == "content_shell") and (os == "mac") and (port == "mac13"): [ERROR, OK] + if (product == "content_shell") and (os == "win") and (port == "win11"): TIMEOUT + [ERROR, TIMEOUT] + [Modulepreload with as=""] + expected: + if product == "chrome": [PASS, TIMEOUT] + + [Modulepreload with as="audio"] + expected: + if product == "chrome": [FAIL, NOTRUN] + FAIL + + [Modulepreload with as="audioworklet"] + expected: + if product == "chrome": [FAIL, NOTRUN] + FAIL + + [Modulepreload with as="document"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): [FAIL, PASS] + if (product == "content_shell") and (os == "linux") and (flag_specific == ""): [FAIL, PASS] + if (product == "content_shell") and (os == "win"): [FAIL, PASS] + if product == "chrome": [FAIL, NOTRUN, PASS] + FAIL + + [Modulepreload with as="embed"] + expected: + if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [FAIL, PASS] + if (product == "content_shell") and (os == "win"): [FAIL, PASS] + if product == "chrome": [FAIL, NOTRUN, PASS] + FAIL + + [Modulepreload with as="fetch"] + expected: + if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): PASS + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): PASS + if (product == "content_shell") and (os == "mac") and (port == "mac11"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): PASS + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [FAIL, PASS] + if product == "chrome": [PASS, NOTRUN] + [PASS, FAIL] + + [Modulepreload with as="font"] + expected: + if (product == "content_shell") and (os == "linux") and (flag_specific == ""): [PASS, FAIL] + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): [PASS, FAIL] + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL + if (product == "content_shell") and (os == "win"): [PASS, FAIL] + if product == "chrome": [FAIL, NOTRUN, PASS] + [FAIL, PASS] + + [Modulepreload with as="frame"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): PASS + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL] + if (product == "content_shell") and (os == "win"): [PASS, FAIL] + if product == "chrome": [PASS, FAIL, NOTRUN] + [FAIL, PASS] + + [Modulepreload with as="iMaGe"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac13"): [PASS, FAIL] + if (product == "content_shell") and (os == "mac") and (port == "mac11"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac12"): [PASS, FAIL] + if (product == "content_shell") and (os == "win"): [PASS, FAIL] + if product == "chrome": [PASS, NOTRUN, FAIL] + + [Modulepreload with as="iframe"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): PASS + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL] + if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL + if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL] + if (product == "content_shell") and (os == "win"): PASS + if product == "chrome": [PASS, NOTRUN, FAIL] + [FAIL, PASS] + + [Modulepreload with as="image"] + expected: + if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): PASS + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): PASS + if (product == "content_shell") and (os == "mac") and (port == "mac13"): [FAIL, PASS] + if product == "chrome": [PASS, NOTRUN] + [PASS, FAIL] + + [Modulepreload with as="invalid-dest"] + expected: + if product == "chrome": [FAIL, NOTRUN] + FAIL + + [Modulepreload with as="manifest"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac12"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): PASS + if (product == "content_shell") and (os == "mac") and (port == "mac13"): [FAIL, PASS] + if (product == "content_shell") and (os == "win"): PASS + if product == "chrome": [PASS, NOTRUN] + [PASS, FAIL] + + [Modulepreload with as="object"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL] + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac12"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac13"): [PASS, FAIL] + if product == "chrome": [PASS, NOTRUN] + + [Modulepreload with as="paintworklet"] + expected: + if product == "chrome": [FAIL, NOTRUN] + FAIL + + [Modulepreload with as="report"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac12"): [PASS, FAIL] + if (product == "content_shell") and (os == "mac") and (port == "mac13"): [PASS, FAIL] + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if product == "chrome": [PASS, NOTRUN] + + [Modulepreload with as="sCrIpT"] + expected: + if product == "chrome": [PASS, NOTRUN] + + [Modulepreload with as="script"] + expected: + if product == "chrome": [PASS, NOTRUN] + + [Modulepreload with as="serviceworker"] + expected: + if product == "chrome": [FAIL, NOTRUN] + FAIL + + [Modulepreload with as="sharedworker"] + expected: + if product == "chrome": [FAIL, NOTRUN] + FAIL + + [Modulepreload with as="style"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "linux") and (flag_specific == ""): [PASS, FAIL] + if product == "chrome": [FAIL, PASS, NOTRUN] + [FAIL, PASS] + + [Modulepreload with as="track"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): [PASS, FAIL] + if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL + if (product == "content_shell") and (os == "linux") and (flag_specific == "disable-site-isolation-trials"): [PASS, FAIL] + if (product == "content_shell") and (os == "linux") and (flag_specific == ""): [PASS, FAIL] + if product == "chrome": [PASS, FAIL, NOTRUN] + [FAIL, PASS] + + [Modulepreload with as="video"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac12"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac13"): FAIL + if product == "chrome": [PASS, FAIL, NOTRUN] + [PASS, FAIL] + + [Modulepreload with as="webidentity"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac13"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac11"): FAIL + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac12"): [FAIL, PASS] + if (product == "content_shell") and (os == "linux") and (flag_specific == ""): PASS + if product == "chrome": [PASS, NOTRUN] + [PASS, FAIL] + + [Modulepreload with as="worker"] + expected: + if product == "chrome": [FAIL, NOTRUN] + FAIL + + [Modulepreload with as="xslt"] + expected: + if (product == "content_shell") and (os == "mac") and (port == "mac11"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): PASS + if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac12"): [FAIL, PASS] + if (product == "content_shell") and (os == "mac") and (port == "mac13"): [FAIL, PASS] + if product == "chrome": [PASS, NOTRUN, FAIL] + [PASS, FAIL]
diff --git a/third_party/blink/web_tests/external/wpt/preload/modulepreload-expected.txt b/third_party/blink/web_tests/external/wpt/preload/modulepreload-expected.txt new file mode 100644 index 0000000..1cef0aff --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/preload/modulepreload-expected.txt
@@ -0,0 +1,28 @@ +This is a testharness.js-based test. +PASS link rel=modulepreload +PASS same-origin link rel=modulepreload crossorigin=anonymous +PASS same-origin link rel=modulepreload crossorigin=use-credentials +PASS cross-origin link rel=modulepreload +PASS cross-origin link rel=modulepreload crossorigin=anonymous +PASS cross-origin link rel=modulepreload crossorigin=use-credentials +PASS link rel=modulepreload with submodules +PASS link rel=modulepreload for a module with syntax error +PASS link rel=modulepreload for a module with network error +PASS link rel=modulepreload with bad href attribute +PASS link rel=modulepreload as=script +PASS link rel=modulepreload with non-script-like as= value (image) +PASS link rel=modulepreload with non-script-like as= value (xslt) +PASS link rel=modulepreload with integrity match +PASS link rel=modulepreload with integrity match2 +PASS link rel=modulepreload with integrity mismatch +PASS link rel=modulepreload with integrity mismatch2 +FAIL link rel=modulepreload with integrity mismatch3 promise_test: Unhandled rejection with value: object "[object Event]" +PASS multiple link rel=modulepreload with same href +PASS multiple link rel=modulepreload with child module before parent +PASS link rel=modulepreload with matching media +PASS link rel=modulepreload with non-matching media +PASS link rel=modulepreload with empty media +PASS link rel=modulepreload with empty href +PASS link rel=modulepreload with empty href and invalid as= value +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/preload/modulepreload-sri.html b/third_party/blink/web_tests/external/wpt/preload/modulepreload-sri.html new file mode 100644 index 0000000..ea32a6a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/preload/modulepreload-sri.html
@@ -0,0 +1,18 @@ +<!doctype html> +<meta charset=utf-8> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<link rel="modulepreload" href="resources/module1.js" integrity="sha384-invalid"> +<script type="module" src="resources/module1.js" id="myscript"></script> +<body> +<script> + // compared to modulepreload.html, this tests behavior when elements are + // initially on an HTML page instead of being added by JS + promise_test(() => { + return new Promise((resolve, reject) => { + let myscript = document.querySelector('#myscript'); + myscript.onerror = resolve; + myscript.onload = reject; + }); + }, "Script should not be loaded if modulepreload's integrity is invalid"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/preload/modulepreload.html b/third_party/blink/web_tests/external/wpt/preload/modulepreload.html index 0e4b692..bcd18c89 100644 --- a/third_party/blink/web_tests/external/wpt/preload/modulepreload.html +++ b/third_party/blink/web_tests/external/wpt/preload/modulepreload.html
@@ -33,6 +33,15 @@ }); } +function attachAndWaitForTimeout(element, t) { + return new Promise((resolve, reject) => { + element.onload = reject; + element.onerror = reject; + t.step_timeout(resolve, 1000); + document.body.appendChild(element); + }); +} + promise_test(function(t) { var link = document.createElement('link'); link.rel = 'modulepreload'; @@ -214,13 +223,21 @@ link.href = 'resources/module1.js?as-image'; link.as = 'image' return attachAndWaitForError(link); -}, 'link rel=modulepreload with invalid as= value'); +}, 'link rel=modulepreload with non-script-like as= value (image)'); + +promise_test(function(t) { + var link = document.createElement('link'); + link.rel = 'modulepreload'; + link.href = 'resources/module1.js?as-xslt'; + link.as = 'xslt' + return attachAndWaitForError(link); +}, 'link rel=modulepreload with non-script-like as= value (xslt)'); promise_test(function(t) { var link = document.createElement('link'); link.rel = 'modulepreload'; link.href = 'resources/module1.js?integrity-match'; - link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc=%' + link.integrity = 'sha256-+Ks3iNIiTq2ujlWhvB056cmXobrCFpU9hd60xZ1WCaA=' return attachAndWaitForLoad(link); }, 'link rel=modulepreload with integrity match'); @@ -228,7 +245,7 @@ var link = document.createElement('link'); link.rel = 'modulepreload'; link.href = 'resources/module1.mjs?integrity-match'; - link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc=%' + link.integrity = 'sha256-+Ks3iNIiTq2ujlWhvB056cmXobrCFpU9hd60xZ1WCaA=' return attachAndWaitForLoad(link); }, 'link rel=modulepreload with integrity match2'); @@ -240,5 +257,88 @@ return attachAndWaitForError(link); }, 'link rel=modulepreload with integrity mismatch'); +promise_test(function(t) { + var link = document.createElement('link'); + link.rel = 'modulepreload'; + link.href = 'resources/module1.mjs?integrity-doesnotmatch'; + link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc=' + return attachAndWaitForError(link); +}, 'link rel=modulepreload with integrity mismatch2'); + +promise_test(function(t) { + var link = document.createElement('link'); + link.rel = 'modulepreload'; + link.href = 'resources/module1.mjs?integrity-invalid'; + link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc=%' + return attachAndWaitForError(link); +}, 'link rel=modulepreload with integrity mismatch3'); + +promise_test(function(t) { + var link1 = document.createElement('link'); + var link2 = document.createElement('link'); + link1.rel = 'modulepreload'; + link2.rel = 'modulepreload'; + link1.href = 'resources/module1.js?same-url'; + link2.href = 'resources/module1.js?same-url'; + return Promise.all([ + attachAndWaitForLoad(link1), + attachAndWaitForLoad(link2), + ]); +}, 'multiple link rel=modulepreload with same href'); + +promise_test(function(t) { + var link1 = document.createElement('link'); + var link2 = document.createElement('link'); + link1.rel = 'modulepreload'; + link2.rel = 'modulepreload'; + link1.href = 'resources/module2.js?child-before'; + link2.href = 'resources/module1.js?child-before'; + return attachAndWaitForLoad(link1) + .then(() => attachAndWaitForLoad(link2)) + .then(() => new Promise(r => t.step_timeout(r, 1000))) + .then(() => { + verifyNumberOfDownloads('resources/module2.js?child-before', 1); + }); + +}, 'multiple link rel=modulepreload with child module before parent'); + +promise_test(function(t) { + var link = document.createElement('link'); + link.rel = 'modulepreload'; + link.href = 'resources/module1.mjs?matching-media'; + link.media = 'all'; + return attachAndWaitForLoad(link); +}, 'link rel=modulepreload with matching media'); + +promise_test(function(t) { + var link = document.createElement('link'); + link.rel = 'modulepreload'; + link.href = 'resources/module1.mjs?non-matching-media'; + link.media = 'not all'; + return attachAndWaitForTimeout(link, t); +}, 'link rel=modulepreload with non-matching media'); + +promise_test(function(t) { + var link = document.createElement('link'); + link.rel = 'modulepreload'; + link.href = 'resources/module1.mjs?empty-media'; + link.media = ''; + return attachAndWaitForLoad(link); +}, 'link rel=modulepreload with empty media'); + +promise_test(function(t) { + var link = document.createElement('link'); + link.rel = 'modulepreload'; + link.href = ''; + return attachAndWaitForTimeout(link, t); +}, 'link rel=modulepreload with empty href'); + +promise_test(function(t) { + var link = document.createElement('link'); + link.rel = 'modulepreload'; + link.href = ''; + link.as = 'fetch'; + return attachAndWaitForTimeout(link, t); +}, 'link rel=modulepreload with empty href and invalid as= value'); </script> </body>
diff --git a/third_party/blink/web_tests/external/wpt/preload/modulepreload.html.ini b/third_party/blink/web_tests/external/wpt/preload/modulepreload.html.ini new file mode 100644 index 0000000..fe059ec --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/preload/modulepreload.html.ini
@@ -0,0 +1,3 @@ +[modulepreload.html] + [link rel=modulepreload with integrity mismatch3] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/scroll-animations/css/printing/scroll-timeline-default-print.tentative.html.ini b/third_party/blink/web_tests/external/wpt/scroll-animations/css/printing/scroll-timeline-default-print.tentative.html.ini new file mode 100644 index 0000000..6da54ae --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/scroll-animations/css/printing/scroll-timeline-default-print.tentative.html.ini
@@ -0,0 +1,3 @@ +[scroll-timeline-default-print.tentative.html] + expected: + if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/prefetch.https.html.ini b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/prefetch.https.html.ini index a47b266..ef1c0dd 100644 --- a/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/prefetch.https.html.ini +++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prerender/prefetch.https.html.ini
@@ -1,6 +1,3 @@ [prefetch.https.html] - expected: - if product == "chrome": [OK, ERROR] - [Prerender navigation requests don't use prefetched results (for now)] - expected: - if product == "chrome": FAIL + [Prerender navigation requests should use prefetched results] + expected: FAIL
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/full-cycle-test.https.any.js.ini b/third_party/blink/web_tests/external/wpt/webcodecs/full-cycle-test.https.any.js.ini index 2bbc8fa..36fa0f32 100644 --- a/third_party/blink/web_tests/external/wpt/webcodecs/full-cycle-test.https.any.js.ini +++ b/third_party/blink/web_tests/external/wpt/webcodecs/full-cycle-test.https.any.js.ini
@@ -19,12 +19,12 @@ [full-cycle-test.https.any.html?h264_avc] expected: - if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): ERROR - if (product == "content_shell") and (os == "mac") and (port == "mac11"): ERROR - if (product == "content_shell") and (os == "mac") and (port == "mac12"): ERROR - if (product == "content_shell") and (os == "mac") and (port == "mac13"): ERROR - if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): ERROR if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): TIMEOUT + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): CRASH + if (product == "content_shell") and (os == "mac") and (port == "mac12"): CRASH + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): CRASH + if (product == "content_shell") and (os == "mac") and (port == "mac11"): CRASH + if (product == "content_shell") and (os == "mac") and (port == "mac13"): CRASH [Encoding and decoding cycle] expected: if (product == "content_shell") and (os == "mac"): FAIL @@ -58,11 +58,11 @@ [full-cycle-test.https.any.worker.html?h264_avc] expected: if (product == "content_shell") and (os == "mac") and (port == "mac10.15"): TIMEOUT - if (product == "content_shell") and (os == "mac") and (port == "mac11"): ERROR - if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): ERROR - if (product == "content_shell") and (os == "mac") and (port == "mac12"): ERROR - if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): ERROR - if (product == "content_shell") and (os == "mac") and (port == "mac13"): ERROR + if (product == "content_shell") and (os == "mac") and (port == "mac13-arm64"): CRASH + if (product == "content_shell") and (os == "mac") and (port == "mac11"): CRASH + if (product == "content_shell") and (os == "mac") and (port == "mac13"): CRASH + if (product == "content_shell") and (os == "mac") and (port == "mac12"): CRASH + if (product == "content_shell") and (os == "mac") and (port == "mac12-arm64"): CRASH [Encoding and decoding cycle] expected: if (product == "content_shell") and (os == "mac"): FAIL
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-storage-key.js b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-storage-key.js index a67b6d69..c27695b4 100644 --- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-storage-key.js +++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-storage-key.js
@@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {TestRunner} from 'test_runner'; +import {ApplicationTestRunner} from 'application_test_runner'; +import {ConsoleTestRunner} from 'console_test_runner'; + (async function() { TestRunner.addResult(`Validate IndexeddbModel clearForStorageKey\n`); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('application_test_runner'); + await TestRunner.loadLegacyModule('console'); // Note: every test that uses a storage API must manually clean-up state from previous tests. await ApplicationTestRunner.resetState(); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner'); + await TestRunner.loadLegacyModule('console'); await TestRunner.showPanel('resources'); const model = TestRunner.mainTarget.model(Resources.IndexedDBModel);
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-iframe-idb.js b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-iframe-idb.js index fb47a92..694f912 100644 --- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-iframe-idb.js +++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-iframe-idb.js
@@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {TestRunner} from 'test_runner'; +import {ApplicationTestRunner} from 'application_test_runner'; +import {ConsoleTestRunner} from 'console_test_runner'; + (async function() { TestRunner.addResult(`Tests Application Panel's handling of storages in iframes.\n`); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('application_test_runner'); + await TestRunner.loadLegacyModule('console'); // Note: every test that uses a storage API must manually clean-up state from previous tests. await ApplicationTestRunner.resetState(); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner'); + await TestRunner.loadLegacyModule('console'); await TestRunner.showPanel('resources'); function createIndexedDBInMainFrame(callback) {
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-on-navigation.js b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-on-navigation.js index 196e713..507c42bd 100644 --- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-on-navigation.js +++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-on-navigation.js
@@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {TestRunner} from 'test_runner'; +import {ApplicationTestRunner} from 'application_test_runner'; +import {ConsoleTestRunner} from 'console_test_runner'; + (async function() { TestRunner.addResult(`Tests Application Panel response to a main frame navigation.\n`); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('application_test_runner'); + await TestRunner.loadLegacyModule('console'); // Note: every test that uses a storage API must manually clean-up state from previous tests. await ApplicationTestRunner.resetState(); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner'); + await TestRunner.loadLegacyModule('console'); await TestRunner.showPanel('resources'); function createIndexedDB(callback) {
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-resource-preview.js b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-resource-preview.js index 46cc4327..af4a837 100644 --- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-resource-preview.js +++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-resource-preview.js
@@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {TestRunner} from 'test_runner'; +import {ApplicationTestRunner} from 'application_test_runner'; +import {ConsoleTestRunner} from 'console_test_runner'; + (async function() { TestRunner.addResult(`Tests Application Panel preview for resources of different types.\n`); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('application_test_runner'); + await TestRunner.loadLegacyModule('console'); // Note: every test that uses a storage API must manually clean-up state from previous tests. await ApplicationTestRunner.resetState(); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner'); + await TestRunner.loadLegacyModule('console'); await TestRunner.loadLegacyModule('source_frame'); await TestRunner.showPanel('resources'); await TestRunner.loadHTML(`
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-selection-on-reload.js b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-selection-on-reload.js index 4e4d0280..b68c5c00 100644 --- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-selection-on-reload.js +++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-selection-on-reload.js
@@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {TestRunner} from 'test_runner'; +import {ApplicationTestRunner} from 'application_test_runner'; +import {ConsoleTestRunner} from 'console_test_runner'; + (async function() { TestRunner.addResult(`Tests Application Panel response to a main frame navigation.\n`); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('application_test_runner'); + await TestRunner.loadLegacyModule('console'); // Note: every test that uses a storage API must manually clean-up state from previous tests. await ApplicationTestRunner.resetState(); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner'); + await TestRunner.loadLegacyModule('console'); await TestRunner.showPanel('resources'); function createIndexedDB(callback) {
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-websql.js b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-websql.js index 241d7c8..75c2f83c 100644 --- a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-websql.js +++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-websql.js
@@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {TestRunner} from 'test_runner'; +import {ApplicationTestRunner} from 'application_test_runner'; +import {ConsoleTestRunner} from 'console_test_runner'; + (async function() { TestRunner.addResult(`Tests Application Panel WebSQL support.\n`); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('application_test_runner'); + await TestRunner.loadLegacyModule('console'); // Note: every test that uses a storage API must manually clean-up state from previous tests. await ApplicationTestRunner.resetState(); - await TestRunner.loadLegacyModule('console'); await TestRunner.loadTestModule('console_test_runner'); + await TestRunner.loadLegacyModule('console'); await TestRunner.showPanel('resources'); await TestRunner.evaluateInPagePromise(` function parse(val) {
diff --git a/third_party/blink/web_tests/paint/markers/marker-invalidation-expected.html b/third_party/blink/web_tests/paint/markers/marker-invalidation-expected.html new file mode 100644 index 0000000..bb9d217c --- /dev/null +++ b/third_party/blink/web_tests/paint/markers/marker-invalidation-expected.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> +<style> + @font-face { + font-family: 'testFont'; + src: url('../../resources/opensans/OpenSans-Regular.woff') format("woff"); + } + + div { + width: 150px; + height: 30px; + font: 15px testFont; + } +</style> + +<div id="markAllSpelling">aaaaaaaaaa</div> +<div id="markNoSpelling">bbbbbbbbbb</div> + +<script> +function addSpellingMarker(elem, start, end) { + const range = document.createRange(); + const textNode = elem.firstChild; + range.setStart(textNode, start); + range.setEnd(textNode, end); + if (typeof internals !== 'undefined') + internals.setMarker(document, range, 'spelling'); +}; + +addSpellingMarker(markAllSpelling, 0, 10); +</script>
diff --git a/third_party/blink/web_tests/paint/markers/marker-invalidation.html b/third_party/blink/web_tests/paint/markers/marker-invalidation.html new file mode 100644 index 0000000..5c7efb0 --- /dev/null +++ b/third_party/blink/web_tests/paint/markers/marker-invalidation.html
@@ -0,0 +1,44 @@ +<!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> +<style> + @font-face { + font-family: 'testFont'; + src: url('../../resources/opensans/OpenSans-Regular.woff') format("woff"); + } + + div { + width: 150px; + height: 30px; + font: 15px testFont; + } +</style> + +<div id="markAllSpelling">aaaaaaaaaa</div> +<div id="markNoSpelling">bbbbbbbbbb</div> + +<script> +function addSpellingMarker(elem, start, end) { + const range = document.createRange(); + const textNode = elem.firstChild; + range.setStart(textNode, start); + range.setEnd(textNode, end); + if (typeof internals !== 'undefined') + internals.setMarker(document, range, 'spelling'); +}; + +function removeSpellingMarker(elem, start, end) { + const range = document.createRange(); + const textNode = elem.firstChild; + range.setStart(textNode, start); + range.setEnd(textNode, end); + if (typeof internals !== 'undefined') + internals.removeMarker(document, range, 'spelling'); +}; + +addSpellingMarker(markAllSpelling, 0, 10); +addSpellingMarker(markNoSpelling, 0, 10); + +onload = runAfterLayoutAndPaint(function() { + removeSpellingMarker(markNoSpelling, 0, 10); + }, true); +</script>
diff --git a/third_party/blink/web_tests/wpt_internal/dom/abort/abort-signal-any-internal.html.ini b/third_party/blink/web_tests/wpt_internal/dom/abort/abort-signal-any-internal.html.ini new file mode 100644 index 0000000..722ccc6 --- /dev/null +++ b/third_party/blink/web_tests/wpt_internal/dom/abort/abort-signal-any-internal.html.ini
@@ -0,0 +1,4 @@ +[abort-signal-any-internal.html] + [abort-signal-any-internal] + expected: + if product == "chrome": FAIL
diff --git a/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.https.any.js.ini b/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.https.any.js.ini index 47a1458..3e369f37 100644 --- a/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.https.any.js.ini +++ b/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.https.any.js.ini
@@ -1,4 +1,9 @@ [avc_encoder_config.https.any.html] + expected: + if (product == "content_shell") and (os == "linux"): OK + if (product == "content_shell") and (os == "win"): OK + if product == "chrome": OK + CRASH [Resolutions exceeding H.264 level are rejected] expected: FAIL @@ -10,6 +15,11 @@ [avc_encoder_config.https.any.worker.html] + expected: + if (product == "content_shell") and (os == "win"): OK + if (product == "content_shell") and (os == "linux"): OK + if product == "chrome": OK + CRASH [Resolutions exceeding H.264 level are rejected] expected: FAIL
diff --git a/third_party/puffin/BUILD.gn b/third_party/puffin/BUILD.gn index c60092a..8553b84 100644 --- a/third_party/puffin/BUILD.gn +++ b/third_party/puffin/BUILD.gn
@@ -33,7 +33,6 @@ static_library("libpuffpatch") { configs += [ ":target_defaults" ] - complete_static_lib = true deps = [ ":libpuffin-proto", "//base",
diff --git a/third_party/puffin/README.chromium b/third_party/puffin/README.chromium index 6877fad..9342a2b 100644 --- a/third_party/puffin/README.chromium +++ b/third_party/puffin/README.chromium
@@ -55,4 +55,6 @@ - Updating patching_unittest with zucchini v2 patches to fix broken tests. - missed one stream close in puffdiff.cc. - Making sure to call FindDeflateSubBlocks in PuffDiff to prepopulate deflate -subblocks. \ No newline at end of file +subblocks. +- Removing complete_static_lib = true from libpuffpatch to fix duplicate symbol +issue in nonembedded android component_updater. \ No newline at end of file
diff --git a/tools/android/dependency_analysis/generate_json_dependency_graph.py b/tools/android/dependency_analysis/generate_json_dependency_graph.py index 9c0df26..742aa671 100755 --- a/tools/android/dependency_analysis/generate_json_dependency_graph.py +++ b/tools/android/dependency_analysis/generate_json_dependency_graph.py
@@ -171,8 +171,6 @@ cache_path = _calculate_cache_path(filepath, src_path, build_output_dir) if (cache_path.exists() and cache_path.stat().st_mtime > filepath.stat().st_mtime): - logging.debug( - f'Found valid jdeps cache at {_relsrc(cache_path, src_path)}') with cache_path.open() as f: return f.read() @@ -181,12 +179,12 @@ f'Running jdeps and parsing output for {_relsrc(filepath, src_path)}') output = subprocess_utils.run_command([ str(jdeps_path), - '-R', '-verbose:class', '--multi-release', # Some jars support multiple JDK releases. 'base', str(filepath), ]) + logging.debug('Writing output to cache.') with cache_path.open('w') as f: f.write(output) return output
diff --git a/tools/clang/rewrite_templated_container_fields/RewriteTemplatedPtrFields.cpp b/tools/clang/rewrite_templated_container_fields/RewriteTemplatedPtrFields.cpp index 4ef9309..67573ae3 100644 --- a/tools/clang/rewrite_templated_container_fields/RewriteTemplatedPtrFields.cpp +++ b/tools/clang/rewrite_templated_container_fields/RewriteTemplatedPtrFields.cpp
@@ -214,13 +214,16 @@ if (const auto* ptr = BoundNodesView.getNodeAs<clang::FunctionDecl>("fct_decl")) { fct_decl_ = BoundNodesView.getNodeAs<clang::FunctionDecl>("fct_decl"); + is_lambda_ = false; } else { const clang::LambdaExpr* lambda_expr = BoundNodesView.getNodeAs<clang::LambdaExpr>("lambda_expr"); fct_decl_ = lambda_expr->getCallOperator(); + is_lambda_ = true; } } const clang::FunctionDecl* fct_decl_; + bool is_lambda_; }; // This is used to map arguments passed to std::make_unique to the underlying @@ -297,12 +300,25 @@ LocalVisitor l; arg_matches.visitMatches(&l); const auto* fct_decl = l.fct_decl_; - if (fct_decl->getNumParams() != num_args - 1) { - return false; - } - // i-1 because we start with second arg for Bind and first arg for + + // start_index=1 when we start with second arg for Bind and first arg for // lambda/fct - const auto* param = fct_decl->getParamDecl(i - 1); + unsigned start_index = 1; + // start_index=2 when the second arg is a pointer to the object on which + // the function is to be invoked. This is done when the function pointer is + // not a static class function. + // isGlobal is true for free functions as well as static member functions, + // both of which don't need a pointer to the object on which they are + // invoked. + if (!l.is_lambda_ && !l.fct_decl_->isGlobal()) { + start_index = 2; + // Skip the second argument passed to BindOnce/BindRepeating as it is an + // object pointer unrelated to target function args. + if (i == 1) { + continue; + } + } + const auto* param = fct_decl->getParamDecl(i - start_index); clang::ast_matchers::internal::BoundNodesTreeBuilder parm_var_decl_matches(arg_matches); if (parm_var_decl_matcher.matches(*param, Finder,
diff --git a/tools/clang/rewrite_templated_container_fields/tests/bind-tests-expected.cc b/tools/clang/rewrite_templated_container_fields/tests/bind-tests-expected.cc index ab0e6281..58b4e89b 100644 --- a/tools/clang/rewrite_templated_container_fields/tests/bind-tests-expected.cc +++ b/tools/clang/rewrite_templated_container_fields/tests/bind-tests-expected.cc
@@ -24,7 +24,7 @@ } } - void fct() { BindOnce(&s::do_something, member); } + void fct() { BindOnce(&s::do_something, this, member); } // Expected rewrite: std::vector<raw_ptr<int>> member; std::vector<raw_ptr<int>> member;
diff --git a/tools/clang/rewrite_templated_container_fields/tests/bind-tests-original.cc b/tools/clang/rewrite_templated_container_fields/tests/bind-tests-original.cc index 2fbe238..b48664a 100644 --- a/tools/clang/rewrite_templated_container_fields/tests/bind-tests-original.cc +++ b/tools/clang/rewrite_templated_container_fields/tests/bind-tests-original.cc
@@ -22,7 +22,7 @@ } } - void fct() { BindOnce(&s::do_something, member); } + void fct() { BindOnce(&s::do_something, this, member); } // Expected rewrite: std::vector<raw_ptr<int>> member; std::vector<int*> member;
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 97de090..1165210 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -26851,6 +26851,26 @@ <description>Please enter the description of this user action.</description> </action> +<action name="PaymentsUserAuthSuccessfulForMandatoryAuthToggle"> + <owner>koulvipul@google.com</owner> + <owner>vinnypersky@google.com</owner> + <owner>sujiezhu@google.com</owner> + <description> + Recorded when user completes a successful auth after trying to change the + mandatory auth toggle in the chrome://settings/payments page. + </description> +</action> + +<action name="PaymentsUserAuthTriggeredForMandatoryAuthToggle"> + <owner>koulvipul@google.com</owner> + <owner>vinnypersky@google.com</owner> + <owner>sujiezhu@google.com</owner> + <description> + Recorded when user is asked for an auth after trying to change the mandatory + auth toggle in the chrome://settings/payments page. + </description> +</action> + <action name="PDF.FitToHeightButton"> <obsolete>Removed with Out of Process PDF (issue 303491)</obsolete> <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index c673c8d..2f49050 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -32968,6 +32968,21 @@ <int value="2" label="Failure encoding the profile id."/> </enum> +<enum name="EnterpriseReportingEventType"> + <int value="0" label="Unknown event"/> + <int value="1" label="Password reuse event"/> + <int value="2" label="Password changed event"/> + <int value="3" label="Dangerous download event"/> + <int value="4" label="Interstitial event"/> + <int value="5" label="Sensitive data event"/> + <int value="6" label="Unscanned file event"/> + <int value="7" label="Login event"/> + <int value="8" label="Password breach event"/> + <int value="9" label="URL filtering interstitial event"/> + <int value="10" label="Extension install event"/> + <int value="11" label="Browser crash event"/> +</enum> + <enum name="EnterpriseRetrievePolicyResponseType"> <obsolete> Removed in M91 since the data is no longer monitored. @@ -36086,6 +36101,8 @@ <int value="1784" label="ENTERPRISE_REMOTEAPPS_SETPINNEDAPPS"/> <int value="1785" label="SMARTCARDPROVIDERPRIVATE_REPORTDATARESULT"/> <int value="1786" label="FILEMANAGERPRIVATE_CALCULATEBULKPINREQUIREDSPACE"/> + <int value="1787" + label="AUTOFILLPRIVATE_AUTHENTICATEUSERANDFLIPMANDATORYAUTHTOGGLE"/> </enum> <enum name="ExtensionIconState"> @@ -54623,24 +54640,10 @@ <int value="2" label="Subresource"/> </enum> -<enum name="IsolatedWebAppReadIntegrityBlockAndMetadataStatus"> - <int value="0" label="Success"/> - <int value="1" label="Error: Integrity Block parsing: Internal error"/> - <int value="2" label="Error: Integrity Block parsing: Format error"/> - <int value="3" label="Error: Integrity Block parsing: Version error"/> - <int value="4" label="Error: Integrity Block validation error"/> - <int value="5" label="Error: Signature verification error"/> - <int value="6" label="Error: Metadata parsing: Internal error"/> - <int value="7" label="Error: Metadata parsing: Format error"/> - <int value="8" label="Error: Metadata parsing: Version error"/> - <int value="9" label="Error: Metadata validation error"/> -</enum> - -<enum name="IsolatedWebAppReadResponseHeadStatus"> - <int value="0" label="Success"/> - <int value="1" label="Error: Response head parsing: Internal error"/> - <int value="2" label="Error: Response head parsing: Format error"/> - <int value="3" label="Error: Response not found"/> +<enum name="IsolatedWebAppReadResponseHeadError"> + <int value="1" label="Response head parsing: Internal error"/> + <int value="2" label="Response head parsing: Format error"/> + <int value="3" label="Response not found"/> </enum> <enum name="IsolatedWebAppResponseReaderCacheState"> @@ -54651,6 +54654,18 @@ metadata"/> </enum> +<enum name="IsolatedWebAppSwbnFileUsabilityError"> + <int value="1" label="Integrity Block parsing: Internal error"/> + <int value="2" label="Integrity Block parsing: Format error"/> + <int value="3" label="Integrity Block parsing: Version error"/> + <int value="4" label="Integrity Block validation error"/> + <int value="5" label="Signature verification error"/> + <int value="6" label="Metadata parsing: Internal error"/> + <int value="7" label="Metadata parsing: Format error"/> + <int value="8" label="Metadata parsing: Version error"/> + <int value="9" label="Metadata validation error"/> +</enum> + <enum name="IsPinnedToTaskbarResult"> <int value="0" label="Not pinned"/> <int value="1" label="Pinned"/> @@ -59648,6 +59663,7 @@ <int value="-1490298774" label="enable-captive-portal-bypass-proxy-option"/> <int value="-1490048536" label="PageVisibilityPageContentAnnotations:disabled"/> + <int value="-1489518120" label="PasswordGenerationExperiment:disabled"/> <int value="-1488867232" label="PageInfoAboutThisSiteNonEn:disabled"/> <int value="-1488744539" label="QuickUnlockFingerprint:enabled"/> <int value="-1488329159" label="ScreenAI:enabled"/> @@ -60311,6 +60327,7 @@ <int value="-1159154050" label="FilesSinglePartitionFormat:enabled"/> <int value="-1159151875" label="RecordWebAppDebugInfo:disabled"/> <int value="-1158993534" label="PrintScaling:enabled"/> + <int value="-1157991559" label="CloudApAuthAttachAsHeader:enabled"/> <int value="-1156950420" label="CryptAuthV2DeviceActivityStatusUseConnectivity:enabled"/> <int value="-1156179600" label="OmniboxRichEntitySuggestions:enabled"/> @@ -60909,6 +60926,7 @@ <int value="-839544057" label="WebRtcCombinedNetworkAndWorkerThread:enabled"/> <int value="-838719204" label="ForceMajorVersionInMinorPositionInUserAgent:disabled"/> + <int value="-838419212" label="CloudApAuthAttachAsHeader:disabled"/> <int value="-837650216" label="DisableCryptAuthV1DeviceSync:disabled"/> <int value="-837473047" label="AutofillEnableStickyPaymentsBubble:disabled"/> <int value="-836123854" label="wallet-service-use-sandbox"/> @@ -64760,6 +64778,7 @@ <int value="1246486472" label="SafeBrowsingPasswordCheckIntegrationForSavedPasswordsAndroid:disabled"/> <int value="1247293682" label="topchrome-md"/> + <int value="1247309454" label="PasswordGenerationExperiment:enabled"/> <int value="1248222772" label="ZeroCopyTabCapture:disabled"/> <int value="1248486441" label="LauncherOmniboxPublishLogicLog:disabled"/> <int value="1249215617" label="SelectToSpeakNavigationControl:enabled"/>
diff --git a/tools/metrics/histograms/histograms_index.txt b/tools/metrics/histograms/histograms_index.txt index e11b4020..70fbbb9 100644 --- a/tools/metrics/histograms/histograms_index.txt +++ b/tools/metrics/histograms/histograms_index.txt
@@ -141,7 +141,6 @@ tools/metrics/histograms/metadata/update_engine/histograms.xml tools/metrics/histograms/metadata/v8/histograms.xml tools/metrics/histograms/metadata/variations/histograms.xml -tools/metrics/histograms/metadata/video_tutorials/histograms.xml tools/metrics/histograms/metadata/views/histograms.xml tools/metrics/histograms/metadata/web_apk/histograms.xml tools/metrics/histograms/metadata/web_audio/histograms.xml
diff --git a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS index 2b8d35a..7430c02 100644 --- a/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS +++ b/tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS
@@ -17,6 +17,7 @@ # arc mhasank@chromium.org batoon@google.com +youkichihosoi@chromium.org # ash_clipboard ckincaid@chromium.org dmblack@google.com @@ -394,9 +395,6 @@ poromov@chromium.org # v8 mlippautz@chromium.org -# video_tutorials -qinmin@chromium.org -shaktisahu@chromium.org # web_apk eirage@chromium.org hartmanng@chromium.org
diff --git a/tools/metrics/histograms/metadata/arc/OWNERS b/tools/metrics/histograms/metadata/arc/OWNERS index 4c2da61c..27669c2 100644 --- a/tools/metrics/histograms/metadata/arc/OWNERS +++ b/tools/metrics/histograms/metadata/arc/OWNERS
@@ -4,3 +4,4 @@ # Use chromium-metrics-reviews@google.com as a backup. mhasank@chromium.org batoon@google.com +youkichihosoi@chromium.org
diff --git a/tools/metrics/histograms/metadata/chromeos/histograms.xml b/tools/metrics/histograms/metadata/chromeos/histograms.xml index c6702a9..3661bb9 100644 --- a/tools/metrics/histograms/metadata/chromeos/histograms.xml +++ b/tools/metrics/histograms/metadata/chromeos/histograms.xml
@@ -1317,6 +1317,7 @@ <variant name="Audio"/> <variant name="BatteryLife"/> <variant name="General"/> + <variant name="GeneralCamera"/> <variant name="Performance"/> <variant name="Stability"/> </token>
diff --git a/tools/metrics/histograms/metadata/data/histograms.xml b/tools/metrics/histograms/metadata/data/histograms.xml index 02487a4..1ea3fe36 100644 --- a/tools/metrics/histograms/metadata/data/histograms.xml +++ b/tools/metrics/histograms/metadata/data/histograms.xml
@@ -145,8 +145,9 @@ </histogram> <histogram name="DataUse.AppTabState" units="bytes" expires_after="2023-05-07"> - <owner>rajendrant@chromium.org</owner> - <owner>mcrouse@chromium.org</owner> + <owner>spelchat@chromium.org</owner> + <owner>curranmax@chromium.org</owner> + <owner>chrome-brapp-loading@google.com</owner> <summary> Records the data use of Chrome user traffic by the foregound vs. background state of the app and tab. @@ -155,6 +156,9 @@ <histogram name="DataUse.BackgroundToDataRecievedPerByte" units="ms" expires_after="2021-12-20"> + <obsolete> + Obsoleted. + </obsolete> <owner>rajendrant@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -166,6 +170,9 @@ <histogram name="DataUse.BackgroundToFirstDownstream" units="ms" expires_after="2021-12-20"> + <obsolete> + Obsoleted. + </obsolete> <owner>rajendrant@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -194,6 +201,7 @@ <owner>curranmax@chromium.org</owner> <owner>ryansturm@chromium.org</owner> <owner>spelchat@chromium.org</owner> + <owner>chrome-brapp-loading@google.com</owner> <summary> Count of total bytes received by the Chrome on the network, as reported by the network delegate. This is recorded when requests complete. @@ -204,8 +212,9 @@ <obsolete> Obsoleted. </obsolete> - <owner>rajendrant@chromium.org</owner> - <owner>mcrouse@chromium.org</owner> + <owner>spelchat@chromium.org</owner> + <owner>curranmax@chromium.org</owner> + <owner>chrome-brapp-loading@google.com</owner> <summary> Count of total bytes sent by the Chrome on the network. With network servicification this is recorded when requests complete. @@ -217,6 +226,7 @@ <owner>curranmax@chromium.org</owner> <owner>ryansturm@chromium.org</owner> <owner>spelchat@chromium.org</owner> + <owner>chrome-brapp-loading@google.com</owner> <summary> Count of total bytes sent by the Chrome on the network, as reported by the network delegate. With network servicification this is recorded when @@ -226,8 +236,9 @@ <histogram name="DataUse.ContentType.UserTrafficKB" enum="DataUseContentType" expires_after="2023-03-05"> - <owner>rajendrant@chromium.org</owner> - <owner>mcrouse@chromium.org</owner> + <owner>spelchat@chromium.org</owner> + <owner>curranmax@chromium.org</owner> + <owner>chrome-brapp-loading@google.com</owner> <summary> Data use of user traffic by different content types. Recorded in KB when network bytes are received by Chrome. @@ -236,6 +247,9 @@ <histogram name="DataUse.FavIcon.Downstream" units="bytes" expires_after="2021-12-20"> + <obsolete> + Obsoleted. + </obsolete> <owner>rajendrant@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -247,6 +261,9 @@ <histogram name="DataUse.FavIcon.Downstream.Non200Response" units="bytes" expires_after="2021-12-20"> + <obsolete> + Obsoleted. + </obsolete> <owner>rajendrant@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -257,6 +274,9 @@ <histogram name="DataUse.PageTransition.UserTrafficKB" enum="DataUsePageTransition" expires_after="2021-12-20"> + <obsolete> + Obsoleted. + </obsolete> <owner>rajendrant@chromium.org</owner> <owner>mcrouse@chromium.org</owner> <summary> @@ -266,9 +286,10 @@ </histogram> <histogram name="DataUse.TrafficSize.User" units="bytes" - expires_after="2023-05-07"> - <owner>rajendrant@chromium.org</owner> - <owner>mcrouse@chromium.org</owner> + expires_after="2024-05-07"> + <owner>spelchat@chromium.org</owner> + <owner>curranmax@chromium.org</owner> + <owner>chrome-brapp-loading@google.com</owner> <summary> The total amount of data use of Chrome for user traffic. This traffic has content::ResourceRequestInfo attached to its request. If the OS is not
diff --git a/tools/metrics/histograms/metadata/dev/histograms.xml b/tools/metrics/histograms/metadata/dev/histograms.xml index 37736fa..96b2368 100644 --- a/tools/metrics/histograms/metadata/dev/histograms.xml +++ b/tools/metrics/histograms/metadata/dev/histograms.xml
@@ -335,16 +335,6 @@ </summary> </histogram> -<histogram name="DevTools.MutatingHttpAction" - enum="DevToolsMutatingHttpActionVerb" expires_after="2023-05-07"> - <owner>dsv@chromium.org</owner> - <owner>caseq@chromium.org</owner> - <summary> - Records the invocation of actions like /json/new on the HTTP server exposed - with running with --remote-debugging-port. - </summary> -</histogram> - <histogram name="DevTools.NetworkPanelResponsePreviewOpened" enum="DevToolsMediaType" expires_after="2023-12-31"> <owner>yangguo@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/enterprise/histograms.xml b/tools/metrics/histograms/metadata/enterprise/histograms.xml index e56995ae..60e76a2 100644 --- a/tools/metrics/histograms/metadata/enterprise/histograms.xml +++ b/tools/metrics/histograms/metadata/enterprise/histograms.xml
@@ -2441,6 +2441,28 @@ </summary> </histogram> +<histogram name="Enterprise.ReportingEventUploadFailure" + enum="EnterpriseReportingEventType" expires_after="2024-06-01"> + <owner>xanth@google.com</owner> + <owner>alshawwa@chromium.org</owner> + <owner>domfc@chromium.org</owner> + <summary> + Failures to upload reporting events to the reporting server bucketed by + event type. + </summary> +</histogram> + +<histogram name="Enterprise.ReportingEventUploadSuccess" + enum="EnterpriseReportingEventType" expires_after="2024-06-01"> + <owner>xanth@google.com</owner> + <owner>alshawwa@chromium.org</owner> + <owner>domfc@chromium.org</owner> + <summary> + Reporting events successfully uploaded to the reporting server bucketed by + event type. + </summary> +</histogram> + <histogram name="Enterprise.SecondaryGoogleAccountUsage.PolicyFetch.ResponseLatency" units="ms" expires_after="2023-10-04">
diff --git a/tools/metrics/histograms/metadata/password/histograms.xml b/tools/metrics/histograms/metadata/password/histograms.xml index 5fdf6f555..8986332 100644 --- a/tools/metrics/histograms/metadata/password/histograms.xml +++ b/tools/metrics/histograms/metadata/password/histograms.xml
@@ -1083,6 +1083,27 @@ <summary>Error encountered during the password bulk check.</summary> </histogram> +<histogram name="PasswordManager.BulkCheck.InsecureCredentials.Count" + units="credentials" expires_after="2023-11-01"> + <owner>eic@google.com</owner> + <owner>noemies@google.com</owner> + <summary> + Count of unique pairs of username-password present in a compromised, weak or + reused credential warning. Recorded after every successful password check. + </summary> +</histogram> + +<histogram name="PasswordManager.BulkCheck.InsecureCredentials.Unmuted.Count" + units="credentials" expires_after="2023-11-01"> + <owner>eic@google.com</owner> + <owner>noemies@google.com</owner> + <summary> + Count of unique pairs of username-password present in a compromised, weak or + reused credential warning not muted by the user. Recorded after every + successful password check. + </summary> +</histogram> + <histogram name="PasswordManager.BulkCheck.LeaksFound" units="credentials" expires_after="2023-09-10"> <owner>vasilii@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/power/histograms.xml b/tools/metrics/histograms/metadata/power/histograms.xml index e51cbcd1..43cedde 100644 --- a/tools/metrics/histograms/metadata/power/histograms.xml +++ b/tools/metrics/histograms/metadata/power/histograms.xml
@@ -23,7 +23,7 @@ <histograms> <variants name="AdaptiveChargingType"> -<!-- +<!-- Variants describing the type of charging used to charge to full once the hold percent is reached in Adaptive Charging. --> @@ -911,18 +911,31 @@ </summary> </histogram> +<histogram name="Power.BatteryDischargeMode5.TenMinutes" + enum="BatteryDischargeMode" expires_after="2024-03-31"> + <owner>pmonette@chromium.org</owner> + <owner>fdoray@chromium.org</owner> + <summary> + Battery discharge mode describing whether + Power.BatteryDischargeRateMilliwatts6.TenMinutes could be reported, and why. + Windows only. + + This is reported when a 1 minute periodic timer fires and at least 10 + minutes have elapsed since the last report or startup. + </summary> +</histogram> + <histogram name="Power.BatteryDischargeMode5{UsageScenario}{IntervalType}" enum="BatteryDischargeMode" expires_after="2024-03-31"> <owner>etiennep@chromium.org</owner> <owner>olivierli@chromium.org</owner> <summary> - Battery discharge mode describing whether BatteryDischargeRateMilliwatts5 - could be reported or not, and why. + Battery discharge mode describing whether + Power.BatteryDischargeRateMilliwatts6 could be reported, and why. - This is reported at the end of every valid 1 minute interval. An invalid - interval is one that deviate too much from 1 minute, which can be caused by - the computer going to sleep, or the OS sending multiple notifications in a - row. + On Windows and ChromeOS, this is reported when a 1 minute periodic timer + fires. On macOS, this is reported when an IOPMPowerSource state change + notification fires (typically every minute but may happen more frequently). This is recorded for {UsageScenario}. @@ -942,6 +955,22 @@ </summary> </histogram> +<histogram name="Power.BatteryDischargeRateMilliwatts6.TenMinutes" + units="milliwatts" expires_after="2024-03-31"> + <owner>pmonette@chromium.org</owner> + <owner>fdoray@chromium.org</owner> + <summary> + Battery discharge in milliwatts over a 10 minutes interval. Windows only. + + Example: Used capacity at the beginning of the interval: 1000 mWh, used + capacity at the end of the interval: 1010 mWh, Discharge: (1010-1000) = 10 + mWh per 10 minutes, reported value: 60 mW. + + Reported when "discharging" is reported to + Power.BatteryDischargeMode5.TenMinutes. + </summary> +</histogram> + <histogram name="Power.BatteryDischargeRateMilliwatts6{UsageScenario}{IntervalType}" units="milliwatts" expires_after="2024-03-31"> @@ -949,14 +978,14 @@ <owner>olivierli@chromium.org</owner> <owner>lgrey@chromium.org</owner> <summary> - Battery discharge in milliwatts, example: - Used capacity at the beginning - of the interval: 1000 mWh; - Used capacity at the end of the interval: 1010 - mWh; - Discharge: (1010-1000) = 10 mWh per minute - Reported value: 600 mW. + Battery discharge in milliwatts over a 1 minute interval. - This is reported at the end of every valid 1 minute interval. An invalid - interval is one that deviate too much from 1 minute, which can be caused by - the computer going to sleep, or the OS sending multiple notifications in a - row. + Example: Used capacity at the beginning of the interval: 1000 mWh, used + capacity at the end of the interval: 1010 mWh, Discharge: (1010-1000) = 10 + mWh per 1 minute, reported value: 600 mW. + + Reported when "discharging" is reported to + Power.BatteryDischargeMode5. This is recorded for {UsageScenario}.
diff --git a/tools/metrics/histograms/metadata/settings/histograms.xml b/tools/metrics/histograms/metadata/settings/histograms.xml index 0bed0db..26937b5 100644 --- a/tools/metrics/histograms/metadata/settings/histograms.xml +++ b/tools/metrics/histograms/metadata/settings/histograms.xml
@@ -632,6 +632,45 @@ </summary> </histogram> +<histogram + name="Settings.SafetyCheck.UnusedSitePermissionsRegrantDays{SourceUI}.All" + units="days" expires_after="2023-12-21"> + <owner>sideyilmaz@chromium.org</owner> + <owner>tov@chromium.org</owner> + <owner>msramek@chromium.org</owner> + <summary> + Captures the number of days since the permission was revoked for any + permission type, up until the cleanup threshold for revoked permissions has + been reached. The metric is recorded when the user regrants a permission + that was previously revoked by the unused site permission module of + SafetyCheck. + </summary> + <token key="SourceUI"> + <variant name="Prompt"/> + <variant name="Settings"/> + </token> +</histogram> + +<histogram + name="Settings.SafetyCheck.UnusedSitePermissionsRegrantDays{SourceUI}.{PermissionType}" + units="days" expires_after="2023-12-21"> + <owner>sideyilmaz@chromium.org</owner> + <owner>tov@chromium.org</owner> + <owner>msramek@chromium.org</owner> + <summary> + Captures the number of days since the permission was revoked for the + {PermissionType} permission type, up until the cleanup threshold for revoked + permissions has been reached. The metric is recorded when the user regrants + a permission that was previously revoked by the unused site permission + module of SafetyCheck. + </summary> + <token key="PermissionType" variants="AllPermissionTypes"/> + <token key="SourceUI"> + <variant name="Prompt"/> + <variant name="Settings"/> + </token> +</histogram> + <histogram name="Settings.SafetyCheck.UpdatesResult" enum="SafetyCheckUpdateStatus" expires_after="2023-04-23"> <owner>andzaytsev@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/sync/histograms.xml b/tools/metrics/histograms/metadata/sync/histograms.xml index 68c700a..bb6077c 100644 --- a/tools/metrics/histograms/metadata/sync/histograms.xml +++ b/tools/metrics/histograms/metadata/sync/histograms.xml
@@ -896,7 +896,7 @@ </histogram> <histogram name="Sync.ModelTypeInitialUpdateReceived" enum="SyncModelTypes" - expires_after="2023-06-18"> + expires_after="2024-04-16"> <owner>rushans@google.com</owner> <owner>mastiz@chromium.org</owner> <component>Services>Sync</component>
diff --git a/tools/metrics/histograms/metadata/tab/histograms.xml b/tools/metrics/histograms/metadata/tab/histograms.xml index d48128c..1edb1ee 100644 --- a/tools/metrics/histograms/metadata/tab/histograms.xml +++ b/tools/metrics/histograms/metadata/tab/histograms.xml
@@ -526,6 +526,16 @@ </summary> </histogram> +<histogram name="TabGroups.SavedTabGroupAge" units="minutes" + expires_after="2023-12-27"> + <owner>dljames@chromium.org</owner> + <owner>chrome-desktop-ui-sea@google.com</owner> + <summary> + Records once an hour once the SavedTabGroupKeyedService is instantiated. + Tracks the age of a SavedTabGroup (since creation). + </summary> +</histogram> + <histogram name="TabGroups.SavedTabGroupCount" units="groups" expires_after="2023-12-27"> <owner>dljames@chromium.org</owner> @@ -536,6 +546,16 @@ </summary> </histogram> +<histogram name="TabGroups.SavedTabGroupLifespan" units="minutes" + expires_after="2023-12-27"> + <owner>dljames@chromium.org</owner> + <owner>chrome-desktop-ui-sea@google.com</owner> + <summary> + Records when a SavedTabGroup is deleted. Tracks the total age / lifespan of + a SavedTabGroup (since creation) once deleted. + </summary> +</histogram> + <histogram name="TabGroups.SavedTabGroupTabCount" units="tabs" expires_after="2023-12-27"> <owner>dljames@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/video_tutorials/OWNERS b/tools/metrics/histograms/metadata/video_tutorials/OWNERS deleted file mode 100644 index 66926bc..0000000 --- a/tools/metrics/histograms/metadata/video_tutorials/OWNERS +++ /dev/null
@@ -1,6 +0,0 @@ -per-file OWNERS=file://tools/metrics/histograms/metadata/METRIC_REVIEWER_OWNERS - -# Prefer sending CLs to the owners listed below. -# Use chromium-metrics-reviews@google.com as a backup. -qinmin@chromium.org -shaktisahu@chromium.org
diff --git a/tools/metrics/histograms/metadata/video_tutorials/histograms.xml b/tools/metrics/histograms/metadata/video_tutorials/histograms.xml deleted file mode 100644 index 93c7170..0000000 --- a/tools/metrics/histograms/metadata/video_tutorials/histograms.xml +++ /dev/null
@@ -1,92 +0,0 @@ -<!-- -Copyright 2020 The Chromium Authors -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<!-- -This file is used to generate a comprehensive list of histograms -related to video tutorials along with a detailed description for each histogram. - -For best practices on writing histogram descriptions, see -https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md - -Please follow the instructions in the OWNERS file in this directory to find a -reviewer. If no OWNERS file exists, please consider signing up at -go/reviewing-metrics (Googlers only), as all subdirectories are expected to -have an OWNERS file. As a last resort you can send the CL to -chromium-metrics-reviews@google.com. ---> - -<histogram-configuration> - -<histograms> - -<variants name="VideoTutorialFeatureTopic"> - <variant name="ChromeIntro"/> - <variant name="Download"/> - <variant name="Search"/> - <variant name="Summary"/> - <variant name="Unknown"/> - <variant name="VoiceSearch"/> -</variants> - -<histogram name="VideoTutorials.LanguagePicker.Action" - enum="VideoTutorials.LanguagePickerAction" expires_after="2022-08-07"> - <owner>shaktisahu@chromium.org</owner> - <owner>chrome-upboarding-eng@google.com</owner> - <summary> - Recorded whenever the user interacts with the video player language picker - UI. Records various user actions such as language selection, back press, or - dismiss actions. - </summary> -</histogram> - -<histogram name="VideoTutorials.LanguagePicker.LanguageSelected" - units="position" expires_after="2022-08-28"> - <owner>shaktisahu@chromium.org</owner> - <owner>chrome-upboarding-eng@google.com</owner> - <summary> - Recorded whenever the user taps on a language in the video player language - picker UI. Only the position of the language in the list of available - languages will be recorded. - </summary> -</histogram> - -<histogram name="VideoTutorials.Player.LoadTimeLatency" units="ms" - expires_after="2022-09-18"> - <owner>shaktisahu@chromium.org</owner> - <owner>chrome-upboarding-eng@google.com</owner> - <summary> - Records the latency in bringing up the video player for video tutorials. - Measures the time difference between user clicking on a video to the time - when it actually starts playing. - </summary> -</histogram> - -<histogram name="VideoTutorials.{Feature}.Player.Progress" - enum="VideoTutorials.WatchState" expires_after="2022-02-01"> - <owner>shaktisahu@chromium.org</owner> - <owner>chrome-upboarding-eng@google.com</owner> - <summary> - Records video watch progress events such as play, pause, resume, completion, - failure etc. encountered during when watching video tutorial for the - {Feature} feature. - </summary> - <token key="Feature" variants="VideoTutorialFeatureTopic"/> -</histogram> - -<histogram name="VideoTutorials.{Feature}.Player.UserAction" - enum="VideoTutorials.UserAction" expires_after="2022-02-01"> - <owner>shaktisahu@chromium.org</owner> - <owner>chrome-upboarding-eng@google.com</owner> - <summary> - Records user actions on the video player UI, such as clicking on various - buttons, encountered when watching video tutorial for the {Feature} feature. - </summary> - <token key="Feature" variants="VideoTutorialFeatureTopic"/> -</histogram> - -</histograms> - -</histogram-configuration>
diff --git a/tools/metrics/histograms/metadata/webapps/histograms.xml b/tools/metrics/histograms/metadata/webapps/histograms.xml index af15a0d..5bebba6 100644 --- a/tools/metrics/histograms/metadata/webapps/histograms.xml +++ b/tools/metrics/histograms/metadata/webapps/histograms.xml
@@ -881,25 +881,20 @@ <summary>Records the result code of Web App installs.</summary> </histogram> -<histogram name="WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus" - enum="IsolatedWebAppReadIntegrityBlockAndMetadataStatus" - expires_after="2023-11-08"> +<histogram name="WebApp.Isolated.ReadResponseHeadError" + enum="IsolatedWebAppReadResponseHeadError" expires_after="2024-05-08"> <owner>cmfcmf@chromium.org</owner> <owner>peletskyi@chromium.org</owner> <summary> - Records whether reading integrity block and metadata from a Signed Web - Bundle via the isolated-app: scheme was successful or resulted in an error. - This is logged every time the integrity block and metadata of an Isolated - Web App are parsed, which happens whenever the reader for an Isolated Web - App is not yet cached. Readers are evicted from the cache after - approximately 10 minutes of not reading any responses from their - corresponding Signed Web Bundle. Isolated Web Apps are parsed for any - resources loading for the web app, so any usage could trigger this UMA. + Records the exact error that occured during reading of a response head for a + request to an Isolated Web App via the isolated-app: scheme. The error is + logged together with WebApp.Isolated.ReadResponseHeadSuccess in case when an + error occurs. </summary> </histogram> -<histogram name="WebApp.Isolated.ReadResponseHeadStatus" - enum="IsolatedWebAppReadResponseHeadStatus" expires_after="2023-11-08"> +<histogram name="WebApp.Isolated.ReadResponseHeadSuccess" enum="BooleanSuccess" + expires_after="2024-05-08"> <owner>cmfcmf@chromium.org</owner> <owner>peletskyi@chromium.org</owner> <summary> @@ -954,6 +949,34 @@ </summary> </histogram> +<histogram name="WebApp.Isolated.SwbnFileUsabilityError" + enum="IsolatedWebAppSwbnFileUsabilityError" expires_after="2024-05-08"> + <owner>cmfcmf@chromium.org</owner> + <owner>peletskyi@chromium.org</owner> + <summary> + Records the exact error why a Signed Web Bundle is unusable. In particular + integrity block or metadata parsing errors are recorded here. The error is + logged together with WebApp.Isolated.SwbnFileUsabilitySuccess when an error + occurs. + </summary> +</histogram> + +<histogram name="WebApp.Isolated.SwbnFileUsabilitySuccess" enum="BooleanValid" + expires_after="2024-05-08"> + <owner>cmfcmf@chromium.org</owner> + <owner>peletskyi@chromium.org</owner> + <summary> + Records whether a Signed Web Bundle file is usable. To be usable the file's + integrity block and metadata should be read, parsed and validated + successfully. This is logged every time the integrity block and metadata of + an Isolated Web App are parsed, which happens whenever the reader for an + Isolated Web App is not yet cached. Readers are evicted from the cache after + approximately 10 minutes of not reading any responses from their + corresponding Signed Web Bundle. Isolated Web Apps are parsed for any + resources loading for the web app, so any usage could trigger this UMA. + </summary> +</histogram> + <histogram name="WebApp.LaunchContainer" enum="AppLaunchContainer" expires_after="2023-10-15"> <owner>phillis@chromium.org</owner>
diff --git a/tools/perf/contrib/companion/OWNERS b/tools/perf/contrib/companion/OWNERS new file mode 100644 index 0000000..3c79727d --- /dev/null +++ b/tools/perf/contrib/companion/OWNERS
@@ -0,0 +1 @@ +mgeorgaklis@google.com
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json index 28a5cd86..e6ab872 100644 --- a/tools/perf/core/perfetto_binary_roller/binary_deps.json +++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -13,16 +13,16 @@ "full_remote_path": "perfetto-luci-artifacts/v34.0/linux-arm/trace_processor_shell" }, "mac": { - "hash": "4e055f15be3f3051b390477d13bdb0685f9f5148", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/0b3824020e3b444cb05de5020ded5102fc259507/trace_processor_shell" + "hash": "e570da0a55037586249babd89fffccb9554baf19", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/6c650e1ad49593538b1bff04070cce56b8f036f9/trace_processor_shell" }, "mac_arm64": { "hash": "c32364e05e22cdf82ee0866aedd11c0e2050809c", "full_remote_path": "perfetto-luci-artifacts/v34.0/mac-arm64/trace_processor_shell" }, "linux": { - "hash": "1d8180921422595a6d099a574d0d7c68c32dbde1", - "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/6c650e1ad49593538b1bff04070cce56b8f036f9/trace_processor_shell" + "hash": "d5fb18033f52e0ca3127c9df8d2f0f286e394b9b", + "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux/c34c76b0a0c322d35c46f6caf154d2e377919da1/trace_processor_shell" } }, "power_profile.sql": {
diff --git a/tools/traffic_annotation/safe_list.txt b/tools/traffic_annotation/safe_list.txt index b64972c..093403b 100644 --- a/tools/traffic_annotation/safe_list.txt +++ b/tools/traffic_annotation/safe_list.txt
@@ -170,7 +170,6 @@ missing_new_fields,chrome/browser/ui/webui/sanitized_image_source.cc missing_new_fields,chrome/browser/ui/webui/signin/ash/user_cloud_signin_restriction_policy_fetcher.cc missing_new_fields,chrome/browser/ui/webui/whats_new/whats_new_util.cc -missing_new_fields,chrome/browser/video_tutorials/internal/tutorial_fetcher.cc missing_new_fields,chrome/services/sharing/nearby/platform/webrtc.cc missing_new_fields,chrome/services/sharing/nearby/platform/wifi_lan_medium.cc missing_new_fields,chromeos/ash/components/device_activity/device_activity_client.cc
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml index a46408b..19f7dd4 100644 --- a/tools/traffic_annotation/summary/annotations.xml +++ b/tools/traffic_annotation/summary/annotations.xml
@@ -244,7 +244,6 @@ <item id="update_client" added_in_milestone="74" content_hash_code="05223987" os_list="linux,windows,chromeos,android" file_path="components/update_client/net/network_impl.cc" /> <item id="url_prevision_fetcher" added_in_milestone="62" content_hash_code="03f14ce9" os_list="linux,windows,chromeos,android" file_path="content/browser/media/url_provision_fetcher.cc" /> <item id="user_info_fetcher" added_in_milestone="62" content_hash_code="044ae168" os_list="linux,windows,chromeos,android" file_path="components/policy/core/common/cloud/user_info_fetcher.cc" /> - <item id="video_tutorial_fetcher" added_in_milestone="87" content_hash_code="074438b7" os_list="linux,windows,chromeos,android" file_path="chrome/browser/video_tutorials/internal/tutorial_fetcher.cc" /> <item id="web_app_origin_association_download" added_in_milestone="90" content_hash_code="03a46d77" os_list="linux,windows,chromeos,android" file_path="components/webapps/services/web_app_origin_association/web_app_origin_association_fetcher.cc" /> <item id="web_history_counter" added_in_milestone="62" type="partial" second_id="web_history_service" content_hash_code="02f5cd95" os_list="linux,windows,chromeos,android" semantics_fields="2,3,4" policy_fields="4" file_path="components/browsing_data/core/counters/history_counter.cc" /> <item id="web_history_delete_url" added_in_milestone="74" type="partial" second_id="web_history_service" content_hash_code="018bdbf2" os_list="linux,windows,chromeos,android" semantics_fields="2,3,4" policy_fields="4" file_path="components/history/core/browser/history_service.cc" />
diff --git a/tools/traffic_annotation/summary/grouping.xml b/tools/traffic_annotation/summary/grouping.xml index 00d3b87..7cfcbed6 100644 --- a/tools/traffic_annotation/summary/grouping.xml +++ b/tools/traffic_annotation/summary/grouping.xml
@@ -162,7 +162,6 @@ <annotation id="password_requirements_spec_fetch"/> <annotation id="payment_manifest_downloader"/> <annotation id="proxy_config_settings"/> - <annotation id="video_tutorial_fetcher"/> <annotation id="qr_code_save"/> <annotation id="desktop_screenshot_save"/> <annotation id="safe_browsing_cache_collector"/>
diff --git a/tools/typescript/definitions/autofill_private.d.ts b/tools/typescript/definitions/autofill_private.d.ts index d946dbf..c3cebcf 100644 --- a/tools/typescript/definitions/autofill_private.d.ts +++ b/tools/typescript/definitions/autofill_private.d.ts
@@ -132,6 +132,7 @@ export function getUpiIdList(): Promise<string[]>; export function addVirtualCard(cardId: string): void; export function removeVirtualCard(cardId: string): void; + export function authenticateUserAndFlipMandatoryAuthToggle(): void; export const onPersonalDataChanged: ChromeEvent< (addresses: AddressEntry[], creditCards: CreditCardEntry[],
diff --git a/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java b/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java index 45647eb8..24f656f 100644 --- a/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java +++ b/ui/android/java/src/org/chromium/ui/KeyboardVisibilityDelegate.java
@@ -6,13 +6,13 @@ import android.annotation.SuppressLint; import android.content.Context; -import android.graphics.Rect; import android.os.Handler; import android.os.StrictMode; import android.view.View; -import android.view.WindowInsets; import android.view.inputmethod.InputMethodManager; +import androidx.core.view.WindowInsetsCompat; + import org.chromium.base.Log; import org.chromium.base.ObserverList; import org.chromium.base.TraceEvent; @@ -141,22 +141,15 @@ public int calculateKeyboardHeight(View rootView) { try (TraceEvent te = TraceEvent.scoped("KeyboardVisibilityDelegate.calculateKeyboardHeight")) { - Rect appRect = new Rect(); - rootView.getWindowVisibleDisplayFrame(appRect); - - // Assume status bar is always at the top of the screen. - final int statusBarHeight = appRect.top; - - int bottomMargin = rootView.getHeight() - (appRect.height() + statusBarHeight); - - // If there is no bottom margin, the keyboard is not showing. - if (bottomMargin <= 0) return 0; - WindowInsets insets = rootView.getRootWindowInsets(); - if (insets != null) { // Either not supported or the rootView isn't attached. - bottomMargin -= insets.getStableInsetBottom(); - } - - return bottomMargin; // This might include a bottom navigation. + if (rootView == null || rootView.getRootWindowInsets() == null) return 0; + WindowInsetsCompat windowInsetsCompat = WindowInsetsCompat.toWindowInsetsCompat( + rootView.getRootWindowInsets(), rootView); + int imeHeightIncludingNavigationBar = + windowInsetsCompat.getInsets(WindowInsetsCompat.Type.ime()).bottom; + if (imeHeightIncludingNavigationBar == 0) return 0; + int navigationBarHeight = + windowInsetsCompat.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom; + return imeHeightIncludingNavigationBar - navigationBarHeight; } }
diff --git a/ui/gfx/animation/keyframe/keyframe_model.cc b/ui/gfx/animation/keyframe/keyframe_model.cc index 0ffa309..9fcb8fb 100644 --- a/ui/gfx/animation/keyframe/keyframe_model.cc +++ b/ui/gfx/animation/keyframe/keyframe_model.cc
@@ -92,7 +92,8 @@ base::TimeDelta before_active_boundary_time = std::max(opposite_time_offset, base::TimeDelta()); if (local_time < before_active_boundary_time || - (local_time == before_active_boundary_time && playback_rate_ < 0)) { + (local_time == before_active_boundary_time && playback_rate_ < 0 && + !active_at_boundary_)) { return KeyframeModel::Phase::BEFORE; } // TODO(crbug.com/909794): By spec end time = max(start delay + duration + @@ -112,7 +113,8 @@ std::max(opposite_time_offset + active_duration, base::TimeDelta()); } if (local_time > active_after_boundary_time || - (local_time == active_after_boundary_time && playback_rate_ > 0)) { + (local_time == active_after_boundary_time && playback_rate_ > 0 && + !active_at_boundary_)) { return KeyframeModel::Phase::AFTER; } return KeyframeModel::Phase::ACTIVE;
diff --git a/ui/gfx/animation/keyframe/keyframe_model.h b/ui/gfx/animation/keyframe/keyframe_model.h index 3b9aefc..dc902057 100644 --- a/ui/gfx/animation/keyframe/keyframe_model.h +++ b/ui/gfx/animation/keyframe/keyframe_model.h
@@ -114,6 +114,11 @@ iteration_start_ = iteration_start; } + bool active_at_boundary() const { return active_at_boundary_; } + void set_active_at_boundary(bool active_at_boundary) { + active_at_boundary_ = active_at_boundary; + } + AnimationCurve* curve() { return curve_.get(); } const AnimationCurve* curve() const { return curve_.get(); } @@ -218,6 +223,8 @@ // about these values. base::TimeTicks pause_time_; base::TimeDelta total_paused_duration_; + + bool active_at_boundary_ = false; }; } // namespace gfx
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h index f95db55..a337d8f 100644 --- a/ui/native_theme/native_theme.h +++ b/ui/native_theme/native_theme.h
@@ -455,7 +455,7 @@ // Returns true when the NativeTheme uses a light-on-dark color scheme. If // you're considering using this function to choose between two hard-coded - // colors, you probably shouldn't. Instead, use GetSystemColor(). + // colors, you probably shouldn't. Instead, use ColorProvider::GetColor(). virtual bool ShouldUseDarkColors() const; // Returns the user's current page colors.
diff --git a/ui/views/controls/button/toggle_button_unittest.cc b/ui/views/controls/button/toggle_button_unittest.cc index 59357c8..18700af 100644 --- a/ui/views/controls/button/toggle_button_unittest.cc +++ b/ui/views/controls/button/toggle_button_unittest.cc
@@ -95,7 +95,6 @@ // The test verifies that the ink drop layer is removed properly when the // ToggleButton gets destroyed. TEST_F(ToggleButtonTest, ToggleButtonDestroyed) { - EXPECT_EQ(0, counter()); gfx::Point center(10, 10); button()->OnMousePressed(ui::MouseEvent( ui::ET_MOUSE_PRESSED, center, center, ui::EventTimeForNow(), @@ -109,7 +108,6 @@ // ToggleButton has focus (and is showing a ripple). TEST_F(ToggleButtonTest, ShutdownWithFocus) { button()->RequestFocus(); - EXPECT_EQ(1, counter()); } // Verify that ToggleButton::accepts_events_ works as expected.
diff --git a/ui/views/controls/focus_ring.cc b/ui/views/controls/focus_ring.cc index 7f00d4a..8546ed0 100644 --- a/ui/views/controls/focus_ring.cc +++ b/ui/views/controls/focus_ring.cc
@@ -351,7 +351,7 @@ // that RefreshLayer gets called somehow whenever |has_focused_predicate_| // returns a new value. const bool should_paint = - has_focus_predicate_.has_value() || (parent() && parent()->HasFocus()); + has_focus_predicate_ || (parent() && parent()->HasFocus()); SetVisible(should_paint); if (should_paint) { // A layer is necessary to paint beyond the parent's bounds. @@ -374,8 +374,8 @@ bool FocusRing::ShouldPaint() { // TODO(pbos): Reevaluate if this can turn into a DCHECK, e.g. we should // never paint if there's no parent focus. - return (!has_focus_predicate_ || (*has_focus_predicate_)(parent())) && - (has_focus_predicate_ || parent()->HasFocus()); + return has_focus_predicate_ ? has_focus_predicate_.Run(parent()) + : parent()->HasFocus(); } SkRRect FocusRing::RingRectFromPathRect(const SkRect& rect) const {
diff --git a/ui/views/controls/focus_ring.h b/ui/views/controls/focus_ring.h index 50d3a09..f96c25f 100644 --- a/ui/views/controls/focus_ring.h +++ b/ui/views/controls/focus_ring.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/functional/callback.h" #include "base/scoped_observation.h" #include "ui/base/class_property.h" #include "ui/color/color_id.h" @@ -35,7 +36,7 @@ static constexpr float kDefaultCornerRadiusDp = 2.0f; - using ViewPredicate = std::function<bool(View* view)>; + using ViewPredicate = base::RepeatingCallback<bool(const View* view)>; // The default thickness and inset amount of focus ring halos. If you need // the thickness of a specific focus ring, call halo_thickness() instead. @@ -145,7 +146,7 @@ absl::optional<ui::ColorId> color_id_; // The predicate used to determine whether the parent has focus. - absl::optional<ViewPredicate> has_focus_predicate_; + ViewPredicate has_focus_predicate_; // The thickness of the focus ring halo, in DIP. float halo_thickness_ = kDefaultHaloThickness;
diff --git a/ui/views/controls/link_fragment.cc b/ui/views/controls/link_fragment.cc index f9c4fb9..5e7fa1627 100644 --- a/ui/views/controls/link_fragment.cc +++ b/ui/views/controls/link_fragment.cc
@@ -22,27 +22,17 @@ prev_fragment_(this), next_fragment_(this) { // Connect to the previous fragment if it exists. - if (other_fragment) + if (other_fragment) { Connect(other_fragment); + } views::FocusRing::Install(this); - views::FocusRing::Get(this)->SetHasFocusPredicate([](View* view) -> bool { - auto* v = views::AsViewClass<LinkFragment>(view); - DCHECK(v); - if (v->HasFocus()) - return true; - - // Iterate through the loop of fragments until reaching the current fragment - // to see if any of them are focused. If so, this fragment will also be - // focused. - for (LinkFragment* current_fragment = v->next_fragment_; - current_fragment != v; - current_fragment = current_fragment->next_fragment_) { - if (current_fragment->HasFocus()) - return true; - } - return false; - }); + views::FocusRing::Get(this)->SetHasFocusPredicate( + base::BindRepeating([](const View* view) { + const auto* v = views::AsViewClass<LinkFragment>(view); + CHECK(v); + return InvokeOnFragments(&LinkFragment::HasFocus, v); + })); } LinkFragment::~LinkFragment() { @@ -75,33 +65,25 @@ void LinkFragment::RecalculateFont() { // Check whether any link fragment should be underlined. - bool should_be_underlined = IsUnderlined(); - for (LinkFragment* current_fragment = next_fragment_; - !should_be_underlined && current_fragment != this; - current_fragment = current_fragment->next_fragment_) { - should_be_underlined = current_fragment->IsUnderlined(); - } + const bool should_be_underlined = + InvokeOnFragments(&LinkFragment::IsUnderlined, this); // If the style differs from the current one, update. if ((font_list().GetFontStyle() & gfx::Font::UNDERLINE) != should_be_underlined) { - auto MaybeUpdateStyle = [should_be_underlined](LinkFragment* fragment) { - const int style = fragment->font_list().GetFontStyle(); - const int intended_style = should_be_underlined - ? (style | gfx::Font::UNDERLINE) - : (style & ~gfx::Font::UNDERLINE); - fragment->Label::SetFontList( - fragment->font_list().DeriveWithStyle(intended_style)); - fragment->SchedulePaint(); - }; - MaybeUpdateStyle(this); - views::FocusRing::Get(this)->SchedulePaint(); - for (LinkFragment* current_fragment = next_fragment_; - current_fragment != this; - current_fragment = current_fragment->next_fragment_) { - MaybeUpdateStyle(current_fragment); - views::FocusRing::Get(current_fragment)->SchedulePaint(); - } + InvokeOnFragments( + [should_be_underlined](LinkFragment* fragment) { + const int style = fragment->font_list().GetFontStyle(); + const int intended_style = should_be_underlined + ? (style | gfx::Font::UNDERLINE) + : (style & ~gfx::Font::UNDERLINE); + fragment->Label::SetFontList( + fragment->font_list().DeriveWithStyle(intended_style)); + fragment->SchedulePaint(); + views::FocusRing::Get(fragment)->SchedulePaint(); + return false; + }, + this); } }
diff --git a/ui/views/controls/link_fragment.h b/ui/views/controls/link_fragment.h index 5bbfca56..10e0adc 100644 --- a/ui/views/controls/link_fragment.h +++ b/ui/views/controls/link_fragment.h
@@ -5,6 +5,10 @@ #ifndef UI_VIEWS_CONTROLS_LINK_FRAGMENT_H_ #define UI_VIEWS_CONTROLS_LINK_FRAGMENT_H_ +#include <functional> +#include <type_traits> +#include <utility> + #include "base/memory/raw_ptr.h" #include "ui/views/controls/link.h" #include "ui/views/metadata/view_factory.h" @@ -29,6 +33,22 @@ LinkFragment& operator=(const LinkFragment&) = delete; private: + // Returns the short-circuiting logical-"or" of invoking `f` on all linked + // fragments, beginning with `initial_fragment`. + template < + typename F, + typename Fragment, // Templated to allow const or non-const LinkFragments + typename = std::enable_if_t<std::is_invocable_r_v<bool, F, Fragment*>>> + static bool InvokeOnFragments(F&& f, Fragment* initial_fragment) { + Fragment* fragment = initial_fragment; + bool result = false; + do { + result = std::invoke(std::forward<F>(f), fragment); + fragment = fragment->next_fragment_; + } while (!result && fragment != initial_fragment); + return result; + } + // Returns whether this fragment indicates that the entire link represented // by it should be underlined. bool IsUnderlined() const;
diff --git a/ui/views/controls/scroll_view.cc b/ui/views/controls/scroll_view.cc index c125f69..bcc425c1 100644 --- a/ui/views/controls/scroll_view.cc +++ b/ui/views/controls/scroll_view.cc
@@ -34,6 +34,7 @@ #include "ui/views/controls/focus_ring.h" #include "ui/views/style/platform_style.h" #include "ui/views/view.h" +#include "ui/views/view_utils.h" #include "ui/views/widget/widget.h" namespace views { @@ -312,10 +313,12 @@ } FocusRing::Install(this); - views::FocusRing::Get(this)->SetHasFocusPredicate([](View* view) -> bool { - auto* v = static_cast<ScrollView*>(view); - return v->draw_focus_indicator_; - }); + views::FocusRing::Get(this)->SetHasFocusPredicate( + base::BindRepeating([](const View* view) { + const auto* v = views::AsViewClass<ScrollView>(view); + CHECK(v); + return v->draw_focus_indicator_; + })); } ScrollView::~ScrollView() = default;
diff --git a/ui/views/controls/table/table_header.cc b/ui/views/controls/table/table_header.cc index 2d02fac..9bcbc79 100644 --- a/ui/views/controls/table/table_header.cc +++ b/ui/views/controls/table/table_header.cc
@@ -28,6 +28,7 @@ #include "ui/views/controls/table/table_view.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/style/platform_style.h" +#include "ui/views/view_utils.h" namespace views { @@ -91,9 +92,12 @@ HighlightPathGenerator::Install( this, std::make_unique<TableHeader::HighlightPathGenerator>()); FocusRing::Install(this); - views::FocusRing::Get(this)->SetHasFocusPredicate([&](View* view) { - return static_cast<TableHeader*>(view)->GetHeaderRowHasFocus(); - }); + views::FocusRing::Get(this)->SetHasFocusPredicate( + base::BindRepeating([](const View* view) { + const auto* v = views::AsViewClass<TableHeader>(view); + CHECK(v); + return v->GetHeaderRowHasFocus(); + })); } TableHeader::~TableHeader() = default;
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc index f01eab7..2ad2dda 100644 --- a/ui/views/controls/table/table_view.cc +++ b/ui/views/controls/table/table_view.cc
@@ -52,6 +52,7 @@ #include "ui/views/layout/layout_provider.h" #include "ui/views/style/platform_style.h" #include "ui/views/style/typography.h" +#include "ui/views/view_utils.h" namespace views { @@ -182,9 +183,12 @@ this, std::make_unique<TableView::HighlightPathGenerator>()); FocusRing::Install(this); - views::FocusRing::Get(this)->SetHasFocusPredicate([&](View* view) { - return static_cast<TableView*>(view)->HasFocus() && !header_row_is_active_; - }); + views::FocusRing::Get(this)->SetHasFocusPredicate( + base::BindRepeating([](const View* view) { + const auto* v = views::AsViewClass<TableView>(view); + CHECK(v); + return v->HasFocus() && !v->header_row_is_active_; + })); } TableView::TableView(ui::TableModel* model,