diff --git a/DEPS b/DEPS index 99967eb..6c03189 100644 --- a/DEPS +++ b/DEPS
@@ -295,7 +295,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '3744490336cf54f6a167643a8e40298cd6ce2756', + 'skia_revision': '877213bd9a41200b6f568df40cab71deec2d3bd8', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -303,7 +303,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '71ead7b41c8beb1c992f9395a616ea0f41b08b7b', + 'angle_revision': '541cdcbf094fd900f085d14cb896f11240393f0c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -346,7 +346,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. - 'freetype_revision': '1c44de209cb465d175279dc30cd95f9857f703dd', + 'freetype_revision': 'aca4ec5907e0bfb5bbeb01370257a121f3f47a0f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling freetype # and whatever else without interference from each other. @@ -366,7 +366,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': 'ddb664396541c88dc09b7ea2a528b86efa8dc7c6', + 'catapult_revision': '07489847d9adb4d5fb5ab9348f1044acd96e523a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -374,7 +374,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': 'aeb2dc95cce6b337892a9315f2304d8862dc3cf3', + 'devtools_frontend_revision': 'f27464fc7745b4c88ed955c79b80e59b5d7d472e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -414,7 +414,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. - 'quiche_revision': 'cfff7cf007ecb3dcfee2aceb04cdbf3f7f39272d', + 'quiche_revision': 'a9c7837f7085662870031f8134f7464e56f1bb01', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ios_webkit # and whatever else without interference from each other. @@ -434,7 +434,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling nearby # and whatever else without interference from each other. - 'nearby_revision': '8bd3d3458056c59801ecf2d86145844c4137070c', + 'nearby_revision': '00b1a1570ef5290394b7e865a67392ae4199f4c4', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling securemessage # and whatever else without interference from each other. @@ -782,12 +782,12 @@ 'src/clank': { 'url': 'https://chrome-internal.googlesource.com/clank/internal/apps.git' + '@' + - '23dad63168e72047bbb6aa121f53172cc156777d', + '773541ef7b875aad33ec4ffd613cfa4825d0932b', 'condition': 'checkout_android and checkout_src_internal', }, 'src/docs/website': { - 'url': Var('chromium_git') + '/website.git' + '@' + '9aff7766594d07d48603073fafa5d07b16e1d411', + 'url': Var('chromium_git') + '/website.git' + '@' + 'a951c376d10365faee64b904a050695506c4690a', }, 'src/ios/third_party/earl_grey2/src': { @@ -971,7 +971,7 @@ 'packages': [ { 'package': 'chromium/third_party/androidx', - 'version': 'czqUkXtlFi7ry_9Cp8R92jqD6Tk3QQFvQQERxS_8RGYC', + 'version': 'QIAEMIWLTUbZTxvdAvBOr-o7ggm0GYvw3xGm8KdoPqAC', }, ], 'condition': 'checkout_android', @@ -1204,7 +1204,7 @@ # For Linux and Chromium OS. 'src/third_party/cros_system_api': { - 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'f2700e5aaeec4f4735e8a2cf2a13b3561c390448', + 'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '2c7a87d4a4f5d9e55abfd6111843b2cd425c842f', 'condition': 'checkout_linux', }, @@ -1214,13 +1214,13 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6fde0fbe9226ae3fc9f5c709adb93249924e5c49', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '73a26246e50c0718e1b604040937bd3e1af428d4', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), 'src/third_party/devtools-frontend-internal': { - 'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + '79130b882092b6ab79785ea4180de97a72ca7e15', + 'url': 'https://chrome-internal.googlesource.com/devtools/devtools-internal.git' + '@' + 'f196f5a4a0d40987024d0379e4a59a416a1fad44', 'condition': 'checkout_src_internal', }, @@ -1635,7 +1635,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '197b7113ead0b489c3a4a4366786d6733d0d7c35', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'c194bc190ded8849d9d6be943220c5f8f72cc022', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1817,10 +1817,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '95541299f6b73716cb632523c3e7cfb80eb714f3', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '82ec26d039e19c70f6fa979bbff03b82d4b6ff7f', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '46e2d103b4edc76b65a8e71a5de372c213cfb5c3', + Var('webrtc_git') + '/src.git' + '@' + '7216b27406d094834d8644a525370069a70d2f93', # 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.
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/services/JsSandboxServiceTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/services/JsSandboxServiceTest.java index 833f28f1..e57b7fb 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/services/JsSandboxServiceTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/services/JsSandboxServiceTest.java
@@ -13,6 +13,7 @@ import androidx.javascriptengine.IsolateTerminatedException; import androidx.javascriptengine.JavaScriptIsolate; import androidx.javascriptengine.JavaScriptSandbox; +import androidx.javascriptengine.MemoryLimitExceededException; import androidx.javascriptengine.SandboxDeadException; import androidx.test.filters.MediumTest; @@ -450,7 +451,7 @@ @Test @MediumTest - public void testEvaluationThrowsWhenSandboxDead() throws Throwable { + public void testEvaluationThrowsWhenSandboxClosed() throws Throwable { final String code = "while(true){}"; Context context = ContextUtils.getApplicationContext(); @@ -458,16 +459,37 @@ JavaScriptSandbox.createConnectedInstanceForTestingAsync(context); try (JavaScriptSandbox jsSandbox = jsSandboxFuture.get(5, TimeUnit.SECONDS); JavaScriptIsolate jsIsolate = jsSandbox.createIsolate()) { - ListenableFuture<String> resultFuture = jsIsolate.evaluateJavaScriptAsync(code); + ListenableFuture<String> resultFuture1 = jsIsolate.evaluateJavaScriptAsync(code); jsSandbox.close(); + // Check already running evaluation gets SandboxDeadException try { - resultFuture.get(5, TimeUnit.SECONDS); + resultFuture1.get(5, TimeUnit.SECONDS); Assert.fail("Should have thrown."); } catch (ExecutionException e) { - if (!(e.getCause() instanceof IsolateTerminatedException)) { + if (!(e.getCause() instanceof SandboxDeadException)) { throw e; } } + // Check post-close evaluation gets SandboxDeadException + ListenableFuture<String> resultFuture2 = jsIsolate.evaluateJavaScriptAsync(code); + try { + resultFuture2.get(5, TimeUnit.SECONDS); + Assert.fail("Should have thrown."); + } catch (ExecutionException e) { + if (!(e.getCause() instanceof SandboxDeadException)) { + throw e; + } + } + // Check that closing an isolate then causes the IllegalStateException to be + // thrown instead. + jsIsolate.close(); + try { + ListenableFuture<String> postCloseResultFuture = + jsIsolate.evaluateJavaScriptAsync(code); + Assert.fail("Should have thrown."); + } catch (IllegalStateException e) { + // Expected + } } } @@ -558,33 +580,152 @@ @MediumTest public void testHeapSizeEnforced() throws Throwable { final long maxHeapSize = REASONABLE_HEAP_SIZE; - // We need to beat the v8 optimizer to ensure it really allocates the required memory. - // Note that we're allocating an array of elements - not bytes. - final String code = "this.array = Array(" + maxHeapSize + ").fill(Math.random(), 0);" - + "var arrayLength = this.array.length;" - + "var sum = 0;" - + "for (var i = 0; i < arrayLength; i++) {" - + " sum+=this.array[i];" - + "}"; + // We need to beat the v8 optimizer to ensure it really allocates the required memory. Note + // that we're allocating an array of elements - not bytes. Filling will ensure that the + // array is not sparsely allocated. + final String oomingCode = "" + + "const array = Array(" + maxHeapSize + ").fill(Math.random(), 0);"; + final String stableCode = "'PASS'"; + final String stableExpected = "PASS"; + final String unresolvedCode = "new Promise((resolve, reject) => {/* never resolve */})"; Context context = ContextUtils.getApplicationContext(); - ListenableFuture<JavaScriptSandbox> jsSandboxFuture = + + ListenableFuture<JavaScriptSandbox> jsSandboxFuture1 = JavaScriptSandbox.createConnectedInstanceForTestingAsync(context); - try (JavaScriptSandbox jsSandbox = jsSandboxFuture.get(5, TimeUnit.SECONDS)) { + try (JavaScriptSandbox jsSandbox = jsSandboxFuture1.get(5, TimeUnit.SECONDS)) { Assume.assumeTrue(jsSandbox.isFeatureSupported( JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE)); + Assume.assumeTrue( + jsSandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_PROMISE_RETURN)); IsolateStartupParameters isolateStartupParameters = new IsolateStartupParameters(); isolateStartupParameters.setMaxHeapSizeBytes(maxHeapSize); - try (JavaScriptIsolate jsIsolate = jsSandbox.createIsolate(isolateStartupParameters)) { - ListenableFuture<String> resultFuture = jsIsolate.evaluateJavaScriptAsync(code); + try (JavaScriptIsolate jsIsolate1 = jsSandbox.createIsolate(isolateStartupParameters); + JavaScriptIsolate jsIsolate2 = jsSandbox.createIsolate()) { + ListenableFuture<String> earlyUnresolvedResultFuture = + jsIsolate1.evaluateJavaScriptAsync(unresolvedCode); + ListenableFuture<String> earlyResultFuture = + jsIsolate1.evaluateJavaScriptAsync(stableCode); + ListenableFuture<String> oomResultFuture = + jsIsolate1.evaluateJavaScriptAsync(oomingCode); + + // Wait for jsIsolate2 to fully initialize before using jsIsolate1. + jsIsolate2.evaluateJavaScriptAsync(stableCode).get(5, TimeUnit.SECONDS); + + // Check that the heap limit is enforced and that it reports this was the evaluation + // that exceeded the limit. try { - resultFuture.get(10, TimeUnit.SECONDS); + oomResultFuture.get(5, TimeUnit.SECONDS); Assert.fail("Should have thrown."); } catch (ExecutionException e) { - if (!(e.getCause() instanceof SandboxDeadException)) { + if (!(e.getCause() instanceof MemoryLimitExceededException)) { throw e; } } + + // Check that the previously submitted (but unresolved) promise evaluation reports a + // crash + try { + earlyUnresolvedResultFuture.get(5, TimeUnit.SECONDS); + Assert.fail("Should have thrown."); + } catch (ExecutionException e) { + if (!(e.getCause() instanceof IsolateTerminatedException)) { + throw e; + } + } + + // Check that the previously submitted evaluation which completed before the memory + // limit was exceeded, but for which we haven't yet gotten the result, returns its + // result just fine. + String result = earlyResultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, result); + + // Check that a totally new evaluation reports a crash + ListenableFuture<String> lateResultFuture = + jsIsolate1.evaluateJavaScriptAsync(stableCode); + try { + lateResultFuture.get(5, TimeUnit.SECONDS); + Assert.fail("Should have thrown."); + } catch (ExecutionException e) { + if (!(e.getCause() instanceof IsolateTerminatedException)) { + throw e; + } + } + + // Check that other pre-existing isolates can still be used. + ListenableFuture<String> otherIsolateResultFuture = + jsIsolate2.evaluateJavaScriptAsync(stableCode); + String otherIsolateResult = otherIsolateResultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, otherIsolateResult); } } } + + @Test + @MediumTest + public void testIsolateCreationAfterCrash() throws Throwable { + final long maxHeapSize = REASONABLE_HEAP_SIZE; + // We need to beat the v8 optimizer to ensure it really allocates the required memory. Note + // that we're allocating an array of elements - not bytes. Filling will ensure that the + // array is not sparsely allocated. + final String oomingCode = "" + + "const array = Array(" + maxHeapSize + ").fill(Math.random(), 0);"; + final String stableCode = "'PASS'"; + final String stableExpected = "PASS"; + Context context = ContextUtils.getApplicationContext(); + + ListenableFuture<JavaScriptSandbox> jsSandboxFuture1 = + JavaScriptSandbox.createConnectedInstanceForTestingAsync(context); + try (JavaScriptSandbox jsSandbox = jsSandboxFuture1.get(5, TimeUnit.SECONDS)) { + Assume.assumeTrue(jsSandbox.isFeatureSupported( + JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE)); + Assume.assumeTrue( + jsSandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_PROMISE_RETURN)); + IsolateStartupParameters isolateStartupParameters = new IsolateStartupParameters(); + isolateStartupParameters.setMaxHeapSizeBytes(maxHeapSize); + try (JavaScriptIsolate jsIsolate1 = jsSandbox.createIsolate(isolateStartupParameters)) { + ListenableFuture<String> oomResultFuture = + jsIsolate1.evaluateJavaScriptAsync(oomingCode); + + // Check that the heap limit is enforced and that it reports this was the evaluation + // that exceeded the limit. + try { + oomResultFuture.get(5, TimeUnit.SECONDS); + Assert.fail("Should have thrown."); + } catch (ExecutionException e) { + if (!(e.getCause() instanceof MemoryLimitExceededException)) { + throw e; + } + } + + // Check that other isolates can still be created and used (without closing + // jsIsolate1). + try (JavaScriptIsolate jsIsolate2 = + jsSandbox.createIsolate(isolateStartupParameters)) { + ListenableFuture<String> resultFuture = + jsIsolate2.evaluateJavaScriptAsync(stableCode); + String result = resultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, result); + } + } + + // Check that other isolates can still be created and used (after closing jsIsolate1). + try (JavaScriptIsolate jsIsolate = jsSandbox.createIsolate(isolateStartupParameters)) { + ListenableFuture<String> resultFuture = + jsIsolate.evaluateJavaScriptAsync(stableCode); + String result = resultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, result); + } + } + + // Check that the old sandbox with the "crashed" isolate can be torn down and that a new + // sandbox and isolate can be spun up. + ListenableFuture<JavaScriptSandbox> jsSandboxFuture2 = + JavaScriptSandbox.createConnectedInstanceForTestingAsync(context); + try (JavaScriptSandbox jsSandbox = jsSandboxFuture2.get(5, TimeUnit.SECONDS); + JavaScriptIsolate jsIsolate = jsSandbox.createIsolate()) { + ListenableFuture<String> resultFuture = jsIsolate.evaluateJavaScriptAsync(stableCode); + String result = resultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, result); + } + } }
diff --git a/android_webview/js_sandbox/BUILD.gn b/android_webview/js_sandbox/BUILD.gn index 0427827..7daad969 100644 --- a/android_webview/js_sandbox/BUILD.gn +++ b/android_webview/js_sandbox/BUILD.gn
@@ -5,7 +5,10 @@ import("//build/config/android/rules.gni") generate_jni("js_sandbox_jni_headers") { - sources = [ "java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolate.java" ] + sources = [ + "java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolate.java", + "java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolateCallback.java", + ] } android_aidl("js_sandbox_aidl") { @@ -24,6 +27,7 @@ android_library("js_sandbox_service_java") { sources = [ "java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolate.java", + "java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolateCallback.java", "java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxService.java", "java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxService0.java", ] @@ -50,6 +54,7 @@ "java/src/androidx/javascriptengine/JavaScriptException.java", "java/src/androidx/javascriptengine/JavaScriptIsolate.java", "java/src/androidx/javascriptengine/JavaScriptSandbox.java", + "java/src/androidx/javascriptengine/MemoryLimitExceededException.java", "java/src/androidx/javascriptengine/SandboxDeadException.java", "java/src/androidx/javascriptengine/SandboxUnsupportedException.java", ]
diff --git a/android_webview/js_sandbox/java/src/androidx/javascriptengine/IsolateTerminatedException.java b/android_webview/js_sandbox/java/src/androidx/javascriptengine/IsolateTerminatedException.java index b44d0146..ae5b752 100644 --- a/android_webview/js_sandbox/java/src/androidx/javascriptengine/IsolateTerminatedException.java +++ b/android_webview/js_sandbox/java/src/androidx/javascriptengine/IsolateTerminatedException.java
@@ -5,8 +5,23 @@ package androidx.javascriptengine; /** - * Exception thrown when evaluation is terminated due to {@link JavaScriptIsolate} being - * closed. This can occur when the {@link JavaScriptIsolate#close()} is called. + * Exception thrown when evaluation is terminated due to the {@link JavaScriptIsolate} being closed + * or crashing. + * + * Calling {@link JavaScriptIsolate#close()} will cause this exception to be thrown for all + * previously requested but pending evaluations. + * <p> + * If the individual isolate has crashed, for example, due to exceeding a memory limit, this + * exception will also be thrown for all pending and future evaluations (until + * {@link JavaScriptIsolate#close()} is called). + * <p> + * Note that if the sandbox as a whole has crashed or been closed, {@link SandboxDeadException} will + * be thrown instead. + * <p> + * Note that this exception will not be thrown if the isolate has been explicitly closed before a + * call to {@link JavaScriptIsolate#evaluateJavaScriptAsync(String)}, which will instead immediately + * throw an IllegalStateException (and not asynchronously via a future). This applies even if the + * isolate was closed following a crash. */ public final class IsolateTerminatedException extends JavaScriptException { public IsolateTerminatedException() {
diff --git a/android_webview/js_sandbox/java/src/androidx/javascriptengine/JavaScriptIsolate.java b/android_webview/js_sandbox/java/src/androidx/javascriptengine/JavaScriptIsolate.java index fcbf862..667b43aa 100644 --- a/android_webview/js_sandbox/java/src/androidx/javascriptengine/JavaScriptIsolate.java +++ b/android_webview/js_sandbox/java/src/androidx/javascriptengine/JavaScriptIsolate.java
@@ -23,7 +23,7 @@ import java.io.IOException; import java.io.OutputStream; import java.util.HashSet; -import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; @@ -49,10 +49,16 @@ public final class JavaScriptIsolate implements AutoCloseable { private static final String TAG = "JavaScriptIsolate"; private final Object mSetLock = new Object(); + /** + * Interface to underlying service-backed implementation. + * + * mJsIsolateStub should only be null when the Isolate has been explicitly closed - not when the + * isolate has crashed or simply had its pending and future evaluations cancelled. + */ @Nullable private IJsSandboxIsolate mJsIsolateStub; private CloseGuardHelper mGuard = CloseGuardHelper.create(); - private final Executor mThreadPoolTaskExecutor = + private final ExecutorService mThreadPoolTaskExecutor = Executors.newCachedThreadPool(new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); @@ -67,6 +73,13 @@ @GuardedBy("mSetLock") private HashSet<CallbackToFutureAdapter.Completer<String>> mPendingCompleterSet = new HashSet<CallbackToFutureAdapter.Completer<String>>(); + /** + * If mPendingCompleterSet is null, new evaluations will throw this exception asynchronously. + * + * Note that if the isolate is closed, IllegalStateException is thrown synchronously instead. + */ + @Nullable + private Exception mExceptionForNewEvaluations; private class IJsSandboxIsolateCallbackStubWrapper extends IJsSandboxIsolateCallback.Stub { private CallbackToFutureAdapter.Completer<String> mCompleter; @@ -83,9 +96,25 @@ @Override public void reportError(@ExecutionErrorTypes int type, String error) { - assert type == IJsSandboxIsolateCallback.JS_EVALUATION_ERROR; - mCompleter.setException(new EvaluationFailedException(error)); + boolean crashing = false; + switch (type) { + case IJsSandboxIsolateCallback.JS_EVALUATION_ERROR: + mCompleter.setException(new EvaluationFailedException(error)); + break; + case IJsSandboxIsolateCallback.MEMORY_LIMIT_EXCEEDED: + mCompleter.setException(new MemoryLimitExceededException(error)); + crashing = true; + break; + default: + mCompleter.setException(new JavaScriptException( + "Crashing due to unknown JavaScriptException: " + error)); + // Assume the worst + crashing = true; + } removePending(mCompleter); + if (crashing) { + handleCrash(); + } } } @@ -126,8 +155,8 @@ * Promise of a String in case {@link JavaScriptSandbox#JS_FEATURE_PROMISE_RETURN} is * supported * - * @return Future that evaluates to the result String of the evaluation or exceptions({@link - * IsolateTerminatedException}, {@link SandboxDeadException}) if there is an error + * @return Future that evaluates to the result String of the evaluation or exceptions (see + * {@link JavaScriptException} and subclasses) if there is an error */ @SuppressWarnings("NullAway") @NonNull @@ -136,13 +165,12 @@ throw new IllegalStateException( "Calling evaluateJavascript() after closing the Isolate"); } - return CallbackToFutureAdapter.getFuture(completer -> { final String futureDebugMessage = "evaluateJavascript Future"; IJsSandboxIsolateCallbackStubWrapper callbackStub; synchronized (mSetLock) { if (mPendingCompleterSet == null) { - completer.setException(new IsolateTerminatedException()); + completer.setException(mExceptionForNewEvaluations); return futureDebugMessage; } mPendingCompleterSet.add(completer); @@ -176,6 +204,8 @@ */ @Override public void close() { + // IllegalStateException will be thrown synchronously instead for new evaluations. + mExceptionForNewEvaluations = null; if (mJsIsolateStub == null) { return; } @@ -232,7 +262,9 @@ * * @param name Identifier for the data that is passed, the same identifier should be used in the * JavaScript environment to refer to the data - * @param inputBytes Bytes to be passed into the JavaScript environment + * @param inputBytes Bytes to be passed into the JavaScript environment. This array must not be + * modified until the JavaScript promise returned by consumeNamedDataAsArrayBuffer has + * resolved (or rejected). * * @return {@code true} on success, {@code false} if the name has already been used before, * in which case the client should use an unused name @@ -253,12 +285,19 @@ ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); ParcelFileDescriptor readSide = pipe[0]; ParcelFileDescriptor writeSide = pipe[1]; - OutputStream outputStream = new ParcelFileDescriptor.AutoCloseOutputStream(writeSide); - mThreadPoolTaskExecutor.execute( - () -> { convertByteArrayToStream(inputBytes, outputStream); }); + try { + OutputStream outputStream = + new ParcelFileDescriptor.AutoCloseOutputStream(writeSide); + mThreadPoolTaskExecutor.execute( + () -> { convertByteArrayToStream(inputBytes, outputStream); }); - AssetFileDescriptor asd = new AssetFileDescriptor(readSide, offset, length); - return mJsIsolateStub.provideNamedData(name, asd); + AssetFileDescriptor asd = new AssetFileDescriptor(readSide, offset, length); + return mJsIsolateStub.provideNamedData(name, asd); + } finally { + // We pass the readSide to the separate sandbox process but we still need to close + // it on our end to avoid file descriptor leaks. + readSide.close(); + } } catch (RemoteException e) { Log.e(TAG, "RemoteException was thrown during provideNamedData()", e); } catch (IOException e) { @@ -278,16 +317,27 @@ } } + /** + * Cancel all pending and future evaluations with the given exception. + * + * Only the first call to this method has any effect. + */ void cancelAllPendingEvaluations(Exception e) { final HashSet<CallbackToFutureAdapter.Completer<String>> pendingSet; synchronized (mSetLock) { if (mPendingCompleterSet == null) return; pendingSet = mPendingCompleterSet; mPendingCompleterSet = null; + mExceptionForNewEvaluations = e; } for (CallbackToFutureAdapter.Completer<String> ele : pendingSet) { ele.setException(e); } + // This is the closest thing to a .close() method for ExecutorServices. This doesn't force + // the threads or their Runnables to immediately terminate, but will ensure that once the + // worker threads finish their current runnable (if any) that the thread pool terminates + // them, preventing a leak of threads. + mThreadPoolTaskExecutor.shutdownNow(); } void removePending(CallbackToFutureAdapter.Completer<String> completer) { @@ -298,6 +348,10 @@ } } + private void handleCrash() { + cancelAllPendingEvaluations(new IsolateTerminatedException()); + } + private static void closeQuietly(Closeable closeable) { if (closeable == null) return; try {
diff --git a/android_webview/js_sandbox/java/src/androidx/javascriptengine/JavaScriptSandbox.java b/android_webview/js_sandbox/java/src/androidx/javascriptengine/JavaScriptSandbox.java index c0f4febe..e3433150 100644 --- a/android_webview/js_sandbox/java/src/androidx/javascriptengine/JavaScriptSandbox.java +++ b/android_webview/js_sandbox/java/src/androidx/javascriptengine/JavaScriptSandbox.java
@@ -464,7 +464,7 @@ */ @Override public void close() { - doClose(new IsolateTerminatedException()); + doClose(new SandboxDeadException()); } void doClose(Exception cancelPendingWith) {
diff --git a/android_webview/js_sandbox/java/src/androidx/javascriptengine/MemoryLimitExceededException.java b/android_webview/js_sandbox/java/src/androidx/javascriptengine/MemoryLimitExceededException.java new file mode 100644 index 0000000..e188651 --- /dev/null +++ b/android_webview/js_sandbox/java/src/androidx/javascriptengine/MemoryLimitExceededException.java
@@ -0,0 +1,31 @@ +// 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. + +package androidx.javascriptengine; + +import androidx.annotation.NonNull; + +/** + * Indicates that a JavaScriptIsolate's evaluation failed due to exceeding its heap size limit. + * + * This exception is thrown when exceeding the heap size limit configured for the isolate via + * {@link IsolateStartupParameters}, or the default limit. It is not guaranteed to be thrown if the + * Android system as a whole has run out of memory before the JavaScript environment has reached its + * configured heap limit. + * <p> + * The isolate may not continue to be used after this exception has been thrown, and other pending + * evalutions for the isolate will fail. The isolate may continue to hold onto resources (even if + * explicitly closed) until the sandbox has been shutdown. Therefore, it is recommended that the + * sandbox be restarted at the earliest opportunity in order to reclaim these resources. + * <p> + * Other isolates within the same sandbox may continue to be used, created, and closed as normal. + */ +public final class MemoryLimitExceededException extends JavaScriptException { + public MemoryLimitExceededException(@NonNull String error) { + super(error); + } + public MemoryLimitExceededException() { + super(); + } +}
diff --git a/android_webview/js_sandbox/java/src/androidx/javascriptengine/SandboxDeadException.java b/android_webview/js_sandbox/java/src/androidx/javascriptengine/SandboxDeadException.java index b51d545..b06695b 100644 --- a/android_webview/js_sandbox/java/src/androidx/javascriptengine/SandboxDeadException.java +++ b/android_webview/js_sandbox/java/src/androidx/javascriptengine/SandboxDeadException.java
@@ -11,6 +11,9 @@ * <p> * This is different from {@link IsolateTerminatedException} which occurs when the * {@link JavaScriptIsolate} within a {@link JavaScriptSandbox} is terminated. + * <p> + * This exception will continue to be thrown for all future evaluation requests on unclosed + * isolates. */ public final class SandboxDeadException extends JavaScriptException { public SandboxDeadException() {
diff --git a/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl b/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl index 85ca474..f56c5a56 100644 --- a/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl +++ b/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl
@@ -12,6 +12,8 @@ oneway interface IJsSandboxIsolateCallback { // An exception was thrown during the JS evaluation. const int JS_EVALUATION_ERROR = 0; + // The evaluation failed and the isolate crashed due to running out of heap memory. + const int MEMORY_LIMIT_EXCEEDED = 1; void reportResult(String result) = 0;
diff --git a/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolate.java b/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolate.java index 691e626..54c91dc8 100644 --- a/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolate.java +++ b/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolate.java
@@ -9,7 +9,6 @@ import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolate; import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateCallback; -import org.chromium.base.Callback; import org.chromium.base.Log; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; @@ -39,23 +38,24 @@ if (mJsSandboxIsolate == 0) { throw new IllegalStateException("evaluateJavascript() called after close()"); } - JsSandboxIsolateJni.get().evaluateJavascript(mJsSandboxIsolate, this, code, - (result) - -> { - try { - callback.reportResult(result); - } catch (RemoteException e) { - Log.e(TAG, "reporting result failed", e); + JsSandboxIsolateJni.get().evaluateJavascript( + mJsSandboxIsolate, this, code, new JsSandboxIsolateCallback() { + @Override + public void onResult(String result) { + try { + callback.reportResult(result); + } catch (RemoteException e) { + Log.e(TAG, "reporting result failed", e); + } } - }, - (error) -> { - try { - // Currently we only support - // IJsSandboxIsolateCallback.JS_EVALUATION_ERROR - callback.reportError( - IJsSandboxIsolateCallback.JS_EVALUATION_ERROR, error); - } catch (RemoteException e) { - Log.e(TAG, "reporting error failed", e); + + @Override + public void onError(int errorType, String error) { + try { + callback.reportError(errorType, error); + } catch (RemoteException e) { + Log.e(TAG, "reporting error failed", e); + } } }); } @@ -111,7 +111,7 @@ void destroyNative(long nativeJsSandboxIsolate, JsSandboxIsolate caller); boolean evaluateJavascript(long nativeJsSandboxIsolate, JsSandboxIsolate caller, - String script, Callback<String> successCallback, Callback<String> failureCallback); + String script, JsSandboxIsolateCallback callback); boolean provideNamedData(long nativeJsSandboxIsolate, JsSandboxIsolate caller, String name, int fd, int length);
diff --git a/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolateCallback.java b/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolateCallback.java new file mode 100644 index 0000000..9aac3f3 --- /dev/null +++ b/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxIsolateCallback.java
@@ -0,0 +1,32 @@ +// 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. + +package org.chromium.android_webview.js_sandbox.service; + +import org.chromium.base.annotations.CalledByNative; +import org.chromium.base.annotations.JNINamespace; + +/** + * Callback interface for the native code to report a JavaScript evaluation outcome. + */ +@JNINamespace("android_webview") +public interface JsSandboxIsolateCallback { + /** + * Called when an evaluation succeeds immediately or after its promise resolves. + * + * @param result The string result of the evaluation or resolved evaluation promise. + */ + @CalledByNative + void onResult(String result); + /** + * Called in the event of an error. + * + * @param errorType See + * {@link org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateCallback} for + * error types. + * @param error String description of the error. + */ + @CalledByNative + void onError(int errorType, String error); +}
diff --git a/android_webview/js_sandbox/javatests/src/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java b/android_webview/js_sandbox/javatests/src/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java index 5972fd7..d0ab5ac 100644 --- a/android_webview/js_sandbox/javatests/src/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java +++ b/android_webview/js_sandbox/javatests/src/androidx/javascriptengine/WebViewJavaScriptSandboxTest.java
@@ -28,7 +28,8 @@ public class WebViewJavaScriptSandboxTest { // This value is somewhat arbitrary. It might need bumping if V8 snapshots become significantly // larger in future. However, we don't want it too large as that will make the tests slower and - // require more memory. + // require more memory. Although this is a long, it must not be greater than Integer.MAX_VALUE + // and should be much smaller (for the purposes of testing). private static final long REASONABLE_HEAP_SIZE = 100 * 1024 * 1024; @Before @@ -426,7 +427,7 @@ @Test @MediumTest - public void testEvaluationThrowsWhenSandboxDead() throws Throwable { + public void testEvaluationThrowsWhenSandboxClosed() throws Throwable { final String code = "while(true){}"; Context context = ApplicationProvider.getApplicationContext(); @@ -434,16 +435,37 @@ JavaScriptSandbox.createConnectedInstanceAsync(context); try (JavaScriptSandbox jsSandbox = jsSandboxFuture.get(5, TimeUnit.SECONDS); JavaScriptIsolate jsIsolate = jsSandbox.createIsolate()) { - ListenableFuture<String> resultFuture = jsIsolate.evaluateJavaScriptAsync(code); + ListenableFuture<String> resultFuture1 = jsIsolate.evaluateJavaScriptAsync(code); jsSandbox.close(); + // Check already running evaluation gets SandboxDeadException try { - resultFuture.get(5, TimeUnit.SECONDS); + resultFuture1.get(5, TimeUnit.SECONDS); Assert.fail("Should have thrown."); } catch (ExecutionException e) { - if (!(e.getCause() instanceof IsolateTerminatedException)) { + if (!(e.getCause() instanceof SandboxDeadException)) { throw e; } } + // Check post-close evaluation gets SandboxDeadException + ListenableFuture<String> resultFuture2 = jsIsolate.evaluateJavaScriptAsync(code); + try { + resultFuture2.get(5, TimeUnit.SECONDS); + Assert.fail("Should have thrown."); + } catch (ExecutionException e) { + if (!(e.getCause() instanceof SandboxDeadException)) { + throw e; + } + } + // Check that closing an isolate then causes the IllegalStateException to be + // thrown instead. + jsIsolate.close(); + try { + ListenableFuture<String> postCloseResultFuture = + jsIsolate.evaluateJavaScriptAsync(code); + Assert.fail("Should have thrown."); + } catch (IllegalStateException e) { + // Expected + } } } @@ -534,33 +556,152 @@ @MediumTest public void testHeapSizeEnforced() throws Throwable { final long maxHeapSize = REASONABLE_HEAP_SIZE; - // We need to beat the v8 optimizer to ensure it really allocates the required memory. - // Note that we're allocating an array of elements - not bytes. - final String code = "this.array = Array(" + maxHeapSize + ").fill(Math.random(), 0);" - + "var arrayLength = this.array.length;" - + "var sum = 0;" - + "for (var i = 0; i < arrayLength; i++) {" - + " sum+=this.array[i];" - + "}"; + // We need to beat the v8 optimizer to ensure it really allocates the required memory. Note + // that we're allocating an array of elements - not bytes. Filling will ensure that the + // array is not sparsely allocated. + final String oomingCode = "" + + "const array = Array(" + maxHeapSize + ").fill(Math.random(), 0);"; + final String stableCode = "'PASS'"; + final String stableExpected = "PASS"; + final String unresolvedCode = "new Promise((resolve, reject) => {/* never resolve */})"; Context context = ApplicationProvider.getApplicationContext(); - ListenableFuture<JavaScriptSandbox> jsSandboxFuture = + + ListenableFuture<JavaScriptSandbox> jsSandboxFuture1 = JavaScriptSandbox.createConnectedInstanceAsync(context); - try (JavaScriptSandbox jsSandbox = jsSandboxFuture.get(5, TimeUnit.SECONDS)) { + try (JavaScriptSandbox jsSandbox = jsSandboxFuture1.get(5, TimeUnit.SECONDS)) { Assume.assumeTrue(jsSandbox.isFeatureSupported( JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE)); + Assume.assumeTrue( + jsSandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_PROMISE_RETURN)); IsolateStartupParameters isolateStartupParameters = new IsolateStartupParameters(); isolateStartupParameters.setMaxHeapSizeBytes(maxHeapSize); - try (JavaScriptIsolate jsIsolate = jsSandbox.createIsolate(isolateStartupParameters)) { - ListenableFuture<String> resultFuture = jsIsolate.evaluateJavaScriptAsync(code); + try (JavaScriptIsolate jsIsolate1 = jsSandbox.createIsolate(isolateStartupParameters); + JavaScriptIsolate jsIsolate2 = jsSandbox.createIsolate()) { + ListenableFuture<String> earlyUnresolvedResultFuture = + jsIsolate1.evaluateJavaScriptAsync(unresolvedCode); + ListenableFuture<String> earlyResultFuture = + jsIsolate1.evaluateJavaScriptAsync(stableCode); + ListenableFuture<String> oomResultFuture = + jsIsolate1.evaluateJavaScriptAsync(oomingCode); + + // Wait for jsIsolate2 to fully initialize before using jsIsolate1. + jsIsolate2.evaluateJavaScriptAsync(stableCode).get(5, TimeUnit.SECONDS); + + // Check that the heap limit is enforced and that it reports this was the evaluation + // that exceeded the limit. try { - resultFuture.get(10, TimeUnit.SECONDS); + oomResultFuture.get(5, TimeUnit.SECONDS); Assert.fail("Should have thrown."); } catch (ExecutionException e) { - if (!(e.getCause() instanceof SandboxDeadException)) { + if (!(e.getCause() instanceof MemoryLimitExceededException)) { throw e; } } + + // Check that the previously submitted (but unresolved) promise evaluation reports a + // crash + try { + earlyUnresolvedResultFuture.get(5, TimeUnit.SECONDS); + Assert.fail("Should have thrown."); + } catch (ExecutionException e) { + if (!(e.getCause() instanceof IsolateTerminatedException)) { + throw e; + } + } + + // Check that the previously submitted evaluation which completed before the memory + // limit was exceeded, but for which we haven't yet gotten the result, returns its + // result just fine. + String result = earlyResultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, result); + + // Check that a totally new evaluation reports a crash + ListenableFuture<String> lateResultFuture = + jsIsolate1.evaluateJavaScriptAsync(stableCode); + try { + lateResultFuture.get(5, TimeUnit.SECONDS); + Assert.fail("Should have thrown."); + } catch (ExecutionException e) { + if (!(e.getCause() instanceof IsolateTerminatedException)) { + throw e; + } + } + + // Check that other pre-existing isolates can still be used. + ListenableFuture<String> otherIsolateResultFuture = + jsIsolate2.evaluateJavaScriptAsync(stableCode); + String otherIsolateResult = otherIsolateResultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, otherIsolateResult); } } } + + @Test + @MediumTest + public void testIsolateCreationAfterCrash() throws Throwable { + final long maxHeapSize = REASONABLE_HEAP_SIZE; + // We need to beat the v8 optimizer to ensure it really allocates the required memory. Note + // that we're allocating an array of elements - not bytes. Filling will ensure that the + // array is not sparsely allocated. + final String oomingCode = "" + + "const array = Array(" + maxHeapSize + ").fill(Math.random(), 0);"; + final String stableCode = "'PASS'"; + final String stableExpected = "PASS"; + Context context = ApplicationProvider.getApplicationContext(); + + ListenableFuture<JavaScriptSandbox> jsSandboxFuture1 = + JavaScriptSandbox.createConnectedInstanceAsync(context); + try (JavaScriptSandbox jsSandbox = jsSandboxFuture1.get(5, TimeUnit.SECONDS)) { + Assume.assumeTrue(jsSandbox.isFeatureSupported( + JavaScriptSandbox.JS_FEATURE_ISOLATE_MAX_HEAP_SIZE)); + Assume.assumeTrue( + jsSandbox.isFeatureSupported(JavaScriptSandbox.JS_FEATURE_PROMISE_RETURN)); + IsolateStartupParameters isolateStartupParameters = new IsolateStartupParameters(); + isolateStartupParameters.setMaxHeapSizeBytes(maxHeapSize); + try (JavaScriptIsolate jsIsolate1 = jsSandbox.createIsolate(isolateStartupParameters)) { + ListenableFuture<String> oomResultFuture = + jsIsolate1.evaluateJavaScriptAsync(oomingCode); + + // Check that the heap limit is enforced and that it reports this was the evaluation + // that exceeded the limit. + try { + oomResultFuture.get(5, TimeUnit.SECONDS); + Assert.fail("Should have thrown."); + } catch (ExecutionException e) { + if (!(e.getCause() instanceof MemoryLimitExceededException)) { + throw e; + } + } + + // Check that other isolates can still be created and used (without closing + // jsIsolate1). + try (JavaScriptIsolate jsIsolate2 = + jsSandbox.createIsolate(isolateStartupParameters)) { + ListenableFuture<String> resultFuture = + jsIsolate2.evaluateJavaScriptAsync(stableCode); + String result = resultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, result); + } + } + + // Check that other isolates can still be created and used (after closing jsIsolate1). + try (JavaScriptIsolate jsIsolate = jsSandbox.createIsolate(isolateStartupParameters)) { + ListenableFuture<String> resultFuture = + jsIsolate.evaluateJavaScriptAsync(stableCode); + String result = resultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, result); + } + } + + // Check that the old sandbox with the "crashed" isolate can be torn down and that a new + // sandbox and isolate can be spun up. + ListenableFuture<JavaScriptSandbox> jsSandboxFuture2 = + JavaScriptSandbox.createConnectedInstanceAsync(context); + try (JavaScriptSandbox jsSandbox = jsSandboxFuture2.get(5, TimeUnit.SECONDS); + JavaScriptIsolate jsIsolate = jsSandbox.createIsolate()) { + ListenableFuture<String> resultFuture = jsIsolate.evaluateJavaScriptAsync(stableCode); + String result = resultFuture.get(5, TimeUnit.SECONDS); + Assert.assertEquals(stableExpected, result); + } + } }
diff --git a/android_webview/js_sandbox/service/BUILD.gn b/android_webview/js_sandbox/service/BUILD.gn index a4c0555..29f1f41 100644 --- a/android_webview/js_sandbox/service/BUILD.gn +++ b/android_webview/js_sandbox/service/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "js_sandbox_isolate.cc", "js_sandbox_isolate.h", + "js_sandbox_isolate_callback.cc", + "js_sandbox_isolate_callback.h", ] deps = [
diff --git a/android_webview/js_sandbox/service/js_sandbox_isolate.cc b/android_webview/js_sandbox/service/js_sandbox_isolate.cc index afc8031..59354ee 100644 --- a/android_webview/js_sandbox/service/js_sandbox_isolate.cc +++ b/android_webview/js_sandbox/service/js_sandbox_isolate.cc
@@ -10,14 +10,18 @@ #include <string> #include "android_webview/js_sandbox/js_sandbox_jni_headers/JsSandboxIsolate_jni.h" +#include "android_webview/js_sandbox/service/js_sandbox_isolate_callback.h" #include "base/android/callback_android.h" #include "base/android/jni_android.h" #include "base/android/jni_string.h" +#include "base/auto_reset.h" #include "base/bind.h" #include "base/files/file_util.h" +#include "base/immediate_crash.h" #include "base/logging.h" #include "base/memory/raw_ptr.h" #include "base/strings/string_piece.h" +#include "base/synchronization/waitable_event.h" #include "base/system/sys_info.h" #include "base/task/cancelable_task_tracker.h" #include "base/task/single_thread_task_runner.h" @@ -34,6 +38,7 @@ #include "js_sandbox_isolate.h" #include "v8/include/v8-function.h" #include "v8/include/v8-microtask-queue.h" +#include "v8/include/v8-statistics.h" #include "v8/include/v8-template.h" using base::android::ConvertJavaStringToUTF8; @@ -113,6 +118,7 @@ CHECK(resolver->Reject(context, compilation_result).FromJust()); } } + } // namespace namespace android_webview { @@ -133,8 +139,9 @@ length = len; } -JsSandboxIsolate::JsSandboxIsolate(jlong max_heap_size_bytes) { - isolate_max_heap_size_bytes_ = max_heap_size_bytes; +JsSandboxIsolate::JsSandboxIsolate(jlong max_heap_size_bytes) + : isolate_max_heap_size_bytes_(max_heap_size_bytes) { + CHECK_GE(isolate_max_heap_size_bytes_, 0); control_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner({}); isolate_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner( {base::TaskPriority::USER_BLOCKING, @@ -163,19 +170,16 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, const base::android::JavaParamRef<jstring>& jcode, - const base::android::JavaParamRef<jobject>& j_success_callback, - const base::android::JavaParamRef<jobject>& j_failure_callback) { + const base::android::JavaParamRef<jobject>& j_callback) { std::string code = ConvertJavaStringToUTF8(env, jcode); + std::unique_ptr<JsSandboxIsolateCallback> callback = + std::make_unique<JsSandboxIsolateCallback>( + base::android::ScopedJavaGlobalRef(j_callback)); control_task_runner_->PostTask( FROM_HERE, base::BindOnce(&JsSandboxIsolate::PostEvaluationToIsolateThread, base::Unretained(this), std::move(code), - base::BindOnce(&base::android::RunStringCallbackAndroid, - base::android::ScopedJavaGlobalRef<jobject>( - j_success_callback)), - base::BindOnce(&base::android::RunStringCallbackAndroid, - base::android::ScopedJavaGlobalRef<jobject>( - j_failure_callback)))); + std::move(callback))); return true; } @@ -205,13 +209,12 @@ // Called from control sequence. void JsSandboxIsolate::PostEvaluationToIsolateThread( const std::string code, - FinishedCallback success_callback, - FinishedCallback error_callback) { + std::unique_ptr<JsSandboxIsolateCallback> callback) { cancelable_task_tracker_->PostTask( isolate_task_runner_.get(), FROM_HERE, base::BindOnce(&JsSandboxIsolate::EvaluateJavascriptOnThread, base::Unretained(this), std::move(code), - std::move(success_callback), std::move(error_callback))); + std::move(callback))); } // Called from control sequence. @@ -317,6 +320,9 @@ } // Called from isolate thread. +// +// Note that this will never be called if the isolate has "crashed" due to OOM +// and frozen its isolate thread. void JsSandboxIsolate::DeleteSelf() { delete this; } @@ -337,6 +343,9 @@ v8::Isolate::Scope isolate_scope(isolate); isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto); isolate->SetWasmAsyncResolvePromiseCallback(WasmAsyncResolvePromiseCallback); + + isolate->AddNearHeapLimitCallback(&JsSandboxIsolate::NearHeapLimitCallback, + this); v8::HandleScope handle_scope(isolate); v8::Local<v8::ObjectTemplate> android_template = @@ -355,8 +364,10 @@ // Called from isolate thread. void JsSandboxIsolate::EvaluateJavascriptOnThread( const std::string code, - FinishedCallback success_callback, - FinishedCallback error_callback) { + std::unique_ptr<JsSandboxIsolateCallback> callback) { + base::AutoReset<JsSandboxIsolateCallback*> callback_autoreset( + ¤t_callback_, callback.get()); + v8::Isolate::Scope isolate_scope(isolate_holder_->isolate()); v8::HandleScope handle_scope(isolate_holder_->isolate()); v8::Context::Scope scope(context_holder_->context()); @@ -374,7 +385,7 @@ } v8::Local<v8::Script> script; if (!maybe_script.ToLocal(&script)) { - std::move(error_callback).Run(compile_error); + std::move(callback)->ReportJsEvaluationError(compile_error); return; } @@ -397,26 +408,27 @@ // directly. if (promise->State() == v8::Promise::PromiseState::kFulfilled) { std::string result = gin::V8ToString(v8_isolate, promise->Result()); - std::move(success_callback).Run(result); + std::move(callback)->ReportResult(result); return; } if (promise->State() == v8::Promise::PromiseState::kRejected) { v8::Local<v8::Message> message = v8::Exception::CreateMessage( isolate_holder_->isolate(), promise->Result()); std::string error_message = GetStackTrace(message, v8_isolate); - std::move(error_callback).Run(error_message); + std::move(callback)->ReportJsEvaluationError(error_message); return; } v8::Local<v8::Function> fulfill_fun = gin::CreateFunctionTemplate( v8_isolate, base::BindRepeating( - [](FinishedCallback success_callback, gin::Arguments* args) { + [](std::unique_ptr<JsSandboxIsolateCallback> callback, + gin::Arguments* args) { std::string output; args->GetNext(&output); - std::move(success_callback).Run(output); + std::move(callback)->ReportResult(output); }, - base::Passed(std::move(success_callback)))) + base::Passed(std::move(callback)))) ->GetFunction(context_holder_->context()) .ToLocalChecked(); v8::Local<v8::Function> reject_fun = @@ -424,7 +436,7 @@ v8_isolate, base::BindRepeating(&JsSandboxIsolate::PromiseRejectCallback, base::Unretained(this), - base::Passed(std::move(error_callback)))) + base::Passed(std::move(callback)))) ->GetFunction(context_holder_->context()) .ToLocalChecked(); @@ -432,22 +444,23 @@ .ToLocalChecked(); } else { std::string result = gin::V8ToString(v8_isolate, value); - std::move(success_callback).Run(result); + std::move(callback)->ReportResult(result); } } else { - std::move(error_callback).Run(run_error); + std::move(callback)->ReportJsEvaluationError(run_error); } } -void JsSandboxIsolate::PromiseRejectCallback(FinishedCallback error_callback, - gin::Arguments* args) { +void JsSandboxIsolate::PromiseRejectCallback( + std::unique_ptr<JsSandboxIsolateCallback> callback, + gin::Arguments* args) { v8::Local<v8::Value> value; args->GetNext(&value); v8::Local<v8::Message> message = v8::Exception::CreateMessage(isolate_holder_->isolate(), value); std::string error_message = GetStackTrace(message, isolate_holder_->isolate()); - std::move(error_callback).Run(error_message); + std::move(callback)->ReportJsEvaluationError(error_message); } // Called from isolate thread. @@ -529,6 +542,50 @@ args->Return(promise); } +// Called from isolate thread. +[[noreturn]] size_t JsSandboxIsolate::NearHeapLimitCallback( + void* data, + size_t /*current_heap_limit*/, + size_t /*initial_heap_limit*/) { + android_webview::JsSandboxIsolate* js_sandbox_isolate = + static_cast<android_webview::JsSandboxIsolate*>(data); + js_sandbox_isolate->MemoryLimitExceeded(); +} + +// Called from isolate thread. +[[noreturn]] void JsSandboxIsolate::MemoryLimitExceeded() { + LOG(ERROR) << "Isolate has OOMed"; + // TODO(ashleynewson): An isolate could run out of memory outside of an + // evaluation when processing asynchronous code. We should add a crash + // signalling mechanism which doesn't rely on us having a callback for a + // currently running evaluation. + CHECK(current_callback_) + << "Isolate ran out of memory outside of an evaluation."; + uint64_t memory_limit = static_cast<uint64_t>(isolate_max_heap_size_bytes_); + v8::HeapStatistics heap_statistics; + isolate_holder_->isolate()->GetHeapStatistics(&heap_statistics); + uint64_t heap_usage = heap_statistics.used_heap_size(); + current_callback_->ReportMemoryLimitExceededError(memory_limit, heap_usage); + FreezeThread(); +} + +// Halt thread until process dies. +[[noreturn]] void JsSandboxIsolate::FreezeThread() { + // There is no well-defined way to fully terminate a thread prematurely, so we + // idle the thread forever. + // + // TODO(ashleynewson): In future, we may want to look into ways to cleanup or + // even properly terminate the thread if language or V8 features allow for it, + // as we currently hold onto (essentially leaking) all resources this isolate + // has accumulated up to this point. C++20's <stop_token> (not permitted in + // Chromium at time of writing) may contribute to such a future solution. + + base::ScopedAllowBaseSyncPrimitives allow_base_sync_primitives; + base::WaitableEvent().Wait(); + // Unreachable. Make sure the compiler understands that. + base::ImmediateCrash(); +} + static void JNI_JsSandboxIsolate_InitializeEnvironment(JNIEnv* env) { base::ThreadPoolInstance::CreateAndStartWithDefaultParams("JsSandboxIsolate"); #ifdef V8_USE_EXTERNAL_STARTUP_DATA
diff --git a/android_webview/js_sandbox/service/js_sandbox_isolate.h b/android_webview/js_sandbox/service/js_sandbox_isolate.h index a0322e8..2ccd409b 100644 --- a/android_webview/js_sandbox/service/js_sandbox_isolate.h +++ b/android_webview/js_sandbox/service/js_sandbox_isolate.h
@@ -38,20 +38,18 @@ namespace android_webview { class FdWithLength; +class JsSandboxIsolateCallback; class JsSandboxIsolate { public: explicit JsSandboxIsolate(jlong max_heap_size_bytes = 0); ~JsSandboxIsolate(); - using FinishedCallback = base::OnceCallback<void(const std::string&)>; - jboolean EvaluateJavascript( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, const base::android::JavaParamRef<jstring>& jcode, - const base::android::JavaParamRef<jobject>& j_success_callback, - const base::android::JavaParamRef<jobject>& j_failure_callback); + const base::android::JavaParamRef<jobject>& j_callback); void DestroyNative(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); jboolean ProvideNamedData(JNIEnv* env, @@ -63,19 +61,19 @@ private: void DeleteSelf(); void InitializeIsolateOnThread(); - void EvaluateJavascriptOnThread(const std::string code, - FinishedCallback success_callback, - FinishedCallback failure_callback); - void PromiseRejectCallback(FinishedCallback error_callback, + void EvaluateJavascriptOnThread( + const std::string code, + std::unique_ptr<JsSandboxIsolateCallback> callback); + void PromiseRejectCallback(std::unique_ptr<JsSandboxIsolateCallback> callback, gin::Arguments* args); void TerminateAndDestroy(); void DestroyWhenPossible(); void NotifyInitComplete(); void CreateCancelableTaskTracker(); - void PostEvaluationToIsolateThread(const std::string code, - FinishedCallback success_callback, - FinishedCallback error_callback); + void PostEvaluationToIsolateThread( + const std::string code, + std::unique_ptr<JsSandboxIsolateCallback> callback); void ConvertPromiseToArrayBufferInThreadPool(base::ScopedFD fd, ssize_t length, std::string name); @@ -94,6 +92,14 @@ v8::Local<v8::ObjectTemplate> CreateAndroidNamespaceTemplate( v8::Isolate* isolate); + // Must only be used from isolate thread + [[noreturn]] static size_t NearHeapLimitCallback(void* data, + size_t current_heap_limit, + size_t initial_heap_limit); + // Must only be used from isolate thread + [[noreturn]] void MemoryLimitExceeded(); + [[noreturn]] void FreezeThread(); + // Used as a control sequence to add ordering to binder threadpool requests. scoped_refptr<base::SequencedTaskRunner> control_task_runner_; // Should be used from control_task_runner_. @@ -116,7 +122,19 @@ base::Lock named_fd_lock_; std::unordered_map<std::string, FdWithLength> named_fd_ GUARDED_BY(named_fd_lock_); - jlong isolate_max_heap_size_bytes_; + // V8 heap size limit. Must be non-negative. + // + // 0 indicates no explicit limit (but use the default V8 limits). + const jlong isolate_max_heap_size_bytes_; + + // The callback associated with the current evaluation, if any. Used for + // signaling errors from V8 callbacks. + // + // This can be nullptr outside of active evaluation, including when the result + // of an evaluation is a JS promise which is pending resolution/rejection. + // + // This pointer must only be accessed from the isolate thread. + JsSandboxIsolateCallback* current_callback_; }; } // namespace android_webview
diff --git a/android_webview/js_sandbox/service/js_sandbox_isolate_callback.cc b/android_webview/js_sandbox/service/js_sandbox_isolate_callback.cc new file mode 100644 index 0000000..d703f11 --- /dev/null +++ b/android_webview/js_sandbox/service/js_sandbox_isolate_callback.cc
@@ -0,0 +1,58 @@ +// 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 "android_webview/js_sandbox/service/js_sandbox_isolate_callback.h" + +#include <jni.h> +#include <sstream> + +#include "android_webview/js_sandbox/js_sandbox_jni_headers/JsSandboxIsolateCallback_jni.h" +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/android/scoped_java_ref.h" + +namespace android_webview { + +JsSandboxIsolateCallback::JsSandboxIsolateCallback( + base::android::ScopedJavaGlobalRef<jobject>&& callback) + : callback_(std::move(callback)) {} + +JsSandboxIsolateCallback::~JsSandboxIsolateCallback() = default; + +void JsSandboxIsolateCallback::ReportResult(const std::string& result) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jstring> java_string_result = + base::android::ConvertUTF8ToJavaString(env, result); + Java_JsSandboxIsolateCallback_onResult(env, callback_, java_string_result); +} + +void JsSandboxIsolateCallback::ReportJsEvaluationError( + const std::string& error) { + ReportError(ErrorType::kJsEvaluationError, error); +} + +void JsSandboxIsolateCallback::ReportMemoryLimitExceededError( + const uint64_t memory_limit, + const uint64_t heap_usage) { + std::ostringstream details; + details << "Memory limit exceeded.\n"; + if (memory_limit > 0) { + details << "Memory limit: " << memory_limit << " bytes\n"; + } else { + details << "Memory limit not explicitly configured\n"; + } + details << "Heap usage: " << heap_usage << " bytes\n"; + ReportError(ErrorType::kMemoryLimitExceeded, details.str()); +} + +void JsSandboxIsolateCallback::ReportError(const ErrorType error_type, + const std::string& error) { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaLocalRef<jstring> java_string_error = + base::android::ConvertUTF8ToJavaString(env, error); + Java_JsSandboxIsolateCallback_onError( + env, callback_, static_cast<jint>(error_type), java_string_error); +} + +} // namespace android_webview
diff --git a/android_webview/js_sandbox/service/js_sandbox_isolate_callback.h b/android_webview/js_sandbox/service/js_sandbox_isolate_callback.h new file mode 100644 index 0000000..ea563bb --- /dev/null +++ b/android_webview/js_sandbox/service/js_sandbox_isolate_callback.h
@@ -0,0 +1,45 @@ +// 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 ANDROID_WEBVIEW_JS_SANDBOX_SERVICE_JS_SANDBOX_ISOLATE_CALLBACK_H_ +#define ANDROID_WEBVIEW_JS_SANDBOX_SERVICE_JS_SANDBOX_ISOLATE_CALLBACK_H_ + +#include <jni.h> + +#include "base/android/scoped_java_ref.h" + +namespace android_webview { + +class JsSandboxIsolateCallback final { + public: + enum class ErrorType { + kJsEvaluationError = 0, + kMemoryLimitExceeded = 1, + }; + + explicit JsSandboxIsolateCallback( + base::android::ScopedJavaGlobalRef<jobject>&& callback); + JsSandboxIsolateCallback(const JsSandboxIsolateCallback&) = delete; + JsSandboxIsolateCallback& operator=(const JsSandboxIsolateCallback&) = delete; + ~JsSandboxIsolateCallback(); + + void ReportResult(const std::string& result); + void ReportJsEvaluationError(const std::string& error); + // Report that the isolate has exceeded its memory limit, with various stats. + // + // memory_limit == 0 indicates that no explicit limit was configured. + // + // heap_usage describes memory usage before the failed allocation. + void ReportMemoryLimitExceededError(uint64_t memory_limit, + uint64_t heap_usage); + + private: + void ReportError(ErrorType error_type, const std::string& error); + + base::android::ScopedJavaGlobalRef<jobject> callback_; +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_JS_SANDBOX_SERVICE_JS_SANDBOX_ISOLATE_CALLBACK_H_
diff --git a/ash/app_list/app_list_presenter_unittest.cc b/ash/app_list/app_list_presenter_unittest.cc index c25dc0a..e5b46ed 100644 --- a/ash/app_list/app_list_presenter_unittest.cc +++ b/ash/app_list/app_list_presenter_unittest.cc
@@ -3132,13 +3132,13 @@ test_result->set_display_type(SearchResultDisplayType::kList); search_model->results()->Add(std::move(test_result)); - auto test_tile_result = std::make_unique<TestSearchResult>(); - test_tile_result->set_result_id("test_tile"); + auto test_list_result = std::make_unique<TestSearchResult>(); + test_list_result->set_result_id("test_list"); // Give this item a name so that the accessibility paint checks pass. // (Focusable items should have accessible names.) - test_tile_result->SetAccessibleName(u"test_tile"); - test_tile_result->set_display_type(SearchResultDisplayType::kTile); - search_model->results()->Add(std::move(test_tile_result)); + test_list_result->SetAccessibleName(u"test_list"); + test_list_result->set_display_type(SearchResultDisplayType::kList); + search_model->results()->Add(std::move(test_list_result)); // The results are updated asynchronously. Wait until the update is finished. base::RunLoop().RunUntilIdle(); @@ -3173,13 +3173,13 @@ test_result_override->set_display_type(SearchResultDisplayType::kList); search_model_override->results()->Add(std::move(test_result_override)); - auto test_tile_result_override = std::make_unique<TestSearchResult>(); - test_tile_result_override->set_result_id("test_tile_override"); + auto test_list_result_override = std::make_unique<TestSearchResult>(); + test_list_result_override->set_result_id("test_list_override"); // Give this item a name so that the accessibility paint checks pass. // (Focusable items should have accessible names.) - test_tile_result_override->SetAccessibleName(u"test_tile_override"); - test_tile_result_override->set_display_type(SearchResultDisplayType::kTile); - search_model_override->results()->Add(std::move(test_tile_result_override)); + test_list_result_override->SetAccessibleName(u"test_list_override"); + test_list_result_override->set_display_type(SearchResultDisplayType::kList); + search_model_override->results()->Add(std::move(test_list_result_override)); // The results are updated asynchronously. Wait until the update is finished. base::RunLoop().RunUntilIdle();
diff --git a/ash/app_list/views/search_result_list_view_unittest.cc b/ash/app_list/views/search_result_list_view_unittest.cc index f2c6458f6..0661cfb 100644 --- a/ash/app_list/views/search_result_list_view_unittest.cc +++ b/ash/app_list/views/search_result_list_view_unittest.cc
@@ -421,31 +421,5 @@ ExpectConsistent(); } -TEST_P(SearchResultListViewTest, HidesAssistantResultWhenTilesVisible) { - SetUpSearchResults(); - - // No assistant results available. - EXPECT_TRUE(GetAssistantResultViews().empty()); - - AddAssistantSearchResult(); - - // Assistant result should be set and visible. - for (const auto* view : GetAssistantResultViews()) { - EXPECT_TRUE(view->GetVisible()); - EXPECT_EQ(view->result()->title(), u"assistant result"); - } - - // Add a tile result - std::unique_ptr<TestSearchResult> tile_result = - std::make_unique<TestSearchResult>(); - tile_result->set_display_type(ash::SearchResultDisplayType::kTile); - GetResults()->Add(std::move(tile_result)); - - RunPendingMessages(); - - // Assistant result should be gone. - EXPECT_TRUE(GetAssistantResultViews().empty()); -} - } // namespace test } // namespace ash
diff --git a/ash/app_list/views/search_result_page_view.cc b/ash/app_list/views/search_result_page_view.cc index 41455061..c24cff78 100644 --- a/ash/app_list/views/search_result_page_view.cc +++ b/ash/app_list/views/search_result_page_view.cc
@@ -219,15 +219,6 @@ result_container_ptr->set_delegate(this); } -bool SearchResultPageView::IsFirstResultTile() const { - // In the event that the result does not exist, it is not a tile. - if (!first_result_view_ || !first_result_view_->result()) - return false; - - return first_result_view_->result()->display_type() == - SearchResultDisplayType::kTile; -} - bool SearchResultPageView::IsFirstResultHighlighted() const { DCHECK(first_result_view_); return first_result_view_->selected();
diff --git a/ash/app_list/views/search_result_page_view.h b/ash/app_list/views/search_result_page_view.h index 3f2dde31..406cb60 100644 --- a/ash/app_list/views/search_result_page_view.h +++ b/ash/app_list/views/search_result_page_view.h
@@ -50,7 +50,6 @@ return result_container_views_; } - bool IsFirstResultTile() const; bool IsFirstResultHighlighted() const; // Overridden from views::View:
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd index 3e2c5a36..a4585be 100644 --- a/ash/ash_strings.grd +++ b/ash/ash_strings.grd
@@ -884,10 +884,10 @@ Keyboard backlight is on </message> <message name="IDS_ASH_STATUS_AREA_TOAST_MIC_OFF" desc="The text in the toast that shows up when the mic is muted using a physical key or shortcut."> - Microphone is off + Device microphone access is off </message> <message name="IDS_ASH_STATUS_AREA_TOAST_MIC_ON" desc="The text in the toast that shows up when the mic is unmuted using a physical key or shortcut."> - Microphone is on + Device microphone access is on </message> <message name="IDS_ASH_STATUS_TRAY_VOLUME" desc="The accessible text for the toggle volume muted button in the tray."> Toggle Volume. <ph name="STATE_TEXT">$1<ex>Volume is muted</ex></ph>
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_AREA_TOAST_MIC_OFF.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_AREA_TOAST_MIC_OFF.png.sha1 index 5e221a2..a90a97e 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_AREA_TOAST_MIC_OFF.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_AREA_TOAST_MIC_OFF.png.sha1
@@ -1 +1 @@ -2eec248082c775e6293ba3bad6a7ff88b2b7f287 \ No newline at end of file +f38e527e9408214d6938eb86a6267c74361e212f \ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_ASH_STATUS_AREA_TOAST_MIC_ON.png.sha1 b/ash/ash_strings_grd/IDS_ASH_STATUS_AREA_TOAST_MIC_ON.png.sha1 index 173e4d83..4e13c45 100644 --- a/ash/ash_strings_grd/IDS_ASH_STATUS_AREA_TOAST_MIC_ON.png.sha1 +++ b/ash/ash_strings_grd/IDS_ASH_STATUS_AREA_TOAST_MIC_ON.png.sha1
@@ -1 +1 @@ -d5affacf158cd422891415d0d6491d61232a73c7 \ No newline at end of file +3fbc7839d4130768848a1b4424ced74b0c75d7d9 \ No newline at end of file
diff --git a/ash/public/cpp/app_list/app_list_config.cc b/ash/public/cpp/app_list/app_list_config.cc index a20479b..e37acc5c 100644 --- a/ash/public/cpp/app_list/app_list_config.cc +++ b/ash/public/cpp/app_list/app_list_config.cc
@@ -146,10 +146,6 @@ switch (display_type) { case SearchResultDisplayType::kList: return search_list_icon_dimension_; - case SearchResultDisplayType::kTile: - return search_tile_icon_dimension_; - case SearchResultDisplayType::kChip: - return suggestion_chip_icon_dimension_; case SearchResultDisplayType::kContinue: return suggestion_chip_icon_dimension_; case SearchResultDisplayType::kNone:
diff --git a/ash/public/cpp/app_list/app_list_types.h b/ash/public/cpp/app_list/app_list_types.h index 782a856..c11485b 100644 --- a/ash/public/cpp/app_list/app_list_types.h +++ b/ash/public/cpp/app_list/app_list_types.h
@@ -18,7 +18,6 @@ #include "ui/base/models/image_model.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/range/range.h" -#include "url/gurl.h" namespace ash { @@ -412,16 +411,13 @@ // Which UI container(s) the result should be displayed in. // Do not change the order of these as they are used for metrics. -// -// TODO(https://crbug.com/1258415): kChip can be deprecated once -// ProductivityLauncher is launched. enum class SearchResultDisplayType { kNone = 0, kList = 1, // Displays in search list - kTile = 2, // Displays in search tiles + // kTile = 2, // No longer used, Displays in search tiles // kRecommendation = 3 // No longer used, split between kTile and kChip kAnswerCard = 4, // Displays in answer cards - kChip = 5, // Displays in suggestion chips + // kChip = 5, // No longer used, Displays in suggestion chips kContinue = 6, // Displays in the Continue section kRecentApps = 7, // Displays in recent apps row // Add new values here
diff --git a/ash/webui/camera_app_ui/OWNERS b/ash/webui/camera_app_ui/OWNERS index 9fe3d698..3d66d748 100644 --- a/ash/webui/camera_app_ui/OWNERS +++ b/ash/webui/camera_app_ui/OWNERS
@@ -1,5 +1,6 @@ chuhsuan@chromium.org jcliang@chromium.org +kamchonlathorn@chromium.org pihsun@chromium.org shik@chromium.org wtlee@chromium.org
diff --git a/ash/webui/common/resources/office_fallback/office_fallback_dialog.ts b/ash/webui/common/resources/office_fallback/office_fallback_dialog.ts index 0f8a747..ab40117 100644 --- a/ash/webui/common/resources/office_fallback/office_fallback_dialog.ts +++ b/ash/webui/common/resources/office_fallback/office_fallback_dialog.ts
@@ -164,4 +164,10 @@ } } +declare global { + interface HTMLElementTagNameMap { + 'office-fallback': OfficeFallbackElement; + } +} + customElements.define('office-fallback', OfficeFallbackElement); \ No newline at end of file
diff --git a/ash/webui/files_internals/files_internals_page_handler.cc b/ash/webui/files_internals/files_internals_page_handler.cc index 1911dd2..264b0c0 100644 --- a/ash/webui/files_internals/files_internals_page_handler.cc +++ b/ash/webui/files_internals/files_internals_page_handler.cc
@@ -36,4 +36,14 @@ files_internals_ui_->delegate()->SetOfficeSetupComplete(complete); } +void FilesInternalsPageHandler::GetAlwaysMoveOfficeFiles( + GetAlwaysMoveOfficeFilesCallback callback) { + std::move(callback).Run( + files_internals_ui_->delegate()->GetAlwaysMoveOfficeFiles()); +} + +void FilesInternalsPageHandler::SetAlwaysMoveOfficeFiles(bool always_move) { + files_internals_ui_->delegate()->SetAlwaysMoveOfficeFiles(always_move); +} + } // namespace ash
diff --git a/ash/webui/files_internals/files_internals_page_handler.h b/ash/webui/files_internals/files_internals_page_handler.h index a07517d..ab8b1e5 100644 --- a/ash/webui/files_internals/files_internals_page_handler.h +++ b/ash/webui/files_internals/files_internals_page_handler.h
@@ -31,6 +31,9 @@ void SetSmbfsEnableVerboseLogging(bool enabled) override; void GetOfficeSetupComplete(GetOfficeSetupCompleteCallback callback) override; void SetOfficeSetupComplete(bool complete) override; + void GetAlwaysMoveOfficeFiles( + GetAlwaysMoveOfficeFilesCallback callback) override; + void SetAlwaysMoveOfficeFiles(bool always_move) override; private: raw_ptr<FilesInternalsUI> files_internals_ui_; // Owns |this|.
diff --git a/ash/webui/files_internals/files_internals_ui_delegate.h b/ash/webui/files_internals/files_internals_ui_delegate.h index 686fcba7..04d366f5 100644 --- a/ash/webui/files_internals/files_internals_ui_delegate.h +++ b/ash/webui/files_internals/files_internals_ui_delegate.h
@@ -21,6 +21,9 @@ virtual bool GetOfficeSetupComplete() const = 0; virtual void SetOfficeSetupComplete(bool complete) = 0; + + virtual bool GetAlwaysMoveOfficeFiles() const = 0; + virtual void SetAlwaysMoveOfficeFiles(bool always_move) = 0; }; } // namespace ash
diff --git a/ash/webui/files_internals/mojom/files_internals.mojom b/ash/webui/files_internals/mojom/files_internals.mojom index 7df45c8a..82a6bcb 100644 --- a/ash/webui/files_internals/mojom/files_internals.mojom +++ b/ash/webui/files_internals/mojom/files_internals.mojom
@@ -15,4 +15,9 @@ GetOfficeSetupComplete() => (bool complete); // Sets the filebrowser.office.setup_complete pref. SetOfficeSetupComplete(bool complete); + + // Gets the filebrowser.office.setup_complete pref. + GetAlwaysMoveOfficeFiles() => (bool always_move); + // Sets the filebrowser.office.setup_complete pref. + SetAlwaysMoveOfficeFiles(bool always_move); };
diff --git a/ash/webui/files_internals/resources/index.html b/ash/webui/files_internals/resources/index.html index e1f1921..865b78c 100644 --- a/ash/webui/files_internals/resources/index.html +++ b/ash/webui/files_internals/resources/index.html
@@ -35,6 +35,8 @@ <h2>Office file handlers</h2> <p>Office setup complete?: <span id="office-setup-complete-status"></span></p> <button id="clear-office-setup-complete">Clear Office setup complete</button> +<p>Always move files?: <span id="office-always-move-status"></span></p> +<button id="clear-office-always-move">Always ask before moving</button> </body> </html>
diff --git a/ash/webui/files_internals/resources/index.js b/ash/webui/files_internals/resources/index.js index 29ec146..abf334a 100644 --- a/ash/webui/files_internals/resources/index.js +++ b/ash/webui/files_internals/resources/index.js
@@ -26,4 +26,15 @@ const officeSetupComplete = (await pageHandler.getOfficeSetupComplete()).complete; officeSetupStatus.innerText = officeSetupComplete ? 'Yes' : 'No'; + + const clearAlwaysMoveButton = + document.getElementById('clear-office-always-move'); + clearAlwaysMoveButton.addEventListener('click', () => { + pageHandler.setAlwaysMoveOfficeFiles(false); + }); + const officeAlwaysMoveStatus = + document.getElementById('office-always-move-status'); + const officeAlwaysMove = + (await pageHandler.getAlwaysMoveOfficeFiles()).alwaysMove; + officeAlwaysMoveStatus.innerText = officeAlwaysMove ? 'Yes' : 'No'; });
diff --git a/base/BUILD.gn b/base/BUILD.gn index 1484cc6..58bed8e 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1744,13 +1744,18 @@ sources += [ "profiler/chrome_unwind_info_android.cc", "profiler/chrome_unwind_info_android.h", - "profiler/chrome_unwinder_android.cc", - "profiler/chrome_unwinder_android.h", "profiler/chrome_unwinder_android_v2.cc", "profiler/chrome_unwinder_android_v2.h", ] } + if (current_cpu == "arm64") { + sources += [ + "profiler/frame_pointer_unwinder.cc", + "profiler/frame_pointer_unwinder.h", + ] + } + if (current_cpu != "arm" && current_cpu != "arm64") { # The reached code profiler is only supported on Android arm arch. sources -= [ "android/reached_code_profiler.cc" ] @@ -2640,7 +2645,6 @@ flags = [ "ENABLE_ARM_CFI_TABLE=$enable_arm_cfi_table", "IOS_STACK_PROFILER_ENABLED=$ios_stack_profiler_enabled", - "USE_ANDROID_UNWINDER_V2=$use_android_unwinder_v2", ] } @@ -3636,10 +3640,12 @@ if (current_cpu == "arm") { sources += [ "profiler/chrome_unwind_info_android_unittest.cc", - "profiler/chrome_unwinder_android_unittest.cc", "profiler/chrome_unwinder_android_v2_unittest.cc", ] } + if (current_cpu == "arm64") { + sources += [ "profiler/frame_pointer_unwinder_unittest.cc" ] + } if (!exclude_unwind_tables && (current_cpu == "arm" || current_cpu == "arm64")) { sources += [
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc index 679bf7b..2de7862 100644 --- a/base/android/jni_array.cc +++ b/base/android/jni_array.cc
@@ -4,29 +4,12 @@ #include "base/android/jni_array.h" -#include <ostream> - #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/check_op.h" #include "base/numerics/safe_conversions.h" -namespace base { -namespace android { -namespace { - -// As |GetArrayLength| makes no guarantees about the returned value (e.g., it -// may be -1 if |array| is not a valid Java array), provide a safe wrapper -// that always returns a valid, non-negative size. -template <typename JavaArrayType> -size_t SafeGetArrayLength(JNIEnv* env, const JavaRef<JavaArrayType>& jarray) { - DCHECK(jarray); - jsize length = env->GetArrayLength(jarray.obj()); - DCHECK_GE(length, 0) << "Invalid array length: " << length; - return static_cast<size_t>(std::max(0, length)); -} - -} // namespace +namespace base::android { ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(JNIEnv* env, const uint8_t* bytes, @@ -374,6 +357,19 @@ AppendJavaByteArrayToByteVector(env, byte_array, out); } +size_t JavaByteArrayToByteSpan(JNIEnv* env, + const JavaRef<jbyteArray>& byte_array, + base::span<uint8_t> dest) { + CHECK(byte_array); + size_t len = SafeGetArrayLength(env, byte_array); + size_t span_len = dest.size_bytes(); + CHECK_GE(span_len, len) << "Target span is too small, java array size: " + << len << ", span size: " << span_len; + env->GetByteArrayRegion(byte_array.obj(), 0, static_cast<jsize>(len), + reinterpret_cast<int8_t*>(dest.data())); + return len; +} + void JavaByteArrayToString(JNIEnv* env, const JavaRef<jbyteArray>& byte_array, std::string* out) { @@ -540,5 +536,4 @@ } } -} // namespace android -} // namespace base +} // namespace base::android
diff --git a/base/android/jni_array.h b/base/android/jni_array.h index d9d6ceb..ee3bbb5 100644 --- a/base/android/jni_array.h +++ b/base/android/jni_array.h
@@ -8,14 +8,28 @@ #include <jni.h> #include <stddef.h> #include <stdint.h> +#include <ostream> #include <string> #include <vector> #include "base/android/scoped_java_ref.h" +#include "base/check_op.h" #include "base/containers/span.h" -namespace base { -namespace android { +namespace base::android { + +// As |GetArrayLength| makes no guarantees about the returned value (e.g., it +// may be -1 if |array| is not a valid Java array), provide a safe wrapper +// that always returns a valid, non-negative size. +// Returns the length of Java array. +template <typename JavaArrayType> +BASE_EXPORT size_t SafeGetArrayLength(JNIEnv* env, + const JavaRef<JavaArrayType>& jarray) { + DCHECK(jarray); + jsize length = env->GetArrayLength(jarray.obj()); + DCHECK_GE(length, 0) << "Invalid array length: " << length; + return static_cast<size_t>(std::max(0, length)); +} // Returns a new Java byte array converted from the given bytes array. BASE_EXPORT ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(JNIEnv* env, @@ -141,6 +155,14 @@ const JavaRef<jbyteArray>& byte_array, std::vector<uint8_t>* out); +// Copy the contents of java |byte_array| into |dest|. The span must be larger +// than or equal to the array. +// Returns the number of bytes copied. +BASE_EXPORT size_t +JavaByteArrayToByteSpan(JNIEnv* env, + const JavaRef<jbyteArray>& byte_array, + base::span<uint8_t> dest); + // Replaces the content of |out| with the Java bytes in |byte_array|. No UTF-8 // conversion is performed. BASE_EXPORT void JavaByteArrayToString(JNIEnv* env, @@ -220,7 +242,6 @@ const JavaRef<jobjectArray>& array, std::vector<std::vector<int>>* out); -} // namespace android -} // namespace base +} // namespace base::android #endif // BASE_ANDROID_JNI_ARRAY_H_
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc index 61ed0eb..0bf72281 100644 --- a/base/android/jni_array_unittest.cc +++ b/base/android/jni_array_unittest.cc
@@ -13,12 +13,26 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/android/scoped_java_ref.h" +#include "base/containers/span.h" #include "base/strings/utf_string_conversions.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -namespace base { -namespace android { +namespace base::android { + +TEST(JniArray, GetLength) { + const uint8_t bytes[] = {0, 1, 2, 3}; + const size_t len = std::size(bytes); + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jbyteArray> j_bytes = ToJavaByteArray(env, bytes, len); + ASSERT_TRUE(j_bytes); + ASSERT_EQ(4U, SafeGetArrayLength(env, j_bytes)); + + ScopedJavaLocalRef<jbyteArray> j_empty_bytes = + ToJavaByteArray(env, base::span<uint8_t>()); + ASSERT_TRUE(j_empty_bytes); + ASSERT_EQ(0U, SafeGetArrayLength(env, j_empty_bytes)); +} TEST(JniArray, BasicConversions) { const uint8_t kBytes[] = {0, 1, 2, 3}; @@ -42,6 +56,10 @@ EXPECT_EQ(expected_vec, vectorFromBytes); EXPECT_EQ(expected_vec, vectorFromVector); + std::vector<uint8_t> vector_for_span_test(expected_vec.size()); + JavaByteArrayToByteSpan(env, bytes, base::make_span(vector_for_span_test)); + EXPECT_EQ(expected_vec, vector_for_span_test); + AppendJavaByteArrayToByteVector(env, bytes, &vectorFromBytes); EXPECT_EQ(8U, vectorFromBytes.size()); expected_vec.insert(expected_vec.end(), kBytes, kBytes + kLen); @@ -605,5 +623,4 @@ env, static_cast<jstring>(env->GetObjectArrayElement( j_array.obj(), 2))))); } -} // namespace android -} // namespace base +} // namespace base::android
diff --git a/base/memory/README.md b/base/memory/README.md index 5d92cd1..915f32e 100644 --- a/base/memory/README.md +++ b/base/memory/README.md
@@ -12,16 +12,30 @@ [here](https://docs.google.com/document/d/1VRevv8JhlP4I8fIlvf87IrW2IRjE0PbkSfIcI6-UbJo/edit?usp=sharing). ## `raw_ptr<T>` -Use for class fields/members that would otherwise be a native pointer. +Use for class fields/members that would otherwise be a `T*`. -This is a weakly refcounted wrapper for a native pointer (also called a raw +This is a weakly refcounted wrapper for a `T*` (also called a raw pointer). When the object is deleted, the allocator will "poison" the memory that object occupied and keep the memory around so it’s not reused. This reduces the risk and impact of a use-after-free bug. Depending on the use case, it's possible a smart pointer with additional features would be more appropriate, but if none of those are applicable or -necesssary, `raw_ptr<T>` is much safer than a native pointer. +necessary, `raw_ptr<T>` is preferred over a `T*`. + +For more information, see [`raw_ptr.md`](./raw_ptr.md); for guidance on +usage, see +[the style guide](../../styleguide/c++/c++.md#non_owning-pointers-in-class-fields). + +## `raw_ref<T>` +Use for class fields/members that would otherwise be a `T&`. + +This shares much in common with `raw_ptr<T>`, but asserts that the +`raw_ref<T>` is not nullable. + +For more information, see [`raw_ptr.md`](./raw_ptr.md); for guidance on +usage, see +[the style guide](../../styleguide/c++/c++.md#non_owning-pointers-in-class-fields). ## `base::WeakPtr<T>` Use when a reference to an object might outlive the object itself.
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm index 1beda5f..25ee653 100644 --- a/base/message_loop/message_pump_mac.mm +++ b/base/message_loop/message_pump_mac.mm
@@ -43,7 +43,7 @@ // - Cancel an already scheduled timer wake up if there is no delayed work. BASE_FEATURE(kMessagePumpMacDelayedWorkOptimizations, "MessagePumpMacDelayedWorkOptimizations", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Caches the state of the "MessagePumpMacDelayedWorkOptimizations" // feature for efficiency.
diff --git a/base/profiler/chrome_unwinder_android.cc b/base/profiler/chrome_unwinder_android.cc deleted file mode 100644 index 3322b92..0000000 --- a/base/profiler/chrome_unwinder_android.cc +++ /dev/null
@@ -1,104 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/profiler/chrome_unwinder_android.h" - -#include "base/numerics/checked_math.h" -#include "base/profiler/module_cache.h" -#include "build/build_config.h" - -namespace base { - -ChromeUnwinderAndroid::ChromeUnwinderAndroid( - const ArmCFITable* cfi_table, - uintptr_t chrome_module_base_address) - : cfi_table_(cfi_table), - chrome_module_base_address_(chrome_module_base_address) { - DCHECK(cfi_table_); -} - -ChromeUnwinderAndroid::~ChromeUnwinderAndroid() = default; - -bool ChromeUnwinderAndroid::CanUnwindFrom(const Frame& current_frame) const { - return current_frame.module && - current_frame.module->GetBaseAddress() == chrome_module_base_address_; -} - -UnwindResult ChromeUnwinderAndroid::TryUnwind(RegisterContext* thread_context, - uintptr_t stack_top, - std::vector<Frame>* stack) { - DCHECK(CanUnwindFrom(stack->back())); - do { - const ModuleCache::Module* module = stack->back().module; - uintptr_t pc = RegisterContextInstructionPointer(thread_context); - DCHECK_GE(pc, module->GetBaseAddress()); - uintptr_t func_addr = pc - module->GetBaseAddress(); - - auto entry = cfi_table_->FindEntryForAddress(func_addr); - if (entry) { - if (!Step(thread_context, stack_top, *entry)) - return UnwindResult::kAborted; - } else if (stack->size() == 1) { - // Try unwinding by sourcing the return address from the lr register. - if (!StepUsingLrRegister(thread_context, stack_top)) - return UnwindResult::kAborted; - } else { - return UnwindResult::kAborted; - } - stack->emplace_back(RegisterContextInstructionPointer(thread_context), - module_cache()->GetModuleForAddress( - RegisterContextInstructionPointer(thread_context))); - } while (CanUnwindFrom(stack->back())); - return UnwindResult::kUnrecognizedFrame; -} - -// static -bool ChromeUnwinderAndroid::Step(RegisterContext* thread_context, - uintptr_t stack_top, - const ArmCFITable::FrameEntry& entry) { - CHECK_NE(RegisterContextStackPointer(thread_context), 0U); - CHECK_LE(RegisterContextStackPointer(thread_context), stack_top); - if (entry.cfa_offset == 0) - return StepUsingLrRegister(thread_context, stack_top); - - // The rules for unwinding using the CFI information are: - // SP_prev = SP_cur + cfa_offset and - // PC_prev = * (SP_prev - ra_offset). - auto new_sp = - CheckedNumeric<uintptr_t>(RegisterContextStackPointer(thread_context)) + - CheckedNumeric<uint16_t>(entry.cfa_offset); - if (!new_sp.AssignIfValid(&RegisterContextStackPointer(thread_context)) || - RegisterContextStackPointer(thread_context) >= stack_top) { - return false; - } - - if (entry.ra_offset > entry.cfa_offset) - return false; - - // Underflow is prevented because |ra_offset| <= |cfa_offset|. - uintptr_t ip_address = (new_sp - CheckedNumeric<uint16_t>(entry.ra_offset)) - .ValueOrDie<uintptr_t>(); - RegisterContextInstructionPointer(thread_context) = - *reinterpret_cast<uintptr_t*>(ip_address); - return true; -} - -// static -bool ChromeUnwinderAndroid::StepUsingLrRegister(RegisterContext* thread_context, - uintptr_t stack_top) { - CHECK_NE(RegisterContextStackPointer(thread_context), 0U); - CHECK_LE(RegisterContextStackPointer(thread_context), stack_top); - - uintptr_t pc = RegisterContextInstructionPointer(thread_context); - uintptr_t return_address = static_cast<uintptr_t>(thread_context->arm_lr); - - // The step failed if the pc doesn't change. - if (pc == return_address) - return false; - - RegisterContextInstructionPointer(thread_context) = return_address; - return true; -} - -} // namespace base
diff --git a/base/profiler/chrome_unwinder_android.h b/base/profiler/chrome_unwinder_android.h deleted file mode 100644 index 46728d3..0000000 --- a/base/profiler/chrome_unwinder_android.h +++ /dev/null
@@ -1,55 +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. - -#ifndef BASE_PROFILER_CHROME_UNWINDER_ANDROID_H_ -#define BASE_PROFILER_CHROME_UNWINDER_ANDROID_H_ - -#include <vector> - -#include "base/memory/raw_ptr.h" -#include "base/profiler/unwinder.h" - -#include "base/base_export.h" -#include "base/profiler/arm_cfi_table.h" -#include "base/profiler/module_cache.h" -#include "base/profiler/register_context.h" - -namespace base { - -// Chrome unwinder implementation for Android, using ArmCfiTable. -class BASE_EXPORT ChromeUnwinderAndroid : public Unwinder { - public: - ChromeUnwinderAndroid(const ArmCFITable* cfi_table, - uintptr_t chrome_module_base_address); - ~ChromeUnwinderAndroid() override; - ChromeUnwinderAndroid(const ChromeUnwinderAndroid&) = delete; - ChromeUnwinderAndroid& operator=(const ChromeUnwinderAndroid&) = delete; - - // Unwinder: - bool CanUnwindFrom(const Frame& current_frame) const override; - UnwindResult TryUnwind(RegisterContext* thread_context, - uintptr_t stack_top, - std::vector<Frame>* stack) override; - - static bool StepForTesting(RegisterContext* thread_context, - uintptr_t stack_top, - const ArmCFITable::FrameEntry& entry) { - return Step(thread_context, stack_top, entry); - } - - private: - static bool Step(RegisterContext* thread_context, - uintptr_t stack_top, - const ArmCFITable::FrameEntry& entry); - // Fallback setp that attempts to use lr as return address. - static bool StepUsingLrRegister(RegisterContext* thread_context, - uintptr_t stack_top); - - raw_ptr<const ArmCFITable> cfi_table_; - const uintptr_t chrome_module_base_address_; -}; - -} // namespace base - -#endif // BASE_PROFILER_CHROME_UNWINDER_ANDROID_H_
diff --git a/base/profiler/chrome_unwinder_android_unittest.cc b/base/profiler/chrome_unwinder_android_unittest.cc deleted file mode 100644 index 10ae0ea..0000000 --- a/base/profiler/chrome_unwinder_android_unittest.cc +++ /dev/null
@@ -1,309 +0,0 @@ -// Copyright 2019 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/profiler/chrome_unwinder_android.h" - -#include "base/android/library_loader/anchor_functions.h" -#include "base/files/file_util.h" -#include "base/profiler/profile_builder.h" -#include "base/profiler/stack_buffer.h" -#include "base/profiler/stack_copier_signal.h" -#include "base/profiler/stack_sampling_profiler_test_util.h" -#include "base/profiler/thread_delegate_posix.h" -#include "base/test/gtest_util.h" -#include "build/build_config.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Input is generated from the CFI file: -// STACK CFI INIT 100 100 -// STACK CFI 1010 .cfa: sp 8 + .ra: .cfa -4 + ^ -const uint16_t cfi_data[] = { - // UNW_INDEX size - 0x02, - 0x0, - // UNW_INDEX function_addresses (4 byte rows). - 0x100, - 0x0, - 0x200, - 0x0, - // UNW_INDEX entry_data_indices (2 byte rows). - 0x0, - 0xffff, - // UNW_DATA table. - 0x1, - 0x10, - 0x9, -}; - -// Utility function to add a single native module during test setup. Returns -// a pointer to the provided module. -const ModuleCache::Module* AddNativeModule( - ModuleCache* cache, - std::unique_ptr<const ModuleCache::Module> module) { - const ModuleCache::Module* module_ptr = module.get(); - cache->AddCustomNativeModule(std::move(module)); - return module_ptr; -} - -ArmCFITable::FrameEntry MakeFrameEntry(uint16_t cfa_offset, - uint16_t ra_offset) { - return ArmCFITable::FrameEntry{ - static_cast<uint16_t>(cfa_offset * sizeof(uintptr_t)), - static_cast<uint16_t>(ra_offset * sizeof(uintptr_t))}; -} - -} // namespace - -// Tests unwind step under normal operation. -TEST(ChromeUnwinderAndroidTest, Step) { - const std::vector<uintptr_t> stack_buffer = { - 0xFFFF, 0xFFFF, 0xFFFF, 0x1111, 0xFFFF, 0x2222, - }; - const uintptr_t stack_top = - reinterpret_cast<uintptr_t>(stack_buffer.data() + stack_buffer.size()); - RegisterContext context; - RegisterContextInstructionPointer(&context) = 0xBEEF; - RegisterContextStackPointer(&context) = - reinterpret_cast<uintptr_t>(stack_buffer.data()); - - EXPECT_TRUE(ChromeUnwinderAndroid::StepForTesting(&context, stack_top, - MakeFrameEntry(4, 1))); - EXPECT_EQ(RegisterContextInstructionPointer(&context), 0x1111U); - EXPECT_EQ(RegisterContextStackPointer(&context), - reinterpret_cast<uintptr_t>(stack_buffer.data() + 4)); - - EXPECT_TRUE(ChromeUnwinderAndroid::StepForTesting(&context, stack_top, - MakeFrameEntry(1, 0))); - EXPECT_EQ(RegisterContextInstructionPointer(&context), 0x2222U); - EXPECT_EQ(RegisterContextStackPointer(&context), - reinterpret_cast<uintptr_t>(stack_buffer.data() + 5)); -} - -// Tests unwind step using immediate return address. -TEST(ChromeUnwinderAndroidTest, StepImmediate) { - const std::vector<uintptr_t> stack_buffer = {0xFFFF, 0xFFFF}; - const uintptr_t stack_top = - reinterpret_cast<uintptr_t>(stack_buffer.data() + stack_buffer.size()); - RegisterContext context; - RegisterContextInstructionPointer(&context) = 0xBEEF; - RegisterContextStackPointer(&context) = - reinterpret_cast<uintptr_t>(stack_buffer.data()); - context.arm_lr = 0x4444; - - EXPECT_TRUE(ChromeUnwinderAndroid::StepForTesting(&context, stack_top, - MakeFrameEntry(0, 0))); - EXPECT_EQ(RegisterContextInstructionPointer(&context), 0x4444U); - EXPECT_EQ(RegisterContextStackPointer(&context), - reinterpret_cast<uintptr_t>(stack_buffer.data())); -} - -// Tests that unwinding fails if immediate return address is the current -// instruction. -TEST(ChromeUnwinderAndroidTest, StepImmediateFail) { - const std::vector<uintptr_t> stack_buffer = {0xFFFF, 0xFFFF}; - const uintptr_t stack_top = - reinterpret_cast<uintptr_t>(stack_buffer.data() + stack_buffer.size()); - - RegisterContext context; - RegisterContextInstructionPointer(&context) = 0x1111; - RegisterContextStackPointer(&context) = - reinterpret_cast<uintptr_t>(stack_buffer.data()); - context.arm_lr = 0x1111; - - EXPECT_FALSE(ChromeUnwinderAndroid::StepForTesting(&context, stack_top, - MakeFrameEntry(0, 0))); -} - -// Tests that unwinding fails if stack is invalid. -TEST(ChromeUnwinderAndroidTest, StepInvalidStack) { - const std::vector<uintptr_t> stack_buffer = {0xFFFF}; - - const uintptr_t stack_top = - reinterpret_cast<uintptr_t>(stack_buffer.data() + stack_buffer.size()); - - RegisterContext context; - EXPECT_CHECK_DEATH({ - RegisterContextStackPointer(&context) = 0; - - ChromeUnwinderAndroid::StepForTesting(&context, stack_top, - MakeFrameEntry(1, 0)); - }); - - EXPECT_CHECK_DEATH({ - RegisterContextStackPointer(&context) = reinterpret_cast<uintptr_t>( - stack_buffer.data() + stack_buffer.size() + 1); - - ChromeUnwinderAndroid::StepForTesting(&context, stack_top, - MakeFrameEntry(1, 0)); - }); -} - -// Tests that unwinding fails if the frame entry is out of bounds. -TEST(ChromeUnwinderAndroidTest, StepOutOfBounds) { - RegisterContext context; - RegisterContextInstructionPointer(&context) = 0xBEEF; - constexpr uintptr_t kOverflowOffset = 8; - constexpr size_t kStackSize = 4; - // It's fine to use a fake stack pointer since the stack won't be - // dereferenced. Purposely underflow so that sp + |kOverflowOffset| overflows. - RegisterContextStackPointer(&context) = 0 - kOverflowOffset; - const uintptr_t stack_top = - RegisterContextStackPointer(&context) + kStackSize; - - // ra_offset exceeds cfa_offset. - EXPECT_FALSE(ChromeUnwinderAndroid::StepForTesting(&context, stack_top, - MakeFrameEntry(1, 2))); - EXPECT_FALSE(ChromeUnwinderAndroid::StepForTesting( - &context, stack_top, MakeFrameEntry(1, kOverflowOffset))); - - // cfa_offset exceeds |stack_top|. - EXPECT_FALSE(ChromeUnwinderAndroid::StepForTesting( - &context, stack_top, MakeFrameEntry(kStackSize, 0))); - - // sp + cfa_offset overflows. - EXPECT_FALSE(ChromeUnwinderAndroid::StepForTesting( - &context, stack_top, MakeFrameEntry(kOverflowOffset, 0))); -} - -TEST(ChromeUnwinderAndroidTest, StepUnderflows) { - RegisterContext context; - RegisterContextInstructionPointer(&context) = 0xBEEF; - // It's fine to use a fake stack pointer since the stack won't be - // dereferenced. - RegisterContextStackPointer(&context) = 2; - const uintptr_t stack_top = RegisterContextStackPointer(&context) + 4; - - // sp + cfa_offset - ra_offset underflows. - EXPECT_FALSE(ChromeUnwinderAndroid::StepForTesting(&context, stack_top, - MakeFrameEntry(1, 4))); -} - -TEST(ChromeUnwinderAndroidTest, CanUnwindFrom) { - auto cfi_table = ArmCFITable::Parse( - {reinterpret_cast<const uint8_t*>(cfi_data), sizeof(cfi_data)}); - - auto chrome_module = std::make_unique<TestModule>(0x1000, 0x500); - auto non_chrome_module = std::make_unique<TestModule>(0x2000, 0x500); - - ModuleCache module_cache; - ChromeUnwinderAndroid unwinder(cfi_table.get(), - chrome_module->GetBaseAddress()); - unwinder.Initialize(&module_cache); - - EXPECT_TRUE(unwinder.CanUnwindFrom({0x1100, chrome_module.get()})); - EXPECT_FALSE(unwinder.CanUnwindFrom({0x2100, non_chrome_module.get()})); -} - -TEST(ChromeUnwinderAndroidTest, TryUnwind) { - auto cfi_table = ArmCFITable::Parse( - {reinterpret_cast<const uint8_t*>(cfi_data), sizeof(cfi_data)}); - - ModuleCache module_cache; - const ModuleCache::Module* chrome_module = AddNativeModule( - &module_cache, std::make_unique<TestModule>(0x1000, 0x500)); - - ChromeUnwinderAndroid unwinder(cfi_table.get(), - chrome_module->GetBaseAddress()); - unwinder.Initialize(&module_cache); - - std::vector<uintptr_t> stack_buffer = { - 0xFFFF, - // .cfa: sp 8 + .ra: .cfa -4 + ^ - 0x2000, - 0xFFFF, - }; - uintptr_t stack_top = - reinterpret_cast<uintptr_t>(stack_buffer.data() + stack_buffer.size()); - - std::vector<Frame> stack; - stack.emplace_back(0x1100, chrome_module); - - RegisterContext context; - RegisterContextInstructionPointer(&context) = 0x1100; - RegisterContextStackPointer(&context) = - reinterpret_cast<uintptr_t>(stack_buffer.data()); - context.arm_lr = 0x11AA; - - EXPECT_EQ(UnwindResult::kUnrecognizedFrame, - unwinder.TryUnwind(&context, stack_top, &stack)); - EXPECT_EQ(std::vector<Frame>({{0x1100, chrome_module}, - {0x11AA, chrome_module}, - {0x2000, nullptr}}), - stack); -} - -TEST(ChromeUnwinderAndroidTest, TryUnwindAbort) { - auto cfi_table = ArmCFITable::Parse( - {reinterpret_cast<const uint8_t*>(cfi_data), sizeof(cfi_data)}); - ASSERT_TRUE(cfi_table); - - ModuleCache module_cache; - const ModuleCache::Module* chrome_module = AddNativeModule( - &module_cache, std::make_unique<TestModule>(0x1000, 0x500)); - - ChromeUnwinderAndroid unwinder(cfi_table.get(), - chrome_module->GetBaseAddress()); - unwinder.Initialize(&module_cache); - - std::vector<uintptr_t> stack_buffer = { - 0xFFFF, - }; - uintptr_t stack_top = - reinterpret_cast<uintptr_t>(stack_buffer.data() + stack_buffer.size()); - - std::vector<Frame> stack; - stack.emplace_back(0x1100, chrome_module); - - RegisterContext context; - RegisterContextInstructionPointer(&context) = 0x1100; - RegisterContextStackPointer(&context) = - reinterpret_cast<uintptr_t>(stack_buffer.data()); - context.arm_lr = 0x1100; - - // Aborted because ra == pc. - EXPECT_EQ(UnwindResult::kAborted, - unwinder.TryUnwind(&context, stack_top, &stack)); - EXPECT_EQ(std::vector<Frame>({{0x1100, chrome_module}}), stack); -} - -TEST(ChromeUnwinderAndroidTest, TryUnwindNoData) { - auto cfi_table = ArmCFITable::Parse( - {reinterpret_cast<const uint8_t*>(cfi_data), sizeof(cfi_data)}); - - ModuleCache module_cache; - const ModuleCache::Module* chrome_module = AddNativeModule( - &module_cache, std::make_unique<TestModule>(0x1000, 0x500)); - - ChromeUnwinderAndroid unwinder(cfi_table.get(), - chrome_module->GetBaseAddress()); - unwinder.Initialize(&module_cache); - - std::vector<uintptr_t> stack_buffer = {0xFFFF}; - - uintptr_t stack_top = - reinterpret_cast<uintptr_t>(stack_buffer.data() + stack_buffer.size()); - - std::vector<Frame> stack; - stack.emplace_back(0x1200, chrome_module); - - RegisterContext context; - RegisterContextInstructionPointer(&context) = 0xBEEF; - RegisterContextStackPointer(&context) = - reinterpret_cast<uintptr_t>(stack_buffer.data()); - context.arm_lr = 0x12AA; - - // Unwinding will first use arm_lr as fallback because there's no unwind info - // for the instruction pointer, and then abort. - EXPECT_EQ(UnwindResult::kAborted, - unwinder.TryUnwind(&context, stack_top, &stack)); - EXPECT_EQ( - std::vector<Frame>({{0x1200, chrome_module}, {0x12AA, chrome_module}}), - stack); -} - -} // namespace base
diff --git a/base/profiler/stack_sampling_profiler_test_util.cc b/base/profiler/stack_sampling_profiler_test_util.cc index 2c70d58..d703d97c 100644 --- a/base/profiler/stack_sampling_profiler_test_util.cc +++ b/base/profiler/stack_sampling_profiler_test_util.cc
@@ -22,16 +22,10 @@ #if BUILDFLAG(IS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE) #include "base/android/apk_assets.h" -#include "base/files/memory_mapped_file.h" -#include "base/profiler/native_unwinder_android.h" - -#if BUILDFLAG(USE_ANDROID_UNWINDER_V2) #include "base/android/library_loader/anchor_functions.h" +#include "base/files/memory_mapped_file.h" #include "base/profiler/chrome_unwinder_android_v2.h" -#else -#include "base/profiler/chrome_unwinder_android.h" -#endif - +#include "base/profiler/native_unwinder_android.h" #endif #if BUILDFLAG(IS_WIN) @@ -127,7 +121,6 @@ std::move(maps), std::move(memory), exclude_module_with_base_address); } -#if BUILDFLAG(USE_ANDROID_UNWINDER_V2) std::unique_ptr<Unwinder> CreateChromeUnwinderAndroidForTesting( uintptr_t chrome_module_base_address) { static constexpr char kCfiFileName[] = "assets/unwind_cfi_32_v2"; @@ -163,41 +156,6 @@ chrome_module_base_address, /* text_section_start_address= */ base::android::kStartOfText); } -#else -std::unique_ptr<Unwinder> CreateChromeUnwinderAndroidForTesting( - uintptr_t chrome_module_base_address) { - static constexpr char kCfiFileName[] = "assets/unwind_cfi_32"; - - // The wrapper class ensures that `MemoryMappedFile` has the same lifetime - // as the unwinder. - class ChromeUnwinderAndroidForTesting : public ChromeUnwinderAndroid { - public: - ChromeUnwinderAndroidForTesting(std::unique_ptr<MemoryMappedFile> cfi_file, - std::unique_ptr<ArmCFITable> cfi_table, - uintptr_t chrome_module_base_address) - : ChromeUnwinderAndroid(cfi_table.get(), chrome_module_base_address), - cfi_file_(std::move(cfi_file)), - cfi_table_(std::move(cfi_table)) {} - ~ChromeUnwinderAndroidForTesting() override = default; - - private: - std::unique_ptr<MemoryMappedFile> cfi_file_; - std::unique_ptr<ArmCFITable> cfi_table_; - }; - - MemoryMappedFile::Region cfi_region; - int fd = base::android::OpenApkAsset(kCfiFileName, &cfi_region); - DCHECK_GT(fd, 0); - auto cfi_file = std::make_unique<MemoryMappedFile>(); - bool ok = cfi_file->Initialize(base::File(fd), cfi_region); - DCHECK(ok); - std::unique_ptr<ArmCFITable> cfi_table = - ArmCFITable::Parse({cfi_file->data(), cfi_file->length()}); - DCHECK(cfi_table); - return std::make_unique<ChromeUnwinderAndroidForTesting>( - std::move(cfi_file), std::move(cfi_table), chrome_module_base_address); -} -#endif // #if BUILDFLAG(USE_ANDROID_UNWINDER_V2) #endif // #if BUILDFLAG(IS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE) } // namespace
diff --git a/base/task/thread_pool/delayed_task_manager.h b/base/task/thread_pool/delayed_task_manager.h index 4196143..59fbef0 100644 --- a/base/task/thread_pool/delayed_task_manager.h +++ b/base/task/thread_pool/delayed_task_manager.h
@@ -121,7 +121,7 @@ // it is never modified. It is therefore safe to access // |service_thread_task_runner_| without synchronization once it is observed // that it is non-null. - mutable CheckedLock queue_lock_; + mutable CheckedLock queue_lock_{UniversalSuccessor()}; scoped_refptr<SequencedTaskRunner> service_thread_task_runner_;
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h index 24498ec6..e1b4f49 100644 --- a/base/threading/thread_restrictions.h +++ b/base/threading/thread_restrictions.h
@@ -132,6 +132,7 @@ namespace android_webview { class AwFormDatabaseService; class CookieManager; +class JsSandboxIsolate; class ScopedAllowInitGLBindings; class VizCompositorThreadRunnerWebView; } // namespace android_webview @@ -683,6 +684,7 @@ // Allowed usage: friend class ::ChromeNSSCryptoModuleDelegate; + friend class android_webview::JsSandboxIsolate; friend class base::internal::GetAppOutputScopedAllowBaseSyncPrimitives; friend class base::SimpleThread; friend class blink::CategorizedWorkerPoolImpl;
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 958f33a..efba847 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn
@@ -615,8 +615,13 @@ # # As remote execution requires inputs to be made more explicit than is normally # expected with gn, you may find that setting allow_remote to true will result -# in many missing file errors. This should be resolved by explicitly declaring -# these inputs/sources. +# in many missing file errors. In most cases, this should be resolved by +# explicitly declaring these inputs/sources. +# +# However, it may be impractical to determine these inputs in gn. For such +# cases, the invoker can specify a custom input processor, which are currently +# defined and implemented in //build/util/action_remote.py. The appropriate +# value should be set using the custom_processor arg. # Variables needed by rbe.gni aren't available at the top of this file. import("//build/toolchain/rbe.gni")
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni index fa665e3f..e0d44ee 100644 --- a/build/config/compiler/compiler.gni +++ b/build/config/compiler/compiler.gni
@@ -151,8 +151,8 @@ # Use offsets rather than pointers in vtables in order to reduce the number of # relocations. This is safe to enable only when all C++ code is built with the # flag set to the same value. - use_relative_vtables_abi = - is_android && use_custom_libcxx && !is_component_build + use_relative_vtables_abi = is_android && current_cpu == "arm64" && + use_custom_libcxx && !is_component_build } assert(!is_cfi || use_thin_lto, "CFI requires ThinLTO")
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1 index fc3b270..ef17b54 100644 --- a/build/fuchsia/linux_internal.sdk.sha1 +++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@ -10.20221123.1.1 +10.20221123.2.1
diff --git a/build/util/action_remote.py b/build/util/action_remote.py index 021c871..1e9517d 100755 --- a/build/util/action_remote.py +++ b/build/util/action_remote.py
@@ -2,16 +2,129 @@ # 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. -"""Wrapper script to run action remotely through rewrapper with gn.""" +"""Wrapper script to run action remotely through rewrapper with gn. +Also includes Chromium-specific input processors which don't make sense to +be reclient inbuilt input processors.""" + +import argparse +import json +import os import subprocess import sys +from enum import Enum + + +class CustomProcessor(Enum): + mojom_parser = 'mojom_parser' + + def __str__(self): + return self.value + + +def _process_build_metadata_json(bm_file, exec_root, working_dir, output_root, + re_outputs, processed_inputs): + """Recursively find mojom_parser inputs from a build_metadata file.""" + if bm_file in processed_inputs: + return + + processed_inputs.add(bm_file) + + bm_dir = os.path.dirname(bm_file) + wd_rel = os.path.relpath(working_dir, exec_root) + + with open(bm_file) as f: + bm = json.load(f) + + # All sources and corresponding module files are inputs. + for s in bm["sources"]: + src = os.path.normpath(os.path.join(bm_dir, s)) + if src not in processed_inputs and os.path.exists(src): + processed_inputs.add(src) + src_module = os.path.normpath( + os.path.join(output_root, os.path.join(wd_rel, src + "-module"))) + if src_module in re_outputs: + continue + if src_module not in processed_inputs and os.path.exists(src_module): + processed_inputs.add(src_module) + + # Recurse into build_metadata deps. + for d in bm["deps"]: + dep = os.path.normpath(os.path.join(bm_dir, d)) + _process_build_metadata_json(dep, exec_root, working_dir, output_root, + re_outputs, processed_inputs) + + +def _get_mojom_parser_inputs(exec_root, output_files, extra_args): + """Get mojom inputs by walking generated build_metadata files. + + This is less complexity and disk I/O compared to parsing mojom files for + imports and finding all imports. + + Start from the root build_metadata file passed to mojom_parser's + --check-imports flag. + """ + argparser = argparse.ArgumentParser() + argparser.add_argument('--check-imports', dest='check_imports', required=True) + argparser.add_argument('--output-root', dest='output_root', required=True) + mojom_parser_args, _ = argparser.parse_known_args(args=extra_args) + + processed_inputs = set() + _process_build_metadata_json(mojom_parser_args.check_imports, exec_root, + os.getcwd(), mojom_parser_args.output_root, + output_files, processed_inputs) + + # Rebase paths onto rewrapper exec root. + return map(lambda dep: os.path.normpath(os.path.relpath(dep, exec_root)), + processed_inputs) def main(): - # Pass through all args. Use check=True to ensure failure is raised. - args = sys.argv[1:] - proc = subprocess.run(args, check=True) + # Set up argparser with some rewrapper flags. + argparser = argparse.ArgumentParser(description='rewrapper executor for gn', + allow_abbrev=False) + argparser.add_argument('--custom_processor', + type=CustomProcessor, + choices=list(CustomProcessor)) + argparser.add_argument('rewrapper_path') + argparser.add_argument('--input_list_paths') + argparser.add_argument('--output_list_paths') + argparser.add_argument('--exec_root') + parsed_args, extra_args = argparser.parse_known_args() + + # This script expects to be calling rewrapper. + args = [parsed_args.rewrapper_path] + + # Get the output files list. + output_files = set() + with open(parsed_args.output_list_paths, 'r') as file: + for line in file: + output_files.add(line.rstrip('\n')) + + # Scan for and add explicit inputs for rewrapper if necessary. + # These should be in a new input list paths file, as using --inputs can fail + # if the list is extremely large. + if parsed_args.custom_processor == CustomProcessor.mojom_parser: + root, ext = os.path.splitext(parsed_args.input_list_paths) + extra_inputs = _get_mojom_parser_inputs(parsed_args.exec_root, output_files, + extra_args) + extra_input_list_path = '%s__extra%s' % (root, ext) + with open(extra_input_list_path, 'w') as file: + with open(parsed_args.input_list_paths, 'r') as inputs: + file.write(inputs.read()) + file.write("\n".join(extra_inputs)) + args += ["--input_list_paths=%s" % extra_input_list_path] + else: + args += ["--input_list_paths=%s" % parsed_args.input_list_paths] + + # Filter out --custom_processor= which is a flag for this script, + # and filter out --input_list_paths= because we replace it above. + # Pass on the rest of the args to rewrapper. + args_rest = filter(lambda arg: '--custom_processor=' not in arg, sys.argv[2:]) + args += filter(lambda arg: '--input_list_paths=' not in arg, args_rest) + + # Run rewrapper. + proc = subprocess.run(args) return proc.returncode
diff --git a/chrome/VERSION b/chrome/VERSION index 2c61ee02..35dc66a 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=110 MINOR=0 -BUILD=5437 +BUILD=5439 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 66f3610..d84f0d55 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1089,6 +1089,7 @@ "//chrome/browser/tabmodel/internal:java", "//chrome/browser/tabpersistence:junit", "//chrome/browser/thumbnail:java", + "//chrome/browser/touch_to_fill/payments/android/internal:junit", "//chrome/browser/ui/android/appmenu:java", "//chrome/browser/ui/android/appmenu/internal:junit", "//chrome/browser/ui/android/autofill/internal:junit", @@ -3242,6 +3243,7 @@ "//chrome/browser/password_check/android:test_java", "//chrome/browser/subresource_filter:subresource_filter_javatests", "//chrome/browser/touch_to_fill/android:test_java", + "//chrome/browser/touch_to_fill/payments/android/internal:javatests", "//chrome/browser/ui/android/fast_checkout/internal:javatests", "//chrome/browser/ui/android/omnibox:javatests", "//chrome/browser/ui/android/webid/internal:javatests",
diff --git a/chrome/android/java/res/values/styles.xml b/chrome/android/java/res/values/styles.xml index 9101e45..3eac01b9 100644 --- a/chrome/android/java/res/values/styles.xml +++ b/chrome/android/java/res/values/styles.xml
@@ -439,10 +439,6 @@ <!-- TODO(https://crbug.com/1216642): Move color attributes here. --> </style> - <style name="ThemeOverlay.DisableOverscroll" parent=""> - <item name="android:overScrollMode">never</item> - </style> - <!-- Dialog for notification blocked message. --> <style name="NotificationBlockedDialogContent" parent="AlertDialogContent"> <item name="android:paddingBottom">12dp</item>
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 beeefaef..76becf7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBaseAppCompatActivity.java
@@ -31,7 +31,6 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.base.ServiceTracingProxyProvider; import org.chromium.chrome.browser.base.SplitChromeApplication; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.language.GlobalAppLocaleController; import org.chromium.chrome.browser.metrics.UmaSessionStats; import org.chromium.chrome.browser.night_mode.GlobalNightModeStateProviderHolder; @@ -243,17 +242,6 @@ UmaSessionStats.registerSyntheticFieldTrial( "IsDynamicColorAvailable", isDynamicColorAvailable ? "Enabled" : "Disabled"); }); - - // Try to enable browser overscroll when content overscroll is enabled for consistency. This - // needs to be in a cached feature because activity startup happens before native is - // initialized. Unfortunately content overscroll is read in renderer threads, and these two - // are not synchronized. Typically the first time overscroll is enabled, the following will - // use the old value and then content will pick up the enabled value, causing one execution - // of inconsistency. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S - && !ChromeFeatureList.sElasticOverscroll.isEnabled()) { - setTheme(R.style.ThemeOverlay_DisableOverscroll); - } } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java index c7580d9..56f1431 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -101,7 +101,6 @@ add(ChromeFeatureList.sDiscardOccludedBitmaps); add(ChromeFeatureList.sDownloadsAutoResumptionNative); add(ChromeFeatureList.sEarlyLibraryLoad); - add(ChromeFeatureList.sElasticOverscroll); add(ChromeFeatureList.sFeedLoadingPlaceholder); add(ChromeFeatureList.sFoldableJankFix); add(ChromeFeatureList.sGridTabSwitcherForTablets);
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index e602cbe..49d999f1 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -758,6 +758,27 @@ chromeos::LacrosInitializeDBus(); #endif +#if BUILDFLAG(IS_CHROMEOS_LACROS) + // Set Lacros's default paths. + // + // NOTE: When launching Lacros at login screen, this is the first access + // to post-login parameters. In other words, this is as far as Lacros + // initialization will go at login screen. The browser process will block + // here. + // + // IMPORTANT NOTE: If your code requires access to post-login parameters + // (which are only known after login), please place them *after* this call. + chrome::SetLacrosDefaultPathsFromInitParams( + chromeos::BrowserParamsProxy::Get()->DefaultPaths().get()); + + // NOTE: When launching Lacros at login screen, after this point, + // the user should have logged in. The cryptohome is now accessible. + + // Redirect logs from system directory to cryptohome. + if (chromeos::IsLaunchedWithPostLoginParams()) + RedirectLacrosLogging(); +#endif // BUILDFLAG(IS_CHROMEOS_LACROS) + // The DBus initialization above is needed for FeatureList creation here; // features are needed for Mojo initialization; and Mojo initialization is // needed for LacrosService initialization below. @@ -769,21 +790,6 @@ content::InitializeMojoCore(); #if BUILDFLAG(IS_CHROMEOS_LACROS) - // Set Lacros's default paths. - // NOTE: When launching Lacros at login screen, this is the first access - // to post-login parameters. In other words, this is as far as Lacros - // initialization will go at login screen. - // The browser process will block here. - chrome::SetLacrosDefaultPathsFromInitParams( - chromeos::BrowserParamsProxy::Get()->DefaultPaths().get()); - - // NOTE: When launching Lacros at login screen, after this point, - // the user should have logged in. The cryptohome is now accessible. - - // Redirect logs from system directory to cryptohome. - if (chromeos::IsLaunchedWithPostLoginParams()) - RedirectLacrosLogging(); - // LacrosService instance needs the sequence of the main thread, // and needs to be created earlier than incoming Mojo invitation handling. // This also needs ThreadPool sequences to post some tasks internally.
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index b311fc3..cc4f9a5 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -2044,11 +2044,16 @@ </message> <message name="IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_PRIMARY_LABEL" desc="'Review Notification Permissions' shows the websites that send a lot of notifications. This label is the header of the module in the site settings notification page. The number represents the number of notification permissions to be reviewed."> {NUM_SITES, plural, - =1 {Review 1 site that recently sent a lot of notifications} - other {Review {NUM_SITES} sites that recently sent a lot of notifications}} + =1 {Review 1 site that sent a lot of notifications} + other {Review {NUM_SITES} sites that sent a lot of notifications}} + </message> + <message name="IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSIONS_REVIEW_BUTTON_ARIA_LABEL" desc="'Review Notification Permissions' shows the websites that send a lot of notifications. This label is used for the ARIA label of the button of the module in the site settings notification page."> + Review notification permissions </message> <message name="IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_SECONDARY_LABEL" desc="'Review Notification Permissions' shows the websites that send a lot of notifications. This label is the description of the module in site settings notification page."> - These sites sent a lot of notifications recently. You can stop them from sending future notifications. + {NUM_SITES, plural, + =1 {This site sent a lot of notifications recently. You can stop it from sending future notifications.} + other {These sites sent a lot of notifications recently. You can stop them from sending future notifications.}} </message> <message name="IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_IGNORED_TOAST_LABEL" desc="'Review Notification Permissions' shows the websites that send a lot of notifications. This label is to indicate for which site the user has explicitly allowed permissions."> Notifications allowed for <ph name="SITE">$1<ex>www.example.com</ex></ph> @@ -2236,7 +2241,7 @@ <message name="IDS_SETTINGS_PERMISSIONS" desc="Name of the settings page which allows users to manage permissions and site content settings"> Permissions and content settings </message> - <message name="IDS_SETTINGS_PERMISSIONS_DESCRIPTION" desc="Description of the controls available on the permisisons and site content settings page"> + <message name="IDS_SETTINGS_PERMISSIONS_DESCRIPTION" desc="Description of the controls available on the permissions and site content settings page"> Controls what information sites can use and show (location, camera, pop-ups, and more) </message> <message name="IDS_SETTINGS_SECURITY" desc="Name of the settings page which allows
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSIONS_REVIEW_BUTTON_ARIA_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSIONS_REVIEW_BUTTON_ARIA_LABEL.png.sha1 new file mode 100644 index 0000000..c482a97 --- /dev/null +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSIONS_REVIEW_BUTTON_ARIA_LABEL.png.sha1
@@ -0,0 +1 @@ +bf146724fac63bd8d116d4095bcab10b5d66e998 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_PRIMARY_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_PRIMARY_LABEL.png.sha1 index 8e2742d..07877ba9 100644 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_PRIMARY_LABEL.png.sha1 +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_PRIMARY_LABEL.png.sha1
@@ -1 +1 @@ -2046a724d4a713393a02bf4fd77dc28d90fec4ae \ No newline at end of file +8b5b7c8d959bea2a8bf7d31243aba0d0466da239 \ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_SECONDARY_LABEL.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_SECONDARY_LABEL.png.sha1 index cc8a5ce..0a1f8f8 100644 --- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_SECONDARY_LABEL.png.sha1 +++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_SECONDARY_LABEL.png.sha1
@@ -1 +1 @@ -0bcca247ab3656ade7ed536b7a41c7fa2a986be3 \ No newline at end of file +31d9b8d63ca573006b132cf2992dc31ba0ddc376 \ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 9331b71..b6fd4f39 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -95,6 +95,7 @@ buildflag_header("buildflags") { header = "buildflags.h" flags = [ + "ENABLE_UPDATER=$enable_updater", "ENABLE_UPDATE_NOTIFICATIONS=$enable_update_notifications", "USE_MINIKIN_HYPHENATION=$use_minikin_hyphenation", "USE_THIN_LTO=$use_thin_lto", @@ -6975,6 +6976,13 @@ } } + if (enable_bound_session_credentials) { + sources += [ + "signin/bound_session_credentials/bound_session_cookie_fetcher.cc", + "signin/bound_session_credentials/bound_session_cookie_fetcher.h", + ] + } + if (enable_media_remoting) { sources += [ "media/cast_remoting_connector.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 3def3cc..f700857 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -2727,22 +2727,6 @@ nullptr}}; #if BUILDFLAG(IS_ANDROID) -// The variations of --touch-to-fill-password-submission. -const FeatureEntry::FeatureParam - kTouchToFillPasswordSubmissionWithConservativeHeuristics[] = { - {password_manager::features:: - kTouchToFillPasswordSubmissionWithConservativeHeuristics, - "true"}}; - -const FeatureEntry::FeatureVariation - kTouchToFillPasswordSubmissionVariations[] = { - {"Use conservative heuristics", - kTouchToFillPasswordSubmissionWithConservativeHeuristics, - std::size(kTouchToFillPasswordSubmissionWithConservativeHeuristics), - nullptr}}; -#endif // BUILDFLAG(IS_ANDROID) - -#if BUILDFLAG(IS_ANDROID) // The variations of --metrics-settings-android. const FeatureEntry::FeatureParam kMetricsSettingsAndroidAlternativeOne[] = { {"fre", "1"}}; @@ -8201,13 +8185,6 @@ flag_descriptions::kBiometricReauthForPasswordFillingDescription, kOsAndroid, FEATURE_VALUE_TYPE(password_manager::features::kBiometricTouchToFill)}, - {"touch-to-fill-password-submission", - flag_descriptions::kTouchToFillPasswordSubmissionName, - flag_descriptions::kTouchToFillPasswordSubmissionDescription, kOsAndroid, - FEATURE_WITH_PARAMS_VALUE_TYPE( - password_manager::features::kTouchToFillPasswordSubmission, - kTouchToFillPasswordSubmissionVariations, - "TouchToFillPasswordSubmission")}, {"fast-checkout", flag_descriptions::kFastCheckoutName, flag_descriptions::kFastCheckoutDescription, kOsAndroid, FEATURE_VALUE_TYPE(features::kFastCheckout)},
diff --git a/chrome/browser/apps/app_service/app_icon/app_icon_factory.cc b/chrome/browser/apps/app_service/app_icon/app_icon_factory.cc index 47e07a3..afe5ff1 100644 --- a/chrome/browser/apps/app_service/app_icon/app_icon_factory.cc +++ b/chrome/browser/apps/app_service/app_icon/app_icon_factory.cc
@@ -489,6 +489,30 @@ web_app_provider->icon_manager(), Profile::FromBrowserContext(context)); } +#if BUILDFLAG(IS_CHROMEOS_ASH) +void GetWebAppCompressedIconData(content::BrowserContext* context, + const std::string& web_app_id, + IconEffects icon_effects, + IconType icon_type, + int size_in_dip, + ui::ResourceScaleFactor scale_factor, + LoadIconCallback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(context); + web_app::WebAppProvider* web_app_provider = + web_app::WebAppProvider::GetForLocalAppsUnchecked( + Profile::FromBrowserContext(context)); + + DCHECK(web_app_provider); + scoped_refptr<AppIconLoader> icon_loader = + base::MakeRefCounted<AppIconLoader>( + icon_type, size_in_dip, /*is_placeholder_icon=*/false, icon_effects, + kInvalidIconResource, std::move(callback)); + icon_loader->GetWebAppCompressedIconData(web_app_id, scale_factor, + web_app_provider->icon_manager()); +} +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + void LoadIconFromFileWithFallback( IconType icon_type, int size_hint_in_dip,
diff --git a/chrome/browser/apps/app_service/app_icon/app_icon_factory.h b/chrome/browser/apps/app_service/app_icon/app_icon_factory.h index 76a48e2..495f690 100644 --- a/chrome/browser/apps/app_service/app_icon/app_icon_factory.h +++ b/chrome/browser/apps/app_service/app_icon/app_icon_factory.h
@@ -20,6 +20,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/components/arc/mojom/app.mojom.h" #include "ash/components/arc/mojom/intent_helper.mojom.h" +#include "ui/base/resource/resource_scale_factor.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH) namespace content { @@ -105,6 +106,17 @@ IconEffects icon_effects, LoadIconCallback callback); +#if BUILDFLAG(IS_CHROMEOS_ASH) +// Requests a compressed icon data for an web app identified by `app_id`. +void GetWebAppCompressedIconData(content::BrowserContext* context, + const std::string& web_app_id, + IconEffects icon_effects, + IconType icon_type, + int size_in_dip, + ui::ResourceScaleFactor scale_factor, + LoadIconCallback callback); +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + // Loads an icon from a FilePath. If that fails, it calls the fallback. // // The file named by |path| might be empty, not found or otherwise unreadable.
diff --git a/chrome/browser/apps/app_service/app_icon/app_icon_loader.cc b/chrome/browser/apps/app_service/app_icon/app_icon_loader.cc index f7db986..9a53363 100644 --- a/chrome/browser/apps/app_service/app_icon/app_icon_loader.cc +++ b/chrome/browser/apps/app_service/app_icon/app_icon_loader.cc
@@ -649,6 +649,69 @@ } } +void AppIconLoader::GetWebAppCompressedIconData( + const std::string& web_app_id, + ui::ResourceScaleFactor scale_factor, + web_app::WebAppIconManager& icon_manager) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + absl::optional<IconPurpose> icon_purpose_to_read = + GetIconPurpose(web_app_id, icon_manager, size_hint_in_dip_); + + if (!icon_purpose_to_read.has_value()) { + MaybeLoadFallbackOrCompleteEmpty(); + return; + } + + icon_scale_ = ui::GetScaleForResourceScaleFactor(scale_factor); + icon_size_in_px_ = + apps_util::ConvertDipToPxForScale(size_hint_in_dip_, icon_scale_); + + auto size_and_purpose = icon_manager.FindIconMatchBigger( + web_app_id, {*icon_purpose_to_read}, icon_size_in_px_); + DCHECK(size_and_purpose.has_value()); + + switch (icon_type_) { + case IconType::kCompressed: + // Only read IconPurpose::ANY icons compressed as other purposes would + // need to find the icon size to match the icon purpose. + // + // If the icon px size returned from FindIconMatchBigger doesn't match + // icon_size_in_px_, the returned compressed icon should be resized, so + // ReadSmallestCompressedIconAny can't be used. + // + // If `icon_effects_` is not none, the icon needs to be converted to the + // uncompressed icon to apply the icon effects. So ReadIcons is used to + // get the icon to match the size in px and icon purpose to keep the + // consistent implementation with LoadWebAppIcon. + if (icon_effects_ == apps::IconEffects::kNone && + *icon_purpose_to_read == IconPurpose::ANY && + icon_size_in_px_ == size_and_purpose->size_px) { + icon_manager.ReadSmallestCompressedIconAny( + web_app_id, icon_size_in_px_, + base::BindOnce(&AppIconLoader::CompleteWithCompressed, + base::WrapRefCounted(this))); + return; + } + [[fallthrough]]; + case IconType::kUncompressed: + [[fallthrough]]; + case IconType::kStandard: { + std::vector<int> icon_pixel_sizes; + icon_pixel_sizes.emplace_back(size_and_purpose->size_px); + icon_manager.ReadIcons( + web_app_id, *icon_purpose_to_read, icon_pixel_sizes, + base::BindOnce(&AppIconLoader::OnReadWebAppForCompressedIconData, + base::WrapRefCounted(this))); + return; + } + case IconType::kUnknown: + MaybeLoadFallbackOrCompleteEmpty(); + return; + } + NOTREACHED(); +} + std::unique_ptr<arc::IconDecodeRequest> AppIconLoader::CreateArcIconDecodeRequest( base::OnceCallback<void(const gfx::ImageSkia& icon)> callback, @@ -735,7 +798,6 @@ } void AppIconLoader::CompleteWithCompressed(std::vector<uint8_t> data) { - DCHECK_EQ(icon_type_, IconType::kCompressed); if (data.empty()) { MaybeLoadFallbackOrCompleteEmpty(); return; @@ -822,6 +884,30 @@ MaybeApplyEffectsAndComplete(image_skia); } +void AppIconLoader::OnReadWebAppForCompressedIconData( + std::map<int, SkBitmap> icon_bitmaps) { + if (icon_bitmaps.empty()) { + MaybeLoadFallbackOrCompleteEmpty(); + return; + } + + SkBitmap bitmap = icon_bitmaps.begin()->second; + + // Resize |bitmap| to match |icon_scale|. + bitmap = skia::ImageOperations::Resize(bitmap, + skia::ImageOperations::RESIZE_LANCZOS3, + icon_size_in_px_, icon_size_in_px_); + + gfx::ImageSkia image_skia; + image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, icon_scale_)); + image_skia.MakeThreadSafe(); + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&apps::EncodeImageToPngBytes, image_skia, icon_scale_), + base::BindOnce(&AppIconLoader::CompleteWithCompressed, + base::WrapRefCounted(this))); +} + void AppIconLoader::MaybeLoadFallbackOrCompleteEmpty() { if (fallback_favicon_url_.is_valid() && icon_size_in_px_ == kFaviconFallbackImagePx) {
diff --git a/chrome/browser/apps/app_service/app_icon/app_icon_loader.h b/chrome/browser/apps/app_service/app_icon/app_icon_loader.h index a39475f..5491fe1 100644 --- a/chrome/browser/apps/app_service/app_icon/app_icon_loader.h +++ b/chrome/browser/apps/app_service/app_icon/app_icon_loader.h
@@ -22,6 +22,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) #include "ash/components/arc/mojom/intent_helper.mojom.h" +#include "ui/base/resource/resource_scale_factor.h" #endif // BUILDFLAG(IS_CHROMEOS_ASH) namespace arc { @@ -111,6 +112,12 @@ // Loads icons for ARC activities. void LoadArcActivityIcons( const std::vector<arc::mojom::ActivityIconPtr>& icons); + + // Requests a compressed icon data with `scale_factor` for an web app + // identified by `app_id`. + void GetWebAppCompressedIconData(const std::string& web_app_id, + ui::ResourceScaleFactor scale_factor, + web_app::WebAppIconManager& icon_manager); #endif // BUILDFLAG(IS_CHROMEOS_ASH) private: @@ -142,15 +149,17 @@ void OnReadWebAppIcon(std::map<int, SkBitmap> icon_bitmaps); + void OnReadWebAppForCompressedIconData(std::map<int, SkBitmap> icon_bitmaps); + void MaybeLoadFallbackOrCompleteEmpty(); const IconType icon_type_ = IconType::kUnknown; const int size_hint_in_dip_ = 0; - const int icon_size_in_px_ = 0; + int icon_size_in_px_ = 0; // The scale factor the icon is intended for. See gfx::ImageSkiaRep::scale // comments. - const float icon_scale_ = 0.0f; + float icon_scale_ = 0.0f; // A scale factor to take as input for the IconType::kCompressed response. See // gfx::ImageSkia::GetRepresentation() comments. float icon_scale_for_compressed_response_ = 1.0f;
diff --git a/chrome/browser/apps/app_service/app_icon/web_app_icon_unittest.cc b/chrome/browser/apps/app_service/app_icon/web_app_icon_unittest.cc index 741b01c1..dfe2d65 100644 --- a/chrome/browser/apps/app_service/app_icon/web_app_icon_unittest.cc +++ b/chrome/browser/apps/app_service/app_icon/web_app_icon_unittest.cc
@@ -54,6 +54,7 @@ #include "chrome/browser/ui/app_list/md_icon_normalizer.h" #include "chrome/common/chrome_features.h" #include "chrome/grit/chrome_unscaled_resources.h" +#include "ui/base/resource/resource_scale_factor.h" #endif namespace apps { @@ -126,7 +127,8 @@ IconPurpose purpose, const std::vector<int>& sizes_px, apps::ScaleToSize scale_to_size_in_px, - gfx::ImageSkia& output_image_skia) { + gfx::ImageSkia& output_image_skia, + bool skip_icon_effects = false) { base::RunLoop run_loop; icon_manager().ReadIcons( app_id, purpose, sizes_px, @@ -156,20 +158,22 @@ run_loop.QuitClosure())); run_loop.Run(); - extensions::ChromeAppIcon::ResizeFunction resize_function; + if (!skip_icon_effects) { + extensions::ChromeAppIcon::ResizeFunction resize_function; #if BUILDFLAG(IS_CHROMEOS_ASH) - if (purpose == IconPurpose::ANY) { - output_image_skia = apps::CreateStandardIconImage(output_image_skia); - } - if (purpose == IconPurpose::MASKABLE) { - output_image_skia = apps::ApplyBackgroundAndMask(output_image_skia); - } + if (purpose == IconPurpose::ANY) { + output_image_skia = apps::CreateStandardIconImage(output_image_skia); + } + if (purpose == IconPurpose::MASKABLE) { + output_image_skia = apps::ApplyBackgroundAndMask(output_image_skia); + } #endif - extensions::ChromeAppIcon::ApplyEffects( - kSizeInDip, resize_function, true /* app_launchable */, - true /* from_bookmark */, extensions::ChromeAppIcon::Badge::kNone, - &output_image_skia); + extensions::ChromeAppIcon::ApplyEffects( + kSizeInDip, resize_function, true /* app_launchable */, + true /* from_bookmark */, extensions::ChromeAppIcon::Badge::kNone, + &output_image_skia); + } EnsureRepresentationsLoaded(output_image_skia); } @@ -194,6 +198,26 @@ &result)); } + void GenerateWebAppCompressedIcon(const std::string& app_id, + IconPurpose purpose, + const std::vector<int>& sizes_px, + apps::ScaleToSize scale_to_size_in_px, + float scale, + std::vector<uint8_t>& result) { + gfx::ImageSkia image_skia; + GenerateWebAppIcon(app_id, purpose, sizes_px, scale_to_size_in_px, + image_skia, /*skip_icon_effects=*/true); + + const gfx::ImageSkiaRep& image_skia_rep = + image_skia.GetRepresentation(scale); + ASSERT_EQ(image_skia_rep.scale(), scale); + + const SkBitmap& bitmap = image_skia_rep.GetBitmap(); + const bool discard_transparency = false; + ASSERT_TRUE(gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, discard_transparency, + &result)); + } + std::vector<uint8_t> GenerateWebAppNonEffectCompressedIcon( const std::string& app_id, const SquareSizePx icon_size_in_px) { @@ -242,6 +266,20 @@ return icon_value; } +#if BUILDFLAG(IS_CHROMEOS_ASH) + apps::IconValuePtr GetWebAppCompressedIconData( + const std::string& app_id, + IconEffects icon_effects, + IconType icon_type, + ui::ResourceScaleFactor scale_factor) { + base::test::TestFuture<apps::IconValuePtr> result; + apps::GetWebAppCompressedIconData(profile(), app_id, icon_effects, + icon_type, kSizeInDip, scale_factor, + result.GetCallback()); + return result.Take(); + } +#endif // BUILDFLAG(IS_CHROMEOS_ASH) + web_app::WebAppIconManager& icon_manager() { return *icon_manager_; } web_app::WebAppProvider& web_app_provider() { return *web_app_provider_; } @@ -709,6 +747,263 @@ DCHECK(image.isNull()); } +TEST_F(WebAppIconFactoryTest, GetNonMaskableCompressedIconData) { + auto web_app = web_app::test::CreateWebApp(); + const std::string app_id = web_app->app_id(); + + const float scale1 = 1.0; + const float scale2 = 2.0; + const int kIconSize1 = kSizeInDip * scale1; + const int kIconSize2 = kSizeInDip * scale2; + const std::vector<int> sizes_px{kIconSize1, kIconSize2}; + const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW}; + WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors); + + web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px); + RegisterApp(std::move(web_app)); + + ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px)); + + std::vector<uint8_t> src_data1; + std::vector<uint8_t> src_data2; + apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1}, + {2.0, kIconSize2}}; + GenerateWebAppCompressedIcon(app_id, IconPurpose::ANY, sizes_px, + scale_to_size_in_px, scale1, src_data1); + GenerateWebAppCompressedIcon(app_id, IconPurpose::ANY, sizes_px, + scale_to_size_in_px, scale2, src_data2); + + // Verift getting the compressed icon data for the compressed icon with icon + // effects. + auto icon1 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kRoundCorners, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k100Percent); + auto icon2 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kRoundCorners, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon1); + VerifyCompressedIcon(src_data2, *icon2); +} + +TEST_F(WebAppIconFactoryTest, + GetNonMaskableCompressedIconDataWithDifferentSizeIcon) { + auto web_app = web_app::test::CreateWebApp(); + const std::string app_id = web_app->app_id(); + + const float scale1 = 1.0; + const float scale2 = 2.0; + const int kIconSize1 = 96; + const int kIconSize2 = 256; + const std::vector<int> sizes_px{kIconSize1, kIconSize2}; + const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW}; + WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors); + + web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px); + RegisterApp(std::move(web_app)); + + ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px)); + + std::vector<uint8_t> src_data1; + std::vector<uint8_t> src_data2; + apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1}, + {2.0, kIconSize2}}; + GenerateWebAppCompressedIcon(app_id, IconPurpose::ANY, sizes_px, + scale_to_size_in_px, scale1, src_data1); + GenerateWebAppCompressedIcon(app_id, IconPurpose::ANY, sizes_px, + scale_to_size_in_px, scale2, src_data2); + + // Verift getting the compressed icon data for the compressed icon with icon + // effects. + auto icon1 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kRoundCorners, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k100Percent); + auto icon2 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kRoundCorners, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon1); + VerifyCompressedIcon(src_data2, *icon2); + + // Verift getting the compressed icon data for the uncompressed icon. + auto icon3 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kUncompressed, + ui::ResourceScaleFactor::k100Percent); + auto icon4 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kUncompressed, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon3); + VerifyCompressedIcon(src_data2, *icon4); + + // Verift getting the compressed icon data for the standard icon. + auto icon5 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kStandard, + ui::ResourceScaleFactor::k100Percent); + auto icon6 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kStandard, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon5); + VerifyCompressedIcon(src_data2, *icon6); +} + +TEST_F(WebAppIconFactoryTest, GetNonMaskableNonEffectCompressedIcon) { + auto web_app = web_app::test::CreateWebApp(); + const std::string app_id = web_app->app_id(); + + const float scale1 = 1.0; + const float scale2 = 2.0; + const int kIconSize1 = kSizeInDip * scale1; + const int kIconSize2 = kSizeInDip * scale2; + const std::vector<int> sizes_px{kIconSize1, kIconSize2}; + const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW}; + WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors); + + web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px); + RegisterApp(std::move(web_app)); + + ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px)); + + std::vector<uint8_t> src_data1; + std::vector<uint8_t> src_data2; + src_data1 = GenerateWebAppNonEffectCompressedIcon(app_id, kIconSize1); + src_data2 = GenerateWebAppNonEffectCompressedIcon(app_id, kIconSize2); + + auto icon1 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k100Percent); + auto icon2 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon1); + VerifyCompressedIcon(src_data2, *icon2); +} + +TEST_F(WebAppIconFactoryTest, + GetNonMaskableNonEffectCompressedIconWithDifferentSizeIcon) { + auto web_app = web_app::test::CreateWebApp(); + const std::string app_id = web_app->app_id(); + + const float scale1 = 1.0; + const float scale2 = 2.0; + const int kIconSize1 = 96; + const int kIconSize2 = 256; + const std::vector<int> sizes_px{kIconSize1, kIconSize2}; + const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW}; + WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors); + + web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px); + RegisterApp(std::move(web_app)); + + ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px)); + + std::vector<uint8_t> src_data1; + std::vector<uint8_t> src_data2; + apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1}, + {2.0, kIconSize2}}; + GenerateWebAppCompressedIcon(app_id, IconPurpose::ANY, sizes_px, + scale_to_size_in_px, scale1, src_data1); + GenerateWebAppCompressedIcon(app_id, IconPurpose::ANY, sizes_px, + scale_to_size_in_px, scale2, src_data2); + + // Verift getting the compressed icon data for the compressed icon. + auto icon1 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k100Percent); + auto icon2 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon1); + VerifyCompressedIcon(src_data2, *icon2); + + // Verift getting the compressed icon data for the uncompressed icon. + auto icon3 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kUncompressed, + ui::ResourceScaleFactor::k100Percent); + auto icon4 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kUncompressed, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon3); + VerifyCompressedIcon(src_data2, *icon4); + + // Verift getting the compressed icon data for the standard icon. + auto icon5 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kStandard, + ui::ResourceScaleFactor::k100Percent); + auto icon6 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kStandard, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon5); + VerifyCompressedIcon(src_data2, *icon6); +} + +TEST_F(WebAppIconFactoryTest, GetMaskableCompressedIcon) { + auto web_app = web_app::test::CreateWebApp(); + const std::string app_id = web_app->app_id(); + + const float scale1 = 1.0; + const float scale2 = 2.0; + const int kIconSize1 = 128; + const int kIconSize2 = 256; + const std::vector<int> sizes_px{kIconSize1, kIconSize2}; + const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW}; + WriteIcons(app_id, {IconPurpose::ANY, IconPurpose::MASKABLE}, sizes_px, + colors); + + web_app->SetDownloadedIconSizes(IconPurpose::ANY, {kIconSize1}); + web_app->SetDownloadedIconSizes(IconPurpose::MASKABLE, {kIconSize2}); + + RegisterApp(std::move(web_app)); + + std::vector<uint8_t> src_data1; + std::vector<uint8_t> src_data2; + apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize2}, + {2.0, kIconSize2}}; + GenerateWebAppCompressedIcon(app_id, IconPurpose::MASKABLE, {kIconSize2}, + scale_to_size_in_px, scale1, src_data1); + GenerateWebAppCompressedIcon(app_id, IconPurpose::MASKABLE, {kIconSize2}, + scale_to_size_in_px, scale2, src_data2); + + apps::IconValuePtr icon; + + // Verift getting the compressed icon data for the compressed icon. + auto icon1 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k100Percent); + auto icon2 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kCompressed, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon1); + VerifyCompressedIcon(src_data2, *icon2); + + // Verift getting the compressed icon data for the uncompressed icon. + auto icon3 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kUncompressed, + ui::ResourceScaleFactor::k100Percent); + auto icon4 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kUncompressed, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon3); + VerifyCompressedIcon(src_data2, *icon4); + + // Verift getting the compressed icon data for the standard icon. + auto icon5 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kStandard, + ui::ResourceScaleFactor::k100Percent); + auto icon6 = GetWebAppCompressedIconData( + app_id, apps::IconEffects::kNone, apps::IconType::kStandard, + ui::ResourceScaleFactor::k200Percent); + + VerifyCompressedIcon(src_data1, *icon5); + VerifyCompressedIcon(src_data2, *icon6); +} #endif // BUILDFLAG(IS_CHROMEOS_ASH) } // namespace apps
diff --git a/chrome/browser/ash/accessibility/spoken_feedback_app_list_browsertest.cc b/chrome/browser/ash/accessibility/spoken_feedback_app_list_browsertest.cc index 0b4c203..0d8ba84 100644 --- a/chrome/browser/ash/accessibility/spoken_feedback_app_list_browsertest.cc +++ b/chrome/browser/ash/accessibility/spoken_feedback_app_list_browsertest.cc
@@ -133,7 +133,7 @@ TestSearchProvider** web_provider_ptr) { std::unique_ptr<TestSearchProvider> apps_provider = std::make_unique<TestSearchProvider>( - "app", ChromeSearchResult::DisplayType::kTile, + "app", ChromeSearchResult::DisplayType::kList, ChromeSearchResult::Category::kApps, ChromeSearchResult::ResultType::kInstalledApp); *apps_provider_ptr = apps_provider.get(); @@ -235,19 +235,6 @@ return test_item_index; } - std::vector<std::string> GetPublishedSuggestionChips() { - std::vector<std::string> chips; - std::vector<ChromeSearchResult*> published_results = - AppListClientImpl::GetInstance() - ->GetModelUpdaterForTest() - ->GetPublishedSearchResultsForTest(); - for (auto* result : published_results) { - if (result->display_type() == SearchResultDisplayType::kChip) - chips.push_back(base::UTF16ToUTF8(result->title())); - } - return chips; - } - AppListItem* FindItemByName(const std::string& name, int* index) { AppListModel* const model = AppListModelProvider::Get()->model(); AppListItemList* item_list = model->top_level_item_list(); @@ -536,8 +523,9 @@ sm_.Replay(); } +// TODO(https://crbug.com/1393235): Update this browser test to test recent +// apps. IN_PROC_BROWSER_TEST_P(SpokenFeedbackAppListTest, ClamshellLauncher) { - std::vector<std::string> suggestion_chips = GetPublishedSuggestionChips(); PopulateApps(3); int test_item_index = 0; @@ -566,15 +554,6 @@ sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); }); sm_.ExpectSpeech("Button"); - // Move focus over recent apps, which are currently populated using suggestion - // chip results. - // TODO(https://crbug.com/1260427): Traverse over all recent apps when the - // linked issue is fixed. - if (!suggestion_chips.empty()) { - sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_DOWN); }); - sm_.ExpectSpeech("Button"); - } - // Skip over apps that were installed before the test item. // This selects the first app installed by the test. for (int i = 0; i < test_item_index; ++i) {
diff --git a/chrome/browser/ash/android_sms/fcm_connection_establisher_unittest.cc b/chrome/browser/ash/android_sms/fcm_connection_establisher_unittest.cc index 48f6b18..45e5636 100644 --- a/chrome/browser/ash/android_sms/fcm_connection_establisher_unittest.cc +++ b/chrome/browser/ash/android_sms/fcm_connection_establisher_unittest.cc
@@ -31,12 +31,9 @@ : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {} ~FcmConnectionEstablisherTest() override = default; - void VerifyTransferrableMessage( - const char* expected, - const content::FakeServiceWorkerContext:: - StartServiceWorkerAndDispatchMessageArgs& call_args) { - auto payload = blink::DecodeToWebMessagePayload( - std::get<blink::TransferableMessage>(call_args)); + void VerifyTransferrableMessage(const char* expected, + blink::TransferableMessage message) { + auto payload = blink::DecodeToWebMessagePayload(std::move(message)); EXPECT_EQ(base::UTF8ToUTF16(expected), absl::get<std::u16string>(payload.value())); } @@ -66,7 +63,8 @@ ASSERT_EQ(1u, message_dispatch_calls.size()); EXPECT_EQ(GetAndroidMessagesURL(), std::get<GURL>(message_dispatch_calls[0])); VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage, - message_dispatch_calls[0]); + std::move(std::get<blink::TransferableMessage>( + message_dispatch_calls[0]))); // Return success to result callback and verify that no retries are attempted // and success histogram is recorded. @@ -92,7 +90,8 @@ base::RunLoop().RunUntilIdle(); ASSERT_EQ(2u, message_dispatch_calls.size()); VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage, - message_dispatch_calls[1]); + std::move(std::get<blink::TransferableMessage>( + message_dispatch_calls[1]))); // Verify that if the first request fails then it's retried std::move(std::get<content::ServiceWorkerContext::ResultCallback>( @@ -107,7 +106,8 @@ mock_retry_timer_ptr->Fire(); ASSERT_EQ(3u, message_dispatch_calls.size()); VerifyTransferrableMessage(FcmConnectionEstablisher::kStartFcmMessage, - message_dispatch_calls[2]); + std::move(std::get<blink::TransferableMessage>( + message_dispatch_calls[2]))); // Verify that if the first request succeeds then the next message is // dispatched @@ -117,7 +117,8 @@ ASSERT_EQ(4u, message_dispatch_calls.size()); EXPECT_FALSE(mock_retry_timer_ptr->IsRunning()); VerifyTransferrableMessage(FcmConnectionEstablisher::kResumeFcmMessage, - message_dispatch_calls[3]); + std::move(std::get<blink::TransferableMessage>( + message_dispatch_calls[3]))); // Complete second request and verify that no more retries are scheduled. std::move(std::get<content::ServiceWorkerContext::ResultCallback>( @@ -176,7 +177,8 @@ ASSERT_EQ(1u, message_dispatch_calls.size()); EXPECT_EQ(GetAndroidMessagesURL(), std::get<GURL>(message_dispatch_calls[0])); VerifyTransferrableMessage(FcmConnectionEstablisher::kStopFcmMessage, - message_dispatch_calls[0]); + std::move(std::get<blink::TransferableMessage>( + message_dispatch_calls[0]))); } } // namespace android_sms
diff --git a/chrome/browser/ash/app_restore/arc_app_single_restore_handler.cc b/chrome/browser/ash/app_restore/arc_app_single_restore_handler.cc index 527124ba..86e34e7 100644 --- a/chrome/browser/ash/app_restore/arc_app_single_restore_handler.cc +++ b/chrome/browser/ash/app_restore/arc_app_single_restore_handler.cc
@@ -100,10 +100,12 @@ // bounds is from "recording data" in ash wm side, so it will reduce the top // caption bar size when launch ghost window. However, if here use the bounds // from Android side, the bounds should be added a "caption" size. - restore_data.bounds_in_root->Inset(gfx::Insets().set_top( - -views::GetCaptionButtonLayoutSize( - views::CaptionButtonLayoutSize::kNonBrowserCaption) - .height())); + if (restore_data.bounds_in_root.has_value()) { + restore_data.bounds_in_root->Inset(gfx::Insets().set_top( + -views::GetCaptionButtonLayoutSize( + views::CaptionButtonLayoutSize::kNonBrowserCaption) + .height())); + } restore_data.window_state_type = static_cast<chromeos::WindowStateType>(window_info->state); restore_data.event_flag = event_flags;
diff --git a/chrome/browser/ash/app_restore/arc_app_single_restore_handler.h b/chrome/browser/ash/app_restore/arc_app_single_restore_handler.h index 9eaca33b..68cd01b 100644 --- a/chrome/browser/ash/app_restore/arc_app_single_restore_handler.h +++ b/chrome/browser/ash/app_restore/arc_app_single_restore_handler.h
@@ -56,6 +56,8 @@ NotLaunchIfShelfNotReady); FRIEND_TEST_ALL_PREFIXES(ArcAppSingleRestoreHandlerTest, PendingLaunchIfShelfHasReady); + FRIEND_TEST_ALL_PREFIXES(ArcAppSingleRestoreHandlerTest, + NullBoundsNotCauseCrash); // Called when ARC app has ready. It's expected only called once. void SendAppLaunchRequestToARC();
diff --git a/chrome/browser/ash/app_restore/arc_app_single_restore_handler_unittest.cc b/chrome/browser/ash/app_restore/arc_app_single_restore_handler_unittest.cc index 1a693d7d..11512cc 100644 --- a/chrome/browser/ash/app_restore/arc_app_single_restore_handler_unittest.cc +++ b/chrome/browser/ash/app_restore/arc_app_single_restore_handler_unittest.cc
@@ -109,4 +109,20 @@ ASSERT_FALSE(handler.IsAppPendingRestore(fake_app_id + "_not_equal_real_id")); } +TEST_F(ArcAppSingleRestoreHandlerTest, NullBoundsNotCauseCrash) { + ArcAppSingleRestoreHandler handler; + + const std::string fake_app_id = "not_exist_app_id"; + auto window_info = arc::mojom::WindowInfo::New(); + window_info->window_id = 100; + window_info->display_id = display::kInvalidDisplayId; + // leave the bounds null. + + handler.OnShelfReady(); + handler.ghost_window_handler_ = window_handler(); + handler.LaunchGhostWindowWithApp( + profile(), fake_app_id, nullptr, 0 /*event_flags*/, + arc::GhostWindowType::kAppLaunch, std::move(window_info)); +} + } // namespace ash::app_restore
diff --git a/chrome/browser/ash/arc/window_predictor/window_predictor.cc b/chrome/browser/ash/arc/window_predictor/window_predictor.cc index 3d79d97f..7c811cb3 100644 --- a/chrome/browser/ash/arc/window_predictor/window_predictor.cc +++ b/chrome/browser/ash/arc/window_predictor/window_predictor.cc
@@ -117,6 +117,10 @@ arc::mojom::WindowInfoPtr predict_window_info = PredictAppWindowInfo(app_info, window_info.Clone()); + // TODO(sstan): PredictAppWindowInfo should always return fulfilled info. + if (!predict_window_info || !predict_window_info->bounds.has_value()) + return false; + arc_task_handler->GetWindowPredictorArcAppRestoreHandler(launch_counter) ->LaunchGhostWindowWithApp( profile, arc_app_id, intent ? intent->Clone() : nullptr, event_flags,
diff --git a/chrome/browser/ash/borealis/borealis_features_util.cc b/chrome/browser/ash/borealis/borealis_features_util.cc index 9396684e..9d6808b 100644 --- a/chrome/browser/ash/borealis/borealis_features_util.cc +++ b/chrome/browser/ash/borealis/borealis_features_util.cc
@@ -53,10 +53,10 @@ // Returns the model name of this device (either from its CustomizationId or by // parsing its hardware class). Returns "" if it fails. std::string GetModelName() { - std::string ret; - if (chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic( - chromeos::system::kCustomizationIdKey, &ret)) { - return ret; + if (const absl::optional<base::StringPiece> ret = + chromeos::system::StatisticsProvider::GetInstance() + ->GetMachineStatistic(chromeos::system::kCustomizationIdKey)) { + return std::string(ret.value()); } LOG(WARNING) << "CustomizationId unavailable, attempting to parse hardware class"; @@ -64,9 +64,10 @@ // As a fallback when the CustomizationId is not available, we try to parse it // out of the hardware class. If The hardware class is unavailable, all bets // are off. - std::string hardware_class; - if (!chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic( - chromeos::system::kHardwareClassKey, &hardware_class)) { + const absl::optional<base::StringPiece> hardware_class_statistic = + chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic( + chromeos::system::kHardwareClassKey); + if (!hardware_class_statistic) { return ""; } @@ -79,6 +80,7 @@ // // Naively searching for the first hyphen is fine until we start caring about // models with hyphens in the name. + base::StringPiece hardware_class = hardware_class_statistic.value(); size_t hyphen_pos = hardware_class.find('-'); if (hyphen_pos != std::string::npos) hardware_class = hardware_class.substr(0, hyphen_pos);
diff --git a/chrome/browser/ash/dbus/fusebox_service_provider.cc b/chrome/browser/ash/dbus/fusebox_service_provider.cc index f58a42e..359cbe7 100644 --- a/chrome/browser/ash/dbus/fusebox_service_provider.cc +++ b/chrome/browser/ash/dbus/fusebox_service_provider.cc
@@ -16,9 +16,12 @@ // The "fusebox_staging" concept is described in // chrome/browser/ash/fusebox/fusebox_staging.proto +// +// TODO(b/255520194): remove this section. namespace fusebox_staging { const char kRead2Method[] = "Read2"; -} +const char kWrite2Method[] = "Write2"; +} // namespace fusebox_staging namespace ash { @@ -175,6 +178,11 @@ base::BindRepeating(&FuseBoxServiceProvider::Stat, weak_ptr_factory_.GetWeakPtr()), base::BindOnce(&OnExportedCallback)); + object->ExportMethod(fusebox::kFuseBoxServiceInterface, + fusebox_staging::kWrite2Method, + base::BindRepeating(&FuseBoxServiceProvider::Write2, + weak_ptr_factory_.GetWeakPtr()), + base::BindOnce(&OnExportedCallback)); object->ExportMethod( fusebox::kFuseBoxServiceInterface, fusebox::kListStoragesMethod, @@ -411,6 +419,26 @@ base::BindOnce(&ReplyToStat, method_call, std::move(sender))); } +void FuseBoxServiceProvider::Write2( + dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender sender) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + dbus::MessageReader reader(method_call); + fusebox_staging::Write2RequestProto request_proto; + if (!reader.PopArrayOfBytesAsProto(&request_proto)) { + fusebox_staging::Write2ResponseProto response_proto; + response_proto.set_posix_error_code(EINVAL); + ReplyToProtoMethod(method_call, std::move(sender), response_proto); + return; + } + + server_.Write2( + request_proto, + base::BindOnce(&ReplyToProtoMethod<fusebox_staging::Write2ResponseProto>, + method_call, std::move(sender))); +} + void FuseBoxServiceProvider::ListStorages( dbus::MethodCall* method_call, dbus::ExportedObject::ResponseSender sender) {
diff --git a/chrome/browser/ash/dbus/fusebox_service_provider.h b/chrome/browser/ash/dbus/fusebox_service_provider.h index ed85cb9..c5d6567 100644 --- a/chrome/browser/ash/dbus/fusebox_service_provider.h +++ b/chrome/browser/ash/dbus/fusebox_service_provider.h
@@ -58,6 +58,8 @@ dbus::ExportedObject::ResponseSender sender); void Stat(dbus::MethodCall* method_call, dbus::ExportedObject::ResponseSender sender); + void Write2(dbus::MethodCall* method_call, + dbus::ExportedObject::ResponseSender sender); void ListStorages(dbus::MethodCall* method_call, dbus::ExportedObject::ResponseSender sender);
diff --git a/chrome/browser/ash/extensions/input_method_api.cc b/chrome/browser/ash/extensions/input_method_api.cc index 208e79b6..925839b1 100644 --- a/chrome/browser/ash/extensions/input_method_api.cc +++ b/chrome/browser/ash/extensions/input_method_api.cc
@@ -521,8 +521,6 @@ registry .RegisterFunction<InputMethodPrivateFetchAllDictionaryWordsFunction>(); registry.RegisterFunction<InputMethodPrivateAddWordToDictionaryFunction>(); - registry - .RegisterFunction<InputMethodPrivateNotifyImeMenuItemActivatedFunction>(); registry.RegisterFunction<InputMethodPrivateOpenOptionsPageFunction>(); }
diff --git a/chrome/browser/ash/extensions/input_method_apitest_chromeos.cc b/chrome/browser/ash/extensions/input_method_apitest_chromeos.cc index 6461977..3f27cd2 100644 --- a/chrome/browser/ash/extensions/input_method_apitest_chromeos.cc +++ b/chrome/browser/ash/extensions/input_method_apitest_chromeos.cc
@@ -140,7 +140,6 @@ IN_PROC_BROWSER_TEST_F(ExtensionInputMethodApiTest, ImeMenuAPITest) { ExtensionTestMessageListener activated_listener("activated"); ExtensionTestMessageListener menu_listener("get_menu_update"); - ExtensionTestMessageListener item_activated_listenter("get_menu_activated"); ExtensionTestMessageListener list_listenter("list_change"); browser()->profile()->GetPrefs()->SetBoolean(prefs::kLanguageImeMenuActivated, true); @@ -163,7 +162,6 @@ ASSERT_TRUE(activated_listener.WaitUntilSatisfied()) << message_; ASSERT_TRUE(menu_listener.WaitUntilSatisfied()) << message_; - ASSERT_TRUE(item_activated_listenter.WaitUntilSatisfied()) << message_; InputMethodManager::Get()->GetActiveIMEState()->ChangeInputMethod( kTestIMEID2, false /* show_message */);
diff --git a/chrome/browser/ash/file_manager/file_tasks.cc b/chrome/browser/ash/file_manager/file_tasks.cc index 8c82a1b1..f5f05ac 100644 --- a/chrome/browser/ash/file_manager/file_tasks.cc +++ b/chrome/browser/ash/file_manager/file_tasks.cc
@@ -574,6 +574,7 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) { registry->RegisterDictionaryPref(prefs::kDefaultHandlersForFileExtensions); registry->RegisterBooleanPref(prefs::kOfficeSetupComplete, false); + registry->RegisterBooleanPref(prefs::kOfficeFilesAlwaysMove, false); } // Converts a string to a TaskType. Returns TASK_TYPE_UNKNOWN on error. @@ -1242,4 +1243,12 @@ return profile->GetPrefs()->GetBoolean(prefs::kOfficeSetupComplete); } +void SetAlwaysMoveOfficeFiles(Profile* profile, bool always_move) { + profile->GetPrefs()->SetBoolean(prefs::kOfficeFilesAlwaysMove, always_move); +} + +bool AlwaysMoveOfficeFiles(Profile* profile) { + return profile->GetPrefs()->GetBoolean(prefs::kOfficeFilesAlwaysMove); +} + } // namespace file_manager::file_tasks
diff --git a/chrome/browser/ash/file_manager/file_tasks.h b/chrome/browser/ash/file_manager/file_tasks.h index 42fd158..fbebab3 100644 --- a/chrome/browser/ash/file_manager/file_tasks.h +++ b/chrome/browser/ash/file_manager/file_tasks.h
@@ -389,6 +389,12 @@ // Whether or not the setup flow for office files has ever been completed. bool OfficeSetupComplete(Profile* profile); +// Sets the user preference storing whether we should always move office files +// without first asking the user. +void SetAlwaysMoveOfficeFiles(Profile* profile, bool complete = true); +// Whether we should always move office files without first asking the user. +bool AlwaysMoveOfficeFiles(Profile* profile); + } // namespace file_manager::file_tasks #endif // CHROME_BROWSER_ASH_FILE_MANAGER_FILE_TASKS_H_
diff --git a/chrome/browser/ash/fusebox/fusebox_server.cc b/chrome/browser/ash/fusebox/fusebox_server.cc index 92ac1ca..b3a5989 100644 --- a/chrome/browser/ash/fusebox/fusebox_server.cc +++ b/chrome/browser/ash/fusebox/fusebox_server.cc
@@ -21,10 +21,8 @@ #include "chrome/browser/profiles/profile_manager.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" -#include "net/base/io_buffer.h" #include "storage/browser/file_system/async_file_util.h" #include "storage/browser/file_system/external_mount_points.h" -#include "storage/browser/file_system/file_stream_reader.h" #include "storage/browser/file_system/file_system_url.h" #include "storage/common/file_system/file_system_util.h" #include "third_party/cros_system_api/dbus/fusebox/dbus-constants.h" @@ -361,6 +359,25 @@ std::move(callback).Run(response_proto); } +void RunWrite2CallbackFailure(Server::Write2Callback callback, + base::File::Error error_code) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + fusebox_staging::Write2ResponseProto response_proto; + response_proto.set_posix_error_code(FileErrorToErrno(error_code)); + std::move(callback).Run(response_proto); +} + +void RunWrite2CallbackTypical(Server::Write2Callback callback, int length) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + fusebox_staging::Write2ResponseProto response_proto; + if (length < 0) { + response_proto.set_posix_error_code(NetErrorToErrno(length)); + } + std::move(callback).Run(response_proto); +} + void ReadOnIOThread(scoped_refptr<storage::FileSystemContext> fs_context, storage::FileSystemURL fs_url, int64_t offset, @@ -496,6 +513,69 @@ std::move(buffer), length)); } +void Server::ReadWriter::Write( + scoped_refptr<storage::FileSystemContext> fs_context, + scoped_refptr<net::StringIOBuffer> buffer, + int64_t offset, + int length, + Server::Write2Callback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + // See if we can re-use the previous storage::FileStreamWriter. + std::unique_ptr<storage::FileStreamWriter> fs_writer; + if (fs_writer_ && (write_offset_ == offset)) { + fs_writer = std::move(fs_writer_); + write_offset_ = -1; + } else { + fs_writer = fs_context->CreateFileStreamWriter(fs_url_, offset); + if (!fs_writer) { + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce(&RunWrite2CallbackFailure, std::move(callback), + base::File::Error::FILE_ERROR_INVALID_URL)); + return; + } + } + + // Save the pointer before we std::move fs_writer into a base::OnceCallback. + // The std::move keeps the underlying storage::FileStreamWriter alive while + // any network I/O is pending. Without the std::move, the underlying + // storage::FileStreamWriter would get destroyed at the end of this function. + auto* saved_fs_writer = fs_writer.get(); + + auto pair = base::SplitOnceCallback(base::BindOnce( + &Server::ReadWriter::OnWrite, weak_ptr_factory_.GetWeakPtr(), + std::move(callback), fs_context, std::move(fs_writer), buffer, offset)); + + int result = + saved_fs_writer->Write(buffer.get(), length, std::move(pair.first)); + if (result != net::ERR_IO_PENDING) { // The write was synchronous. + std::move(pair.second).Run(result); + } +} + +void Server::ReadWriter::OnWrite( + Server::Write2Callback callback, + scoped_refptr<storage::FileSystemContext> fs_context, + std::unique_ptr<storage::FileStreamWriter> fs_writer, + scoped_refptr<net::IOBuffer> buffer, + int64_t offset, + int length) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + + if (length >= 0) { + fs_writer_ = std::move(fs_writer); + write_offset_ = offset + length; + } else { + fs_writer_.reset(); + write_offset_ = -1; + } + + content::GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, + base::BindOnce(&RunWrite2CallbackTypical, std::move(callback), length)); +} + Server::FuseFileMapEntry::FuseFileMapEntry( scoped_refptr<storage::FileSystemContext> fs_context_arg, storage::FileSystemURL fs_url_arg, @@ -519,6 +599,22 @@ .WithArgs(fs_context_, offset, length, std::move(callback)); } +void Server::FuseFileMapEntry::DoWrite2( + const fusebox_staging::Write2RequestProto& request, + Server::Write2Callback callback) { + if (!request.has_data() || request.data().empty()) { + fusebox_staging::Write2ResponseProto response_proto; + std::move(callback).Run(response_proto); + return; + } + scoped_refptr<net::StringIOBuffer> buffer = + base::MakeRefCounted<net::StringIOBuffer>(request.data()); + int64_t offset = request.has_offset() ? request.offset() : 0; + seqbnd_read_writer_.AsyncCall(&Server::ReadWriter::Write) + .WithArgs(fs_context_, std::move(buffer), offset, + static_cast<int>(request.data().size()), std::move(callback)); +} + Server::PrefixMapEntry::PrefixMapEntry(std::string fs_url_prefix_arg, bool read_only_arg) : fs_url_prefix(fs_url_prefix_arg), read_only(read_only_arg) {} @@ -687,6 +783,8 @@ FuseFileMapEntry& entry = iter->second; base::circular_deque<PendingRead2> pending_reads = std::move(entry.pending_reads_); + base::circular_deque<PendingWrite2> pending_writes = + std::move(entry.pending_writes_); fuse_file_map_.erase(iter); @@ -700,6 +798,13 @@ std::move(pending_read.second).Run(read2_response_proto); } } + if (!pending_writes.empty()) { + fusebox_staging::Write2ResponseProto write2_esponse_proto; + write2_esponse_proto.set_posix_error_code(EBUSY); + for (auto& pending_read : pending_writes) { + std::move(pending_read.second).Run(write2_esponse_proto); + } + } } void Server::Create(const fusebox_staging::CreateRequestProto& request_proto, @@ -1012,6 +1117,41 @@ common.fs_url, metadata_fields, std::move(outer_callback))); } +void Server::Write2(const fusebox_staging::Write2RequestProto& request_proto, + Write2Callback callback) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + uint64_t fuse_handle = + request_proto.has_fuse_handle() ? request_proto.fuse_handle() : 0; + auto iter = fuse_file_map_.find(fuse_handle); + if (iter == fuse_file_map_.end()) { + fusebox_staging::Write2ResponseProto response_proto; + response_proto.set_posix_error_code(ENOENT); + std::move(callback).Run(response_proto); + return; + } else if (!iter->second.writable_) { + fusebox_staging::Write2ResponseProto response_proto; + response_proto.set_posix_error_code(EACCES); + std::move(callback).Run(response_proto); + return; + } else if (request_proto.has_data() && + (request_proto.data().size() > INT_MAX)) { + fusebox_staging::Write2ResponseProto response_proto; + response_proto.set_posix_error_code(EMSGSIZE); + std::move(callback).Run(response_proto); + return; + } else if (iter->second.has_in_flight_write_) { + iter->second.pending_writes_.emplace_back(request_proto, + std::move(callback)); + return; + } + iter->second.has_in_flight_write_ = true; + iter->second.DoWrite2( + request_proto, + base::BindOnce(&Server::OnWrite2, weak_ptr_factory_.GetWeakPtr(), + fuse_handle, std::move(callback))); +} + void Server::ListStorages(const ListStoragesRequestProto& request, ListStoragesCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -1175,6 +1315,36 @@ } } +void Server::OnWrite2( + uint64_t fuse_handle, + Write2Callback callback, + const fusebox_staging::Write2ResponseProto& response_proto) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + auto iter = fuse_file_map_.find(fuse_handle); + if (iter == fuse_file_map_.end()) { + fusebox_staging::Write2ResponseProto enoent_response_proto; + enoent_response_proto.set_posix_error_code(ENOENT); + std::move(callback).Run(enoent_response_proto); + return; + } + FuseFileMapEntry& entry = iter->second; + entry.has_in_flight_write_ = false; + + std::move(callback).Run(std::move(response_proto)); + + if (entry.pending_writes_.empty()) { + return; + } + PendingWrite2 pending = std::move(entry.pending_writes_.front()); + entry.pending_writes_.pop_front(); + entry.has_in_flight_write_ = true; + entry.DoWrite2( + pending.first, + base::BindOnce(&Server::OnWrite2, weak_ptr_factory_.GetWeakPtr(), + fuse_handle, std::move(pending.second))); +} + void Server::EraseFuseFileMapEntry(uint64_t fuse_handle) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/ash/fusebox/fusebox_server.h b/chrome/browser/ash/fusebox/fusebox_server.h index fb8bf44..840df0a 100644 --- a/chrome/browser/ash/fusebox/fusebox_server.h +++ b/chrome/browser/ash/fusebox/fusebox_server.h
@@ -17,7 +17,10 @@ #include "chrome/browser/ash/fusebox/fusebox.pb.h" #include "chrome/browser/ash/fusebox/fusebox_moniker.h" #include "chrome/browser/ash/fusebox/fusebox_staging.pb.h" +#include "net/base/io_buffer.h" #include "storage/browser/file_system/async_file_util.h" +#include "storage/browser/file_system/file_stream_reader.h" +#include "storage/browser/file_system/file_stream_writer.h" #include "storage/browser/file_system/file_system_context.h" class Profile; @@ -161,6 +164,12 @@ bool read_only)>; void Stat(const std::string& fs_url_as_string, StatCallback callback); + // Write2 writes to a virtual file opened by Open2. + using Write2Callback = base::OnceCallback<void( + const fusebox_staging::Write2ResponseProto& response)>; + void Write2(const fusebox_staging::Write2RequestProto& request, + Write2Callback callback); + // File operation D-Bus methods above. Meta D-Bus methods below, which do not // map 1:1 to FUSE or C standard library file operations. @@ -207,6 +216,8 @@ using PendingRead2 = std::pair<fusebox_staging::Read2RequestProto, Read2Callback>; + using PendingWrite2 = + std::pair<fusebox_staging::Write2RequestProto, Write2Callback>; // Lives entirely on the I/O thread, as enforced by base::SequenceBound. struct ReadWriter { @@ -224,13 +235,29 @@ int64_t offset, int length); + void Write(scoped_refptr<storage::FileSystemContext> fs_context, + scoped_refptr<net::StringIOBuffer> buffer, + int64_t offset, + int length, + Server::Write2Callback callback); + void OnWrite(Server::Write2Callback callback, + scoped_refptr<storage::FileSystemContext> fs_context, + std::unique_ptr<storage::FileStreamWriter> fs_writer, + scoped_refptr<net::IOBuffer> buffer, + int64_t offset, + int length); + const storage::FileSystemURL fs_url_; std::unique_ptr<storage::FileStreamReader> fs_reader_; // Unused whenever fs_reader_ is nullptr. int64_t read_offset_ = -1; - // TODO(b/255703917): write support and snapshot management. + std::unique_ptr<storage::FileStreamWriter> fs_writer_; + // Unused whenever fs_writer_ is nullptr. + int64_t write_offset_ = -1; + + // TODO(b/255703917): snapshot management. base::WeakPtrFactory<ReadWriter> weak_ptr_factory_{this}; }; @@ -245,13 +272,17 @@ void DoRead2(const fusebox_staging::Read2RequestProto& request, Read2Callback callback); + void DoWrite2(const fusebox_staging::Write2RequestProto& request, + Write2Callback callback); const scoped_refptr<storage::FileSystemContext> fs_context_; const bool readable_; const bool writable_; bool has_in_flight_read_ = false; + bool has_in_flight_write_ = false; base::circular_deque<PendingRead2> pending_reads_; + base::circular_deque<PendingWrite2> pending_writes_; base::SequenceBound<ReadWriter> seqbnd_read_writer_; }; @@ -330,6 +361,10 @@ storage::AsyncFileUtil::EntryList entry_list, bool has_more); + void OnWrite2(uint64_t fuse_handle, + Write2Callback callback, + const fusebox_staging::Write2ResponseProto& response); + // Removes the entry (if present) for the given map key. void EraseFuseFileMapEntry(uint64_t fuse_handle); // Returns the fuse_handle that is the map key.
diff --git a/chrome/browser/ash/fusebox/fusebox_staging.proto b/chrome/browser/ash/fusebox/fusebox_staging.proto index fc96038a..38ad8d6 100644 --- a/chrome/browser/ash/fusebox/fusebox_staging.proto +++ b/chrome/browser/ash/fusebox/fusebox_staging.proto
@@ -132,3 +132,15 @@ message RmDirResponseProto { optional int32 posix_error_code = 1; } + +// Write2 writes to a fuse_handle previously returned by Open2. + +message Write2RequestProto { + optional uint64 fuse_handle = 2; + optional int64 offset = 4; + optional bytes data = 5; +} + +message Write2ResponseProto { + optional int32 posix_error_code = 1; +}
diff --git a/chrome/browser/ash/input_method/input_method_settings.cc b/chrome/browser/ash/input_method/input_method_settings.cc index 09c2fedb..cd52eb27 100644 --- a/chrome/browser/ash/input_method/input_method_settings.cc +++ b/chrome/browser/ash/input_method/input_method_settings.cc
@@ -232,11 +232,10 @@ return settings; } -} // namespace - -mojom::InputMethodSettingsPtr CreateSettingsFromPrefs( +const base::Value::Dict& GetPrefsDictionaryForEngineId( const PrefService& prefs, - const std::string& engine_id) { + const std::string& engine_id, + const base::Value::Dict& fallback_dictionary) { // All input method settings are stored in a single pref whose value is a // dictionary. const base::Value::Dict& all_input_method_pref = @@ -244,19 +243,28 @@ // For each input method, the dictionary contains an entry, with the key being // a string that identifies the input method, and the value being a - // subdictionary with the specific settings for that input method. - // The subdictionary structure depends on the type of input method it's for. - // The subdictionary may be null if the user hasn't changed any settings for - // that input method. + // subdictionary with the specific settings for that input method. The + // subdictionary structure depends on the type of input method it's for. The + // subdictionary may be null if the user hasn't changed any settings for that + // input method. const base::Value::Dict* input_method_specific_pref_or_null = all_input_method_pref.FindDict(engine_id); // For convenience, pass an empty dictionary if there are no settings for this // input method yet. - base::Value::Dict empty_value; + return input_method_specific_pref_or_null + ? *input_method_specific_pref_or_null + : fallback_dictionary; +} + +} // namespace + +mojom::InputMethodSettingsPtr CreateSettingsFromPrefs( + const PrefService& prefs, + const std::string& engine_id) { + base::Value::Dict empty_dictionary; const auto& input_method_specific_pref = - input_method_specific_pref_or_null ? *input_method_specific_pref_or_null - : empty_value; + GetPrefsDictionaryForEngineId(prefs, engine_id, empty_dictionary); if (IsFstEngine(engine_id)) { return mojom::InputMethodSettings::NewLatinSettings(
diff --git a/chrome/browser/ash/login/oobe_quick_start/BUILD.gn b/chrome/browser/ash/login/oobe_quick_start/BUILD.gn index 8d50351..e8fe6a4e 100644 --- a/chrome/browser/ash/login/oobe_quick_start/BUILD.gn +++ b/chrome/browser/ash/login/oobe_quick_start/BUILD.gn
@@ -11,6 +11,9 @@ "connectivity", "//base", "//chrome/common:channel_info", + "//chromeos/ash/components/attestation:attestation", + "//chromeos/ash/components/dbus/attestation:attestation_proto", + "//components/account_id:account_id", "//components/endpoint_fetcher:endpoint_fetcher", "//components/qr_code_generator:qr_code_generator", "//components/version_info:channel", @@ -37,11 +40,16 @@ "connectivity:unit_tests", "//base", "//base/test:test_support", + "//chromeos/ash/components/attestation:test_support", + "//chromeos/ash/components/dbus/constants:constants", + "//components/account_id:account_id", "//google_apis:google_apis", "//google_apis/common:common", "//services/data_decoder/public/cpp:test_support", "//services/network:test_support", "//services/network/public/cpp:cpp", + "//testing/gmock", + "//testing/gtest", ] sources = [ "second_device_auth_broker_unittest.cc",
diff --git a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc index aea44f00d..4e2fb30 100644 --- a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc +++ b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.cc
@@ -12,11 +12,15 @@ #include "base/check.h" #include "base/functional/bind.h" #include "base/functional/callback_forward.h" +#include "base/guid.h" #include "base/logging.h" #include "base/strings/stringprintf.h" #include "base/types/expected.h" #include "base/values.h" #include "chrome/common/channel_info.h" +#include "chromeos/ash/components/attestation/attestation_flow.h" +#include "chromeos/ash/components/dbus/attestation/keystore.pb.h" +#include "components/account_id/account_id.h" #include "components/endpoint_fetcher/endpoint_fetcher.h" #include "components/version_info/channel.h" #include "google_apis/common/api_error_codes.h" @@ -105,7 +109,7 @@ } void RunChallengeBytesCallback( - SecondDeviceAuthBroker::GetChallengeBytesCallback challenge_callback, + SecondDeviceAuthBroker::ChallengeBytesCallback challenge_callback, const std::string& challenge_bytes) { if (challenge_bytes.empty()) { std::move(challenge_callback) @@ -119,7 +123,7 @@ } void HandleGetChallengeBytesErrorResponse( - SecondDeviceAuthBroker::GetChallengeBytesCallback challenge_callback, + SecondDeviceAuthBroker::ChallengeBytesCallback challenge_callback, std::unique_ptr<EndpointResponse> response) { LOG(ERROR) << "Could not fetch challenge bytes. HTTP status code: " << response->http_status_code; @@ -160,19 +164,50 @@ } } +void RunAttestationCertificateCallback( + SecondDeviceAuthBroker::AttestationCertificateCallback callback, + attestation::AttestationStatus status, + const std::string& pem_certificate_chain) { + switch (status) { + case attestation::ATTESTATION_SUCCESS: + if (pem_certificate_chain.empty()) { + LOG(ERROR) << "Got an empty certificate chain with a success response " + "from attestation server"; + std::move(callback).Run(base::unexpected( + SecondDeviceAuthBroker::AttestationErrorType::kPermanentError)); + return; + } + std::move(callback).Run(base::ok(pem_certificate_chain)); + return; + case attestation::ATTESTATION_UNSPECIFIED_FAILURE: + // TODO(b/259021973): Is it safe to consider + // `ATTESTATION_UNSPECIFIED_FAILURE` transient? Check its side effects. + std::move(callback).Run(base::unexpected( + SecondDeviceAuthBroker::AttestationErrorType::kTransientError)); + return; + case attestation::ATTESTATION_SERVER_BAD_REQUEST_FAILURE: + std::move(callback).Run(base::unexpected( + SecondDeviceAuthBroker::AttestationErrorType::kPermanentError)); + return; + } +} + } // namespace SecondDeviceAuthBroker::SecondDeviceAuthBroker( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + std::unique_ptr<attestation::AttestationFlow> attestation_flow) : url_loader_factory_(std::move(url_loader_factory)), + attestation_(std::move(attestation_flow)), weak_ptr_factory_(this) { DCHECK(url_loader_factory_); + DCHECK(attestation_); } SecondDeviceAuthBroker::~SecondDeviceAuthBroker() = default; void SecondDeviceAuthBroker::GetChallengeBytes( - GetChallengeBytesCallback challenge_callback) { + ChallengeBytesCallback challenge_callback) { DCHECK(!endpoint_fetcher_) << "This class can handle only one request at a time"; @@ -196,7 +231,7 @@ } void SecondDeviceAuthBroker::OnChallengeBytesFetched( - GetChallengeBytesCallback challenge_callback, + ChallengeBytesCallback challenge_callback, std::unique_ptr<EndpointResponse> response) { DCHECK(endpoint_fetcher_) << "Received an unexpected callback for challenge bytes"; @@ -216,4 +251,26 @@ std::move(challenge_callback)))); } +void SecondDeviceAuthBroker::FetchAttestationCertificate( + const std::string& fido_credential_id, + AttestationCertificateCallback certificate_callback) { + // TODO(b/259021973): Figure out if we can use ECC keys where they are + // available. + ::attestation::DeviceSetupCertificateRequestMetadata profile_specific_data; + profile_specific_data.set_id(base::GenerateGUID()); + profile_specific_data.set_content_binding(fido_credential_id); + attestation_->GetCertificate( + /*certificate_profile=*/attestation::AttestationCertificateProfile:: + PROFILE_DEVICE_SETUP_CERTIFICATE, + /*account_id=*/EmptyAccountId(), /*request_origin=*/std::string(), + /*force_new_key=*/true, /*key_crypto_type=*/::attestation::KEY_TYPE_RSA, + /*key_name=*/std::string(), + /*profile_specific_data=*/ + absl::make_optional(attestation::AttestationFlow::CertProfileSpecificData( + profile_specific_data)), + /*callback=*/ + base::BindOnce(&RunAttestationCertificateCallback, + std::move(certificate_callback))); +} + } // namespace ash::quick_start
diff --git a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.h b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.h index c5cf03e..461b90f 100644 --- a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.h +++ b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker.h
@@ -12,23 +12,30 @@ #include "base/memory/scoped_refptr.h" #include "base/memory/weak_ptr.h" #include "base/types/expected.h" +#include "chromeos/ash/components/attestation/attestation_flow.h" #include "components/endpoint_fetcher/endpoint_fetcher.h" class GoogleServiceAuthError; namespace network { class SharedURLLoaderFactory; -} +} // namespace network namespace ash::quick_start { class SecondDeviceAuthBroker { public: - using GetChallengeBytesCallback = base::OnceCallback<void( - const base::expected<std::string, GoogleServiceAuthError>&)>; + enum class AttestationErrorType { kTransientError, kPermanentError }; - explicit SecondDeviceAuthBroker( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); + using ChallengeBytesCallback = base::OnceCallback<void( + const base::expected<std::string, GoogleServiceAuthError>&)>; + using AttestationCertificateCallback = base::OnceCallback<void( + const base::expected<std::string, AttestationErrorType>&)>; + + // Constructs an instance of `SecondDeviceAuthBroker`. + SecondDeviceAuthBroker( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + std::unique_ptr<attestation::AttestationFlow> attestation_flow); SecondDeviceAuthBroker(const SecondDeviceAuthBroker&) = delete; SecondDeviceAuthBroker& operator=(const SecondDeviceAuthBroker&) = delete; ~SecondDeviceAuthBroker(); @@ -37,11 +44,20 @@ // service. // The callback is completed with either the challenge bytes - for successful // execution, or with a `GoogleServiceAuthError` - for a failed execution. - void GetChallengeBytes(GetChallengeBytesCallback challenge_callback); + void GetChallengeBytes(ChallengeBytesCallback challenge_callback); + + // Fetches a new Remote Attestation certificate - for proving device + // integrity. + // The callback is completed with either a PEM encoded certificate chain + // string, or with the type of error (`AttestationErrorType`) which occurred + // during attestation. + void FetchAttestationCertificate( + const std::string& fido_credential_id, + AttestationCertificateCallback certificate_callback); private: // Callback for handling challenge bytes response from Gaia. - void OnChallengeBytesFetched(GetChallengeBytesCallback challenge_callback, + void OnChallengeBytesFetched(ChallengeBytesCallback challenge_callback, std::unique_ptr<EndpointResponse> response); scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_; @@ -49,6 +65,10 @@ // Used for fetching results from Gaia endpoints. std::unique_ptr<EndpointFetcher> endpoint_fetcher_ = nullptr; + // Used for interacting with Google's Privacy CA, for getting a Remote + // Attestation certificate. + std::unique_ptr<attestation::AttestationFlow> attestation_; + base::WeakPtrFactory<SecondDeviceAuthBroker> weak_ptr_factory_; };
diff --git a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker_unittest.cc b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker_unittest.cc index 063d86f..bfa07be74 100644 --- a/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker_unittest.cc +++ b/chrome/browser/ash/login/oobe_quick_start/second_device_auth_broker_unittest.cc
@@ -13,6 +13,10 @@ #include "base/test/bind.h" #include "base/test/task_environment.h" #include "base/types/expected.h" +#include "chromeos/ash/components/attestation/attestation_flow.h" +#include "chromeos/ash/components/attestation/mock_attestation_flow.h" +#include "chromeos/ash/components/dbus/constants/attestation_constants.h" +#include "components/account_id/account_id.h" #include "google_apis/gaia/google_service_auth_error.h" #include "net/http/http_status_code.h" #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h" @@ -24,10 +28,16 @@ namespace ash::quick_start { +using ::testing::_; using ::testing::Eq; using ::testing::Gt; +using ::testing::Invoke; using ::testing::IsFalse; using ::testing::IsTrue; +using ::testing::Optional; +using ::testing::StrictMock; +using ::testing::VariantWith; +using ::testing::WithArg; namespace { @@ -49,13 +59,52 @@ "\"Not-a-base64-character()\"" "}" "}"; +constexpr char kFidoCredentialId[] = "fido_credential_id"; + +MATCHER_P(ProtoBufContentBindingEq, expected, "") { + return arg.content_binding() == expected; +} + +// This class simply delegates all API calls to its mock object. It is used for +// passing information from inside `SecondDeviceAuthBroker` to the mock object, +// without passing ownership of the mock object to `SecondDeviceAuthBroker`. +class MockAttestationFlowFacade : public attestation::MockAttestationFlow { + public: + explicit MockAttestationFlowFacade( + raw_ptr<attestation::MockAttestationFlow> mock_attestation_flow) + : mock_attestation_flow_(std::move(mock_attestation_flow)) {} + MockAttestationFlowFacade(const MockAttestationFlowFacade&) = delete; + MockAttestationFlowFacade& operator=(const MockAttestationFlowFacade&) = + delete; + ~MockAttestationFlowFacade() override = default; + + void GetCertificate( + attestation::AttestationCertificateProfile certificate_profile, + const AccountId& account_id, + const std::string& request_origin, + bool force_new_key, + ::attestation::KeyType key_crypto_type, + const std::string& key_name, + const absl::optional<CertProfileSpecificData>& profile_specific_data, + CertificateCallback callback) override { + mock_attestation_flow_->GetCertificate( + certificate_profile, account_id, request_origin, force_new_key, + key_crypto_type, key_name, profile_specific_data, std::move(callback)); + } + + private: + raw_ptr<attestation::MockAttestationFlow> mock_attestation_flow_; +}; } // namespace class SecondDeviceAuthBrokerTest : public ::testing::Test { public: SecondDeviceAuthBrokerTest() - : second_device_auth_broker_(test_factory_.GetSafeWeakWrapper()) {} + : second_device_auth_broker_(test_factory_.GetSafeWeakWrapper(), + std::make_unique<MockAttestationFlowFacade>( + &mock_attestation_flow_)) {} + SecondDeviceAuthBrokerTest(const SecondDeviceAuthBrokerTest&) = delete; SecondDeviceAuthBrokerTest& operator=(const SecondDeviceAuthBrokerTest&) = delete; @@ -65,16 +114,36 @@ base::expected<std::string, GoogleServiceAuthError> GetChallengeBytes() { base::expected<std::string, GoogleServiceAuthError> response; base::RunLoop run_loop; - base::OnceCallback<void( - const base::expected<std::string, GoogleServiceAuthError>&)> - callback = base::BindLambdaForTesting( + SecondDeviceAuthBroker::ChallengeBytesCallback callback = + base::BindLambdaForTesting( [&response, &run_loop]( const base::expected<std::string, GoogleServiceAuthError>& returned_response) -> void { response = returned_response; run_loop.Quit(); }); - second_device_auth_broker().GetChallengeBytes(std::move(callback)); + second_device_auth_broker_.GetChallengeBytes(std::move(callback)); + run_loop.Run(); + + return response; + } + + base::expected<std::string, SecondDeviceAuthBroker::AttestationErrorType> + FetchAttestationCertificate(const std::string& fido_credential_id) { + base::expected<std::string, SecondDeviceAuthBroker::AttestationErrorType> + response; + base::RunLoop run_loop; + SecondDeviceAuthBroker::AttestationCertificateCallback callback = + base::BindLambdaForTesting( + [&response, &run_loop]( + const base::expected< + std::string, SecondDeviceAuthBroker::AttestationErrorType>& + returned_response) -> void { + response = returned_response; + run_loop.Quit(); + }); + second_device_auth_broker_.FetchAttestationCertificate(fido_credential_id, + std::move(callback)); run_loop.Run(); return response; @@ -89,8 +158,8 @@ net::HTTP_UNAUTHORIZED); } - SecondDeviceAuthBroker& second_device_auth_broker() { - return second_device_auth_broker_; + attestation::MockAttestationFlow& mock_attestation_flow() { + return mock_attestation_flow_; } private: @@ -99,6 +168,7 @@ data_decoder::test::InProcessDataDecoder in_process_data_decoder_; network::TestURLLoaderFactory test_factory_; + StrictMock<attestation::MockAttestationFlow> mock_attestation_flow_; SecondDeviceAuthBroker second_device_auth_broker_; }; @@ -152,4 +222,89 @@ EXPECT_THAT(response->size(), Gt(0UL)); } +TEST_F( + SecondDeviceAuthBrokerTest, + FetchAttestationCertificateReturnsATransientErrorForUnspecifiedFailures) { + EXPECT_CALL( + mock_attestation_flow(), + GetCertificate( + /*certificate_profile=*/attestation::AttestationCertificateProfile:: + PROFILE_DEVICE_SETUP_CERTIFICATE, + /*account_id=*/EmptyAccountId(), /*request_origin=*/"", + /*force_new_key=*/_, /*key_crypto_type=*/_, /*key_name=*/_, + /*profile_specific_data=*/_, /*callback=*/_)) + .WillOnce(WithArg<7>( + Invoke([](attestation::AttestationFlow::CertificateCallback callback) + -> void { + std::move(callback).Run( + /*status=*/ash::attestation::AttestationStatus:: + ATTESTATION_UNSPECIFIED_FAILURE, + /*pem_certificate_chain=*/std::string()); + }))); + + base::expected<std::string, SecondDeviceAuthBroker::AttestationErrorType> + response = FetchAttestationCertificate(kFidoCredentialId); + ASSERT_THAT(response.has_value(), IsFalse()); + EXPECT_THAT( + response.error(), + Eq(SecondDeviceAuthBroker::AttestationErrorType::kTransientError)); +} + +TEST_F(SecondDeviceAuthBrokerTest, + FetchAttestationCertificateReturnsAPermanentErrorForBadRequests) { + EXPECT_CALL( + mock_attestation_flow(), + GetCertificate( + /*certificate_profile=*/attestation::AttestationCertificateProfile:: + PROFILE_DEVICE_SETUP_CERTIFICATE, + /*account_id=*/EmptyAccountId(), /*request_origin=*/"", + /*force_new_key=*/_, /*key_crypto_type=*/_, /*key_name=*/_, + /*profile_specific_data=*/_, /*callback=*/_)) + .WillOnce(WithArg<7>( + Invoke([](attestation::AttestationFlow::CertificateCallback callback) + -> void { + std::move(callback).Run( + /*status=*/ash::attestation::AttestationStatus:: + ATTESTATION_SERVER_BAD_REQUEST_FAILURE, + /*pem_certificate_chain=*/std::string()); + }))); + + base::expected<std::string, SecondDeviceAuthBroker::AttestationErrorType> + response = FetchAttestationCertificate(kFidoCredentialId); + ASSERT_THAT(response.has_value(), IsFalse()); + EXPECT_THAT( + response.error(), + Eq(SecondDeviceAuthBroker::AttestationErrorType::kPermanentError)); +} + +TEST_F(SecondDeviceAuthBrokerTest, + FetchAttestationCertificateReturnsACertificate) { + const std::string kCertificate = "fake_certificate"; + EXPECT_CALL( + mock_attestation_flow(), + GetCertificate( + /*certificate_profile=*/attestation::AttestationCertificateProfile:: + PROFILE_DEVICE_SETUP_CERTIFICATE, + /*account_id=*/EmptyAccountId(), /*request_origin=*/"", + /*force_new_key=*/_, /*key_crypto_type=*/_, /*key_name=*/_, + /*profile_specific_data=*/ + Optional( + VariantWith<::attestation::DeviceSetupCertificateRequestMetadata>( + ProtoBufContentBindingEq(kFidoCredentialId))), + /*callback*/ _)) + .WillOnce(WithArg< + 7>(Invoke([&kCertificate]( + attestation::AttestationFlow::CertificateCallback + callback) -> void { + std::move(callback).Run( + /*status=*/ash::attestation::AttestationStatus::ATTESTATION_SUCCESS, + /*pem_certificate_chain=*/kCertificate); + }))); + + base::expected<std::string, SecondDeviceAuthBroker::AttestationErrorType> + response = FetchAttestationCertificate(kFidoCredentialId); + ASSERT_THAT(response.has_value(), IsTrue()); + EXPECT_THAT(response.value(), Eq(kCertificate)); +} + } // namespace ash::quick_start
diff --git a/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc b/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc index a5974dd..85341b7 100644 --- a/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc +++ b/chrome/browser/ash/web_applications/files_internals_ui_delegate.cc
@@ -55,3 +55,16 @@ file_manager::file_tasks::SetOfficeSetupComplete(profile, complete); } } + +bool ChromeFilesInternalsUIDelegate::GetAlwaysMoveOfficeFiles() const { + Profile* profile = Profile::FromWebUI(web_ui_); + return profile && file_manager::file_tasks::AlwaysMoveOfficeFiles(profile); +} + +void ChromeFilesInternalsUIDelegate::SetAlwaysMoveOfficeFiles( + bool always_move) { + Profile* profile = Profile::FromWebUI(web_ui_); + if (profile) { + file_manager::file_tasks::SetAlwaysMoveOfficeFiles(profile, always_move); + } +}
diff --git a/chrome/browser/ash/web_applications/files_internals_ui_delegate.h b/chrome/browser/ash/web_applications/files_internals_ui_delegate.h index 44e3b29..0be68ac 100644 --- a/chrome/browser/ash/web_applications/files_internals_ui_delegate.h +++ b/chrome/browser/ash/web_applications/files_internals_ui_delegate.h
@@ -30,6 +30,9 @@ bool GetOfficeSetupComplete() const override; void SetOfficeSetupComplete(bool complete) override; + bool GetAlwaysMoveOfficeFiles() const override; + void SetAlwaysMoveOfficeFiles(bool always_move) override; + private: raw_ptr<content::WebUI> web_ui_; // Owns |this|. };
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc index 496c41b..4a16890 100644 --- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc +++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
@@ -94,6 +94,17 @@ std::move(mock_tpm_challenge_key)); } + void SetMockTpmChallengerBadBase64Error() { + auto mock_tpm_challenge_key = + std::make_unique<NiceMock<ash::attestation::MockTpmChallengeKey>>(); + // Error text is "Challenge is not base64 encoded." + mock_tpm_challenge_key->EnableFakeError( + ash::attestation::TpmChallengeKeyResultCode::kChallengeBadBase64Error); + // transfer ownership inside factory + ash::attestation::TpmChallengeKeyFactory::SetForTesting( + std::move(mock_tpm_challenge_key)); + } + // This will be called by BrowserWithTestWindowTest::SetUp(); TestingProfile* CreateProfile() override { fake_user_manager_->AddUserWithAffiliation( @@ -216,6 +227,21 @@ EXPECT_EQ("response", response); } +TEST_F(EPKChallengeMachineKeyTest, BadChallengeThenErrorMessageReturned) { + SetMockTpmChallengerBadBase64Error(); + + base::Value allowlist(base::Value::Type::LIST); + allowlist.Append(extension_->id()); + prefs_->Set(prefs::kAttestationExtensionAllowlist, allowlist); + + base::Value value( + RunFunctionAndReturnError(func_.get(), CreateArgs(), browser())); + + EXPECT_EQ( + ash::attestation::TpmChallengeKeyResult::kChallengeBadBase64ErrorMsg, + value); +} + TEST_F(EPKChallengeMachineKeyTest, KeyNotRegisteredByDefault) { SetMockTpmChallenger(); @@ -266,7 +292,37 @@ scoped_refptr<EnterprisePlatformKeysChallengeUserKeyFunction> func_; }; -TEST_F(EPKChallengeUserKeyTest, ExtensionNotAllowed) { +TEST_F(EPKChallengeUserKeyTest, Success) { + SetMockTpmChallenger(); + + base::Value allowlist(base::Value::Type::LIST); + allowlist.Append(extension_->id()); + prefs_->Set(prefs::kAttestationExtensionAllowlist, allowlist); + + base::Value value( + RunFunctionAndReturnSingleResult(func_.get(), CreateArgs(), browser())); + + ASSERT_TRUE(value.is_blob()); + std::string response(value.GetBlob().begin(), value.GetBlob().end()); + EXPECT_EQ("response", response); +} + +TEST_F(EPKChallengeUserKeyTest, BadChallengeThenErrorMessageReturned) { + SetMockTpmChallengerBadBase64Error(); + + base::Value allowlist(base::Value::Type::LIST); + allowlist.Append(extension_->id()); + prefs_->Set(prefs::kAttestationExtensionAllowlist, allowlist); + + base::Value value( + RunFunctionAndReturnError(func_.get(), CreateArgs(), browser())); + + EXPECT_EQ( + ash::attestation::TpmChallengeKeyResult::kChallengeBadBase64ErrorMsg, + value); +} + +TEST_F(EPKChallengeUserKeyTest, ExtensionNotAllowedThenErrorMessageReturned) { base::ListValue empty_allowlist; prefs_->Set(prefs::kAttestationExtensionAllowlist, empty_allowlist);
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc index 0bb57d6b..fda585e 100644 --- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc +++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -55,8 +55,6 @@ namespace ClearComposition = extensions::api::input_ime::ClearComposition; namespace OnCompositionBoundsChanged = extensions::api::input_method_private::OnCompositionBoundsChanged; -namespace NotifyImeMenuItemActivated = - extensions::api::input_method_private::NotifyImeMenuItemActivated; namespace OnScreenProjectionChanged = extensions::api::input_method_private::OnScreenProjectionChanged; namespace FinishComposingText = @@ -1327,31 +1325,6 @@ } ExtensionFunction::ResponseAction -InputMethodPrivateNotifyImeMenuItemActivatedFunction::Run() { - ash::input_method::InputMethodDescriptor current_input_method = - ash::input_method::InputMethodManager::Get() - ->GetActiveIMEState() - ->GetCurrentInputMethod(); - std::string active_extension_id = - ash::extension_ime_util::GetExtensionIDFromInputMethodID( - current_input_method.id()); - std::string error; - InputMethodEngine* engine = - GetEngineIfActive(Profile::FromBrowserContext(browser_context()), - active_extension_id, &error); - if (!engine) - return RespondNow(Error(InformativeError(error, static_function_name()))); - - std::unique_ptr<NotifyImeMenuItemActivated::Params> params( - NotifyImeMenuItemActivated::Params::Create(args())); - if (params->engine_id != engine->GetActiveComponentId()) - return RespondNow( - Error(InformativeError(kErrorEngineNotActive, static_function_name()))); - engine->PropertyActivate(params->name); - return RespondNow(NoArguments()); -} - -ExtensionFunction::ResponseAction InputMethodPrivateGetCompositionBoundsFunction::Run() { std::string error; InputMethodEngine* engine = GetEngineIfActive(
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h index a820debb..016ccbf 100644 --- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h +++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
@@ -152,27 +152,6 @@ INPUTMETHODPRIVATE_FINISHCOMPOSINGTEXT) }; -class InputMethodPrivateNotifyImeMenuItemActivatedFunction - : public ExtensionFunction { - public: - InputMethodPrivateNotifyImeMenuItemActivatedFunction() = default; - - InputMethodPrivateNotifyImeMenuItemActivatedFunction( - const InputMethodPrivateNotifyImeMenuItemActivatedFunction&) = delete; - InputMethodPrivateNotifyImeMenuItemActivatedFunction& operator=( - const InputMethodPrivateNotifyImeMenuItemActivatedFunction&) = delete; - - protected: - ~InputMethodPrivateNotifyImeMenuItemActivatedFunction() override = default; - - // ExtensionFunction: - ResponseAction Run() override; - - private: - DECLARE_EXTENSION_FUNCTION("inputMethodPrivate.notifyImeMenuItemActivated", - INPUTMETHODPRIVATE_NOTIFYIMEMENUITEMACTIVATED) -}; - class InputMethodPrivateGetCompositionBoundsFunction : public ExtensionFunction { public:
diff --git a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sort_ui/FeedOptionsView.java b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sort_ui/FeedOptionsView.java index e7c85b1..78f3262 100644 --- a/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sort_ui/FeedOptionsView.java +++ b/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/sort_ui/FeedOptionsView.java
@@ -4,6 +4,9 @@ package org.chromium.chrome.browser.feed.sort_ui; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; + import android.content.Context; import android.util.AttributeSet; import android.view.View; @@ -59,7 +62,14 @@ /** Expands this view to full height. */ private void expand() { - if (this.getParent() == null) return; + // If the view's parent is not shown, we want to set this view as VISIBLE without the + // animation, and reset the height if it was previously set by collapse() animation. + if (getParent() == null || !(((View) getParent()).isShown())) { + setVisibility(VISIBLE); + setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)); + return; + } + // Width is match_parent and height is wrap_content. int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec( ((ViewGroup) getParent()).getWidth(), View.MeasureSpec.EXACTLY); @@ -97,7 +107,13 @@ /** Collapses this view to 0 height and then marks it GONE. */ private void collapse() { - if (this.getParent() == null) return; + // If the view's parent is not shown, we want to set this view as GONE without the + // animation. + if (getParent() == null || !(((View) getParent()).isShown())) { + setVisibility(GONE); + return; + } + int initialHeight = getMeasuredHeight(); Animation animation = new Animation() {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 2ebfcb2..0ca8280 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -325,24 +325,6 @@ "When enabled, manual fallback will be auto-triggered on form interaction " "in the case where autofill failed to fill a credit card form accurately."; -const char kAutofillCenterAligngedSuggestionsName[] = - "Center-aligned Autofill suggestions."; -const char kAutofillCenterAligngedSuggestionsDescription[] = - "When enabled, the Autofill suggestion popup will be aligned to the center " - "of the initiating field and not to its border."; - -const char kAutofillVisualImprovementsForSuggestionUiName[] = - "Visual improvements for the Autofill and Password Manager suggestion UI."; -const char kAutofillVisualImprovementsForSuggestionUiDescription[] = - "Non function changes that visually improve the suggestion UI used for " - "addresses, passswords and credit cards."; - -const char kAutofillTypeSpecificPopupWidthName[] = - "Type-specific width limits for the Autofill popup"; -const char kAutofillTypeSpecificPopupWidthDescription[] = - "Controls if different width limits are used for the popup that provides " - "Autofill suggestions, depending on the type of data that is filled."; - const char kAutofillEnableGetDetailsForEnrollParsingInUploadCardResponseName[] = "Enable parsing of the GetDetailsForEnrollResponseDetails in the " "UploadCardResponseDetails"; @@ -589,12 +571,6 @@ "Enables biometric" "re-authentication before password filling"; -const char kTouchToFillPasswordSubmissionName[] = - "Form submission in Touch-To-Fill"; -const char kTouchToFillPasswordSubmissionDescription[] = - "Enables automatic form submission after filling credentials with " - "Touch-To-Fill"; - const char kFastCheckoutName[] = "Fast Checkout"; const char kFastCheckoutDescription[] = "Enables Fast Checkout experiences in Chrome.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 04eee2b..f6158de 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -192,15 +192,6 @@ extern const char kAutofillAutoTriggerManualFallbackForCardsName[]; extern const char kAutofillAutoTriggerManualFallbackForCardsDescription[]; -extern const char kAutofillCenterAligngedSuggestionsName[]; -extern const char kAutofillCenterAligngedSuggestionsDescription[]; - -extern const char kAutofillVisualImprovementsForSuggestionUiName[]; -extern const char kAutofillVisualImprovementsForSuggestionUiDescription[]; - -extern const char kAutofillTypeSpecificPopupWidthName[]; -extern const char kAutofillTypeSpecificPopupWidthDescription[]; - extern const char kAutofillEnableGetDetailsForEnrollParsingInUploadCardResponseName[]; extern const char @@ -319,9 +310,6 @@ extern const char kBiometricReauthForPasswordFillingName[]; extern const char kBiometricReauthForPasswordFillingDescription[]; -extern const char kTouchToFillPasswordSubmissionName[]; -extern const char kTouchToFillPasswordSubmissionDescription[]; - extern const char kFastCheckoutName[]; extern const char kFastCheckoutDescription[];
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 fd64bb8..e91e9eb 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
@@ -313,7 +313,6 @@ public static final String EARLY_LIBRARY_LOAD = "EarlyLibraryLoad"; public static final String ENABLE_AUTOMATIC_SNOOZE = "EnableAutomaticSnooze"; public static final String ENABLE_PASSWORDS_ACCOUNT_STORAGE = "EnablePasswordsAccountStorage"; - public static final String ELASTIC_OVERSCROLL = "ElasticOverscroll"; public static final String EXPERIMENTS_FOR_AGSA = "ExperimentsForAgsa"; public static final String EXPLICIT_LANGUAGE_ASK = "ExplicitLanguageAsk"; public static final String EXPLORE_SITES = "ExploreSites"; @@ -655,7 +654,6 @@ public static final CachedFlag sDownloadsAutoResumptionNative = new CachedFlag(DOWNLOADS_AUTO_RESUMPTION_NATIVE, true); public static final CachedFlag sEarlyLibraryLoad = new CachedFlag(EARLY_LIBRARY_LOAD, true); - public static final CachedFlag sElasticOverscroll = new CachedFlag(ELASTIC_OVERSCROLL, true); public static final CachedFlag sExperimentsForAgsa = new CachedFlag(EXPERIMENTS_FOR_AGSA, true); public static final CachedFlag sFeedLoadingPlaceholder = new CachedFlag(FEED_LOADING_PLACEHOLDER, false);
diff --git a/chrome/browser/history/history_tab_helper_unittest.cc b/chrome/browser/history/history_tab_helper_unittest.cc index 35ef277..986393e 100644 --- a/chrome/browser/history/history_tab_helper_unittest.cc +++ b/chrome/browser/history/history_tab_helper_unittest.cc
@@ -471,11 +471,10 @@ {{"implementation_type", "mparch"}}); break; case MPArchType::kPrerender: - scoped_feature_list_.InitWithFeatures( - {blink::features::kPrerender2}, + scoped_feature_list_.InitAndDisableFeature( // Disable the memory requirement of Prerender2 so the test can run // on any bot. - {blink::features::kPrerender2MemoryControls}); + blink::features::kPrerender2MemoryControls); break; } }
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc index 979ae74..533e94e 100644 --- a/chrome/browser/infobars/infobars_browsertest.cc +++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -13,6 +13,7 @@ #include "build/build_config.h" #include "build/buildflag.h" #include "build/chromeos_buildflags.h" +#include "chrome/browser/buildflags.h" #include "chrome/browser/devtools/devtools_infobar_delegate.h" #include "chrome/browser/extensions/api/debugger/extension_dev_tools_infobar_delegate.h" #include "chrome/browser/extensions/api/messaging/incognito_connectability_infobar_delegate.h" @@ -65,7 +66,7 @@ #include "chrome/browser/ui/startup/default_browser_infobar_delegate.h" #endif -#if BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER) #include "chrome/browser/ui/cocoa/keystone_infobar_delegate.h" #endif @@ -279,7 +280,7 @@ break; case IBD::KEYSTONE_PROMOTION_INFOBAR_DELEGATE_MAC: -#if BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER) KeystonePromotionInfoBarDelegate::Create(GetWebContents()); #else ADD_FAILURE() << "This infobar is not supported on this OS."; @@ -410,7 +411,7 @@ ShowAndVerifyUi(); } -#if BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER) IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_keystone_promotion) { ShowAndVerifyUi(); }
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc index 5d1acce..98847c8 100644 --- a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc +++ b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
@@ -17,7 +17,9 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/common/chrome_content_client.h" +#include "components/gcm_driver/gcm_driver.h" #include "components/gcm_driver/gcm_profile_service.h" +#include "components/gcm_driver/instance_id/instance_id_driver.h" #include "components/gcm_driver/instance_id/instance_id_profile_service.h" #include "components/invalidation/impl/fcm_invalidation_service.h" #include "components/invalidation/impl/fcm_network_handler.h"
diff --git a/chrome/browser/media/media_engagement_contents_observer_unittest.cc b/chrome/browser/media/media_engagement_contents_observer_unittest.cc index 766637e6..b083091 100644 --- a/chrome/browser/media/media_engagement_contents_observer_unittest.cc +++ b/chrome/browser/media/media_engagement_contents_observer_unittest.cc
@@ -1370,11 +1370,10 @@ : public MediaEngagementContentsObserverTest { public: MediaEngagementContentsObserverPrerenderTest() { - scoped_feature_list_.InitWithFeatures( - {blink::features::kPrerender2}, + scoped_feature_list_.InitAndDisableFeature( // Disable the memory requirement of Prerender2 so the test can run on // any bot. - {blink::features::kPrerender2MemoryControls}); + blink::features::kPrerender2MemoryControls); } ~MediaEngagementContentsObserverPrerenderTest() override = default;
diff --git a/chrome/browser/net/nss_service.cc b/chrome/browser/net/nss_service.cc index 78cd32e..bb67767f 100644 --- a/chrome/browser/net/nss_service.cc +++ b/chrome/browser/net/nss_service.cc
@@ -12,6 +12,7 @@ #include "base/task/sequenced_task_runner.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" +#include "net/cert/nss_cert_database.h" // Note: This file contains the platform-agnostic components of NssService; // platform-specific portions are implemented in the _linux.cc and
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc index a5827c8a..66d2177c 100644 --- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc +++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
@@ -35,7 +35,6 @@ void PageLoadMetricsObserverTestHarness::InitializeFeatureList() { scoped_feature_list_.InitWithFeaturesAndParameters( { - {blink::features::kPrerender2, {}}, {blink::features::kFencedFrames, {{"implementation_type", "mparch"}}}, }, {
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc index b80ba44..3db8618 100644 --- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc +++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -82,6 +82,7 @@ #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/common/referrer.h" +#include "content/public/common/result_codes.h" #include "content/public/test/back_forward_cache_util.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" @@ -99,6 +100,7 @@ #include "services/network/public/cpp/features.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/chrome_debug_urls.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/user_agent/user_agent_metadata.h" #include "third_party/blink/public/mojom/use_counter/metrics/css_property_id.mojom.h" @@ -3317,7 +3319,7 @@ ASSERT_EQ(all_frames_value, main_frame_value); } -class PageLoadMetricsBrowserTestDiscardedPage +class PageLoadMetricsBrowserTestTerminatedPage : public PageLoadMetricsBrowserTest { protected: void SetUpOnMainThread() override { @@ -3400,7 +3402,7 @@ } }; -IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTestDiscardedPage, +IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTestTerminatedPage, UkmIsRecordedForDiscardedForegroundTabPage) { // Open a new foreground tab and navigate. The new tab would be of index 1 // which would be used below in verifying the tab is discarded. @@ -3424,7 +3426,7 @@ lcp_time, 10); } -IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTestDiscardedPage, +IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTestTerminatedPage, UkmIsRecordedForDiscardedBackgroundTabPage) { // Open a new foreground tab and navigate. content::WebContents* contents = OpenTabAndNavigate(); @@ -3452,6 +3454,80 @@ lcp_time, 10); } +// This test is to verify page load metrics are recorded in case when the +// render process is shut down. +IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTestTerminatedPage, + UkmIsRecordedWhenRenderProcessShutsDown) { + content::WebContents* contents = OpenTabAndNavigate(); + + // Wait for LCP emission and observation. + double lcp_time = GetLCPTimeFromEmittedLCPEntry(contents); + content::RenderProcessHost* process = RenderFrameHost()->GetProcess(); + + // Shut down render process. + content::RenderProcessHostWatcher crash_observer( + process, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT); + EXPECT_TRUE(process->Shutdown(content::RESULT_CODE_KILLED)); + crash_observer.Wait(); + EXPECT_FALSE(RenderFrameHost()->IsRenderFrameLive()); + + // Verify page load metric is recorded. + EXPECT_NEAR( + GetUKMPageLoadMetric( + PageLoad::kPaintTiming_NavigationToLargestContentfulPaint2Name), + lcp_time, 10); +} + +// This class is used to verify page load metrics are recorded in case of +// crashes of different kinds. These crashes are simulated by navigating to the +// chrome debug urls. +class PageLoadMetricsBrowserTestCrashedPage + : public PageLoadMetricsBrowserTestTerminatedPage, + public ::testing::WithParamInterface<const char*> {}; + +IN_PROC_BROWSER_TEST_P(PageLoadMetricsBrowserTestCrashedPage, + UkmIsRecordedForCrashedTabPage) { + // Open a new foreground tab and navigate. + content::WebContents* contents = OpenTabAndNavigate(); + + // The back/forward cache is disabled because page load metrics can also be + // recorded when entering into the bfcache. We want to test that page load + // metrics are recorded via the PageLoadTracker destructor which is called in + // all crash cases. + content::DisableBackForwardCacheForTesting( + contents, content::BackForwardCache::TEST_REQUIRES_NO_CACHING); + + // Wait for LCP emission and observation. This is to ensure there is an LCP + // entry to report at the time of killing the page. + double lcp_time = GetLCPTimeFromEmittedLCPEntry(contents); + + // Kill the page. + content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(GetParam()))); + + // Page being crashed is only verifiable in these crashes. + if (GetParam() == blink::kChromeUIKillURL || + GetParam() == blink::kChromeUICrashURL) + EXPECT_TRUE( + browser()->tab_strip_model()->GetActiveWebContents()->IsCrashed()); + + // Verify page load metric is recorded. + EXPECT_NEAR( + GetUKMPageLoadMetric( + PageLoad::kPaintTiming_NavigationToLargestContentfulPaint2Name), + lcp_time, 10); +} + +INSTANTIATE_TEST_SUITE_P( + CrashCases, + PageLoadMetricsBrowserTestCrashedPage, + testing::ValuesIn({blink::kChromeUIKillURL, blink::kChromeUICrashURL, + blink::kChromeUIGpuCrashURL, + blink::kChromeUIBrowserCrashURL, + blink::kChromeUIMemoryExhaustURL, + blink::kChromeUINetworkErrorURL, + blink::kChromeUIProcessInternalsURL})); + // Test is flaky. https://crbug.com/1260953 #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX) || \ BUILDFLAG(IS_WIN) @@ -3759,9 +3835,6 @@ // is re-enabled, it should be updated to use a different mechanism. PageLoadMetricsBrowserTest::SetUpCommandLine(command_line); } - - private: - base::test::ScopedFeatureList scoped_feature_list_; }; // Flaky. See https://crbug.com/1224780. @@ -3837,9 +3910,7 @@ PrerenderPageLoadMetricsBrowserTest() : prerender_helper_(base::BindRepeating( &PrerenderPageLoadMetricsBrowserTest::web_contents, - base::Unretained(this))) { - feature_list_.InitAndEnableFeature(blink::features::kPrerender2); - } + base::Unretained(this))) {} void SetUp() override { prerender_helper_.SetUp(embedded_test_server()); @@ -3848,7 +3919,6 @@ protected: content::test::PrerenderTestHelper prerender_helper_; - base::test::ScopedFeatureList feature_list_; }; IN_PROC_BROWSER_TEST_F(PrerenderPageLoadMetricsBrowserTest, PrerenderEvent) {
diff --git a/chrome/browser/platform_util_linux.cc b/chrome/browser/platform_util_linux.cc index de23908..90bf7b59 100644 --- a/chrome/browser/platform_util_linux.cc +++ b/chrome/browser/platform_util_linux.cc
@@ -24,6 +24,7 @@ #include "base/threading/scoped_blocking_call.h" #include "chrome/browser/lifetime/termination_notification.h" #include "chrome/browser/platform_util_internal.h" +#include "chrome/browser/profiles/profile.h" // This file gets pulled in in Chromecast builds, which causes "gn check" to // complain as Chromecast doesn't use (or depend on) //components/dbus. // TODO(crbug.com/1215474): Eliminate //chrome being visible in the GN structure
diff --git a/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc b/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc index a97257e..3f03198 100644 --- a/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc +++ b/chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.cc
@@ -26,6 +26,7 @@ #include "chrome/browser/policy/cloud/remote_commands_invalidator_impl.h" #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths.h" +#include "components/gcm_driver/gcm_driver.h" #include "components/gcm_driver/instance_id/instance_id_driver.h" #include "components/invalidation/impl/fcm_invalidation_service.h" #include "components/invalidation/impl/fcm_network_handler.h"
diff --git a/chrome/browser/preloading/prerender/prerender_omnibox_ui_browsertest.cc b/chrome/browser/preloading/prerender/prerender_omnibox_ui_browsertest.cc index ccaf7c8..2b35343 100644 --- a/chrome/browser/preloading/prerender/prerender_omnibox_ui_browsertest.cc +++ b/chrome/browser/preloading/prerender/prerender_omnibox_ui_browsertest.cc
@@ -500,8 +500,7 @@ public: PrerenderPreloaderHoldbackBrowserTest() { feature_list_.InitWithFeatures( - /*enabled_features=*/{blink::features::kPrerender2, - features::kOmniboxTriggerForPrerender2, + /*enabled_features=*/{features::kOmniboxTriggerForPrerender2, features::kPrerender2Holdback}, /* disabled_features=*/{}); }
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc index a0f5d82..680a185 100644 --- a/chrome/browser/push_messaging/push_messaging_service_impl.cc +++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -64,6 +64,7 @@ #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "third_party/blink/public/common/permissions/permission_utils.h" +#include "third_party/blink/public/common/storage_key/storage_key.h" #include "third_party/blink/public/mojom/devtools/console_message.mojom.h" #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h" #include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom.h" @@ -179,9 +180,10 @@ else if (was_encrypted) event_metadata["Payload"] = payload; + url::Origin origin = url::Origin::Create(app_identifier.origin()); devtools_context->LogBackgroundServiceEvent( app_identifier.service_worker_registration_id(), - url::Origin::Create(app_identifier.origin()), + blink::StorageKey(origin), content::DevToolsBackgroundService::kPushMessaging, "Push message received" /* event_name */, message_id, event_metadata); } @@ -723,12 +725,13 @@ if (app_identifier.is_null()) return; + url::Origin origin = url::Origin::Create(app_identifier.origin()); if (auto* devtools_context = GetDevToolsContext(app_identifier.origin())) { std::stringstream ss; ss << unsubscribe_reason; devtools_context->LogBackgroundServiceEvent( app_identifier.service_worker_registration_id(), - url::Origin::Create(app_identifier.origin()), + blink::StorageKey(origin), content::DevToolsBackgroundService::kPushMessaging, "Unsubscribed due to error" /* event_name */, message.message_id, {{"Reason", ss.str()}}); @@ -793,10 +796,11 @@ if (app_identifier.is_null() || !did_show_generic_notification) return; + url::Origin origin = url::Origin::Create(app_identifier.origin()); if (auto* devtools_context = GetDevToolsContext(app_identifier.origin())) { devtools_context->LogBackgroundServiceEvent( app_identifier.service_worker_registration_id(), - url::Origin::Create(app_identifier.origin()), + blink::StorageKey(origin), content::DevToolsBackgroundService::kPushMessaging, "Generic notification shown" /* event_name */, push_message_id, {} /* event_metadata */);
diff --git a/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn b/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn index 0b7026e..05ff935 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn +++ b/chrome/browser/resources/chromeos/cloud_upload/BUILD.gn
@@ -20,6 +20,7 @@ "base_setup_page.ts", "drive_upload_page.ts", "file_handler_page.ts", + "move_confirmation_page.ts", "office_pwa_install_page.ts", "one_drive_upload_page.ts", "sign_in_page.ts",
diff --git a/chrome/browser/resources/chromeos/cloud_upload/drive_upload_page.ts b/chrome/browser/resources/chromeos/cloud_upload/drive_upload_page.ts index b6f8502b..a88499e 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/drive_upload_page.ts +++ b/chrome/browser/resources/chromeos/cloud_upload/drive_upload_page.ts
@@ -35,7 +35,8 @@ } private onContinueButtonClick(): void { - this.proxy.handler.respondAndClose(UserAction.kUploadToGoogleDrive); + this.proxy.handler.respondAndClose( + UserAction.kConfirmOrUploadToGoogleDrive); } private onCancelButtonClick(): void {
diff --git a/chrome/browser/resources/chromeos/cloud_upload/main.ts b/chrome/browser/resources/chromeos/cloud_upload/main.ts index 6db2907..d7916d0 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/main.ts +++ b/chrome/browser/resources/chromeos/cloud_upload/main.ts
@@ -10,6 +10,7 @@ import {DialogPage} from './cloud_upload.mojom-webui.js'; import {CloudUploadBrowserProxy} from './cloud_upload_browser_proxy.js'; +import {CloudProvider, MoveConfirmationPageElement} from './move_confirmation_page.js'; const dialogArgs = await CloudUploadBrowserProxy.getInstance().handler.getDialogArgs(); @@ -28,4 +29,16 @@ document.body.append(document.createElement('drive-upload-page')); break; } + case DialogPage.kMoveConfirmationOneDrive: { + const movePage = new MoveConfirmationPageElement(); + movePage.setCloudProvider(CloudProvider.ONE_DRIVE); + document.body.append(movePage); + break; + } + case DialogPage.kMoveConfirmationGoogleDrive: { + const movePage = new MoveConfirmationPageElement(); + movePage.setCloudProvider(CloudProvider.GOOGLE_DRIVE); + document.body.append(movePage); + break; + } } \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/cloud_upload/move_confirmation_page.html b/chrome/browser/resources/chromeos/cloud_upload/move_confirmation_page.html new file mode 100644 index 0000000..991ce001 --- /dev/null +++ b/chrome/browser/resources/chromeos/cloud_upload/move_confirmation_page.html
@@ -0,0 +1,53 @@ +<style> + :host { + box-sizing: border-box; + display: flex; + flex-direction: column; + padding: 24px; + width: 448px; + } + + /* TODO(petermarshall): Possibly change font based on the specs */ + .title { + color: var(--cros-text-color-primary); + font: var(--cros-display-7-font); + } + + .normal-text { + color: var(--cros-text-color-secondary); + font: var(--cros-body-1-font); + margin-block-start: 16px; + } + + cr-checkbox { + margin-block-end: 2px; + margin-block-start: 18px; + } + + .checkbox-text { + color: var(--cros-text-color-secondary); + font: var(--cros-body-1-font); + } + + #button-container { + display: flex; + justify-content: flex-end; + } +</style> + +<!-- TODO(b/258071752): Use localized strings --> +<div class="title"> + Move file to <span id="provider-name"></span> to open +</div> +<div class="normal-text"> + The <span id="app-name"></span> app requires files to be in + <span id="provider-short-name"></span>. We can move your files + whenever you chose to open them. +</div> +<cr-checkbox id="always-move-checkbox"> + <p class="checkbox-text">Do this automatically next time</p> +</cr-checkbox> +<div id="button-container"> + <cr-button class="cancel-button">$i18n{cancel}</cr-button> + <cr-button class="action-button">Move & open file</cr-button> +</div> \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/cloud_upload/move_confirmation_page.ts b/chrome/browser/resources/chromeos/cloud_upload/move_confirmation_page.ts new file mode 100644 index 0000000..faed50a8 --- /dev/null +++ b/chrome/browser/resources/chromeos/cloud_upload/move_confirmation_page.ts
@@ -0,0 +1,87 @@ +// 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. + +import 'chrome://resources/cr_elements/cr_button/cr_button.js'; +import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; + +import {UserAction} from './cloud_upload.mojom-webui.js'; +import {CloudUploadBrowserProxy} from './cloud_upload_browser_proxy.js'; +import {getTemplate} from './move_confirmation_page.html.js'; +import type {CrCheckboxElement} from 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.js'; + +export enum CloudProvider { + GOOGLE_DRIVE, + ONE_DRIVE, +} + +/** + * The MoveConfirmationPageElement represents the dialog page shown when the + * user opens a file that needs to be moved first, and they haven't yet decided + * to always move files. + */ +export class MoveConfirmationPageElement extends HTMLElement { + private proxy: CloudUploadBrowserProxy = + CloudUploadBrowserProxy.getInstance(); + private cloudProvider: CloudProvider|undefined; + + constructor() { + super(); + + const shadowRoot = this.attachShadow({mode: 'open'}); + + shadowRoot.innerHTML = getTemplate(); + const moveButton = shadowRoot.querySelector<HTMLElement>('.action-button')!; + const cancelButton = + shadowRoot.querySelector<HTMLElement>('.cancel-button')!; + + moveButton.addEventListener('click', () => this.onMoveButtonClick()); + cancelButton.addEventListener('click', () => this.onCancelButtonClick()); + } + + private getProviderText(cloudProvider: CloudProvider) { + if (cloudProvider === CloudProvider.ONE_DRIVE) { + return { + name: 'Microsoft OneDrive', + appName: 'Microsoft 365', + shortName: 'OneDrive', + }; + } + // TODO(b/260141250): Display Slides or Sheets when appropriate instead? + return {name: 'Google Drive', appName: 'Google Docs', shortName: 'Drive'}; + } + + setCloudProvider(cloudProvider: CloudProvider) { + this.cloudProvider = cloudProvider; + + const {name, appName, shortName} = this.getProviderText(this.cloudProvider); + this.shadowRoot!.getElementById('provider-name')!.innerText = name; + this.shadowRoot!.getElementById('app-name')!.innerText = appName; + this.shadowRoot!.getElementById('provider-short-name')!.innerText = + shortName; + } + + private onMoveButtonClick(): void { + const checkbox = this.shadowRoot!.querySelector<CrCheckboxElement>( + '#always-move-checkbox')!; + this.proxy.handler.setAlwaysMoveOfficeFiles(checkbox.checked); + + if (this.cloudProvider === CloudProvider.ONE_DRIVE) { + this.proxy.handler.respondAndClose(UserAction.kUploadToOneDrive); + } else { + this.proxy.handler.respondAndClose(UserAction.kUploadToGoogleDrive); + } + } + + private onCancelButtonClick(): void { + this.proxy.handler.respondAndClose(UserAction.kCancel); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'move-confirmation-page': MoveConfirmationPageElement; + } +} + +customElements.define('move-confirmation-page', MoveConfirmationPageElement); \ No newline at end of file
diff --git a/chrome/browser/resources/chromeos/cloud_upload/one_drive_upload_page.ts b/chrome/browser/resources/chromeos/cloud_upload/one_drive_upload_page.ts index c38dcdf8..12c0444 100644 --- a/chrome/browser/resources/chromeos/cloud_upload/one_drive_upload_page.ts +++ b/chrome/browser/resources/chromeos/cloud_upload/one_drive_upload_page.ts
@@ -61,7 +61,7 @@ } private onUploadButtonClick(): void { - this.proxy.handler.respondAndClose(UserAction.kUploadToOneDrive); + this.proxy.handler.respondAndClose(UserAction.kConfirmOrUploadToOneDrive); } private onCancelButtonClick(): void {
diff --git a/chrome/browser/resources/chromeos/drive_internals.html b/chrome/browser/resources/chromeos/drive_internals.html index ca6b2456..8ac22fe 100644 --- a/chrome/browser/resources/chromeos/drive_internals.html +++ b/chrome/browser/resources/chromeos/drive_internals.html
@@ -107,6 +107,14 @@ </table> </section> + <section id="bulk-pinning-section" hidden> + <h2>Bulk Pinning</h2> + <label> + Enable Bulk Pinning + <input type="checkbox" id="bulk-pinning-toggle"> + </label> + </section> + <section id="delta-update-status-section" hidden> <h2>Delta Update Status</h2> <table>
diff --git a/chrome/browser/resources/chromeos/drive_internals.js b/chrome/browser/resources/chromeos/drive_internals.js index ec9908e..e6ab44f 100644 --- a/chrome/browser/resources/chromeos/drive_internals.js +++ b/chrome/browser/resources/chromeos/drive_internals.js
@@ -100,6 +100,10 @@ $('mirroring-toggle').checked = enabled; } +function updateBulkPinning(enabled) { + $('bulk-pinning-toggle').checked = enabled; +} + function updateStartupArguments(args) { $('startup-arguments-input').value = args; } @@ -365,6 +369,10 @@ chrome.send('setMirroringEnabled', [e.target.checked]); }); + $('bulk-pinning-toggle').addEventListener('change', function(e) { + chrome.send('setBulkPinningEnabled', [e.target.checked]); + }); + $('startup-arguments-form').addEventListener('submit', function(e) { e.preventDefault(); $('arguments-status-text').textContent = 'applying...';
diff --git a/chrome/browser/resources/chromeos/login/BUILD.gn b/chrome/browser/resources/chromeos/login/BUILD.gn index 9f10a01..4cd118b 100644 --- a/chrome/browser/resources/chromeos/login/BUILD.gn +++ b/chrome/browser/resources/chromeos/login/BUILD.gn
@@ -215,7 +215,6 @@ "components/web_view_helper.m.js", "components/web_view_loader.m.js", "screens/common/family_link_notice.m.js", - "screens/common/guest_tos.m.js", "screens/common/hw_data_collection.m.js", "screens/common/smart_privacy_protection.m.js", "screens/common/sync_consent.m.js", @@ -271,6 +270,7 @@ "screens/common/fingerprint_setup.js", "screens/common/gaia_signin.js", "screens/common/gesture_navigation.js", + "screens/common/guest_tos.js", "screens/common/local_state_error.js", "screens/common/managed_terms_of_service.js", "screens/common/marketing_opt_in.js",
diff --git a/chrome/browser/resources/chromeos/login/screens.js b/chrome/browser/resources/chromeos/login/screens.js index aff3ace0..2c7c65b0c 100644 --- a/chrome/browser/resources/chromeos/login/screens.js +++ b/chrome/browser/resources/chromeos/login/screens.js
@@ -21,7 +21,7 @@ import './screens/common/fingerprint_setup.js'; import './screens/common/gaia_signin.js'; import './screens/common/gesture_navigation.js'; -import './screens/common/guest_tos.m.js'; +import './screens/common/guest_tos.js'; import './screens/common/hw_data_collection.m.js'; import './screens/common/local_state_error.js'; import './screens/common/managed_terms_of_service.js';
diff --git a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn index a180498..859bd12 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn +++ b/chrome/browser/resources/chromeos/login/screens/common/BUILD.gn
@@ -14,7 +14,6 @@ group("polymer3_elements") { public_deps = [ ":family_link_notice_module", - ":guest_tos_module", ":hw_data_collection_module", ":smart_privacy_protection_module", ":sync_consent_module", @@ -54,7 +53,7 @@ ":fingerprint_setup", ":gaia_signin", ":gesture_navigation", - ":guest_tos.m", + ":guest_tos", ":hw_data_collection.m", ":local_state_error", ":managed_terms_of_service", @@ -294,8 +293,8 @@ extra_deps = [ ":web_components" ] } -js_library("guest_tos.m") { - sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/common/guest_tos.m.js" ] +js_library("guest_tos") { + sources = [ "$root_gen_dir/chrome/browser/resources/chromeos/login/screens/common/guest_tos.js" ] deps = [ "../..:display_manager.m", "../../components:web_view_helper.m", @@ -311,7 +310,7 @@ "../../components/dialogs:oobe_modal_dialog.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", ] - extra_deps = [ ":guest_tos_module" ] + extra_deps = [ ":web_components" ] externs_list = [ "$externs_path/chrome_extensions.js", "$externs_path/webview_tag.js", @@ -685,15 +684,6 @@ namespace_rewrites = oobe_namespace_rewrites } -polymer_modulizer("guest_tos") { - js_file = "guest_tos.js" - html_file = "guest_tos.html" - html_type = "dom-module" - auto_imports = oobe_auto_imports - migrated_imports = oobe_migrated_imports - namespace_rewrites = oobe_namespace_rewrites -} - polymer_modulizer("hw_data_collection") { js_file = "hw_data_collection.js" html_file = "hw_data_collection.html" @@ -737,6 +727,7 @@ "fingerprint_setup.js", "gaia_signin.js", "gesture_navigation.js", + "guest_tos.js", "local_state_error.js", "managed_terms_of_service.js", "marketing_opt_in.js",
diff --git a/chrome/browser/resources/chromeos/login/screens/common/guest_tos.html b/chrome/browser/resources/chromeos/login/screens/common/guest_tos.html index 6aafcbb..67f8bef 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/guest_tos.html +++ b/chrome/browser/resources/chromeos/login/screens/common/guest_tos.html
@@ -4,143 +4,115 @@ found in the LICENSE file. --> -<link rel="import" href="chrome://resources/html/polymer.html"> +<style include="oobe-dialog-host-styles"> + #termsTitle { + color: var(--google-grey-900); + font-family: var(--oobe-header-font-family); + font-size: 18px; + font-weight: var(--oobe-header-font-weight); + line-height: 24px; + margin-bottom: 4px; + } -<link rel="import" href="chrome://resources/cr_elements/cr_shared_style.css.html"> -<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html"> -<link rel="import" href="chrome://resources/html/action_link.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> + .tos-webview { + display: flex; + height: 470px; + } +</style> -<link rel="import" href="../../components/behaviors/login_screen_behavior.html"> -<link rel="import" href="../../components/behaviors/multi_step_behavior.html"> -<link rel="import" href="../../components/behaviors/oobe_i18n_behavior.html"> -<link rel="import" href="../../components/buttons/oobe_back_button.html"> -<link rel="import" href="../../components/buttons/oobe_next_button.html"> -<link rel="import" href="../../components/buttons/oobe_text_button.html"> -<link rel="import" href="../../components/common_styles/common_styles.html"> -<link rel="import" href="../../components/common_styles/oobe_dialog_host_styles.html"> -<link rel="import" href="../../components/display_manager_types.html"> -<link rel="import" href="../../components/oobe_icons.html"> -<link rel="import" href="../../components/web_view_loader.html"> -<link rel="import" href="../../components/web_view_helper.html"> -<link rel="import" href="../../components/dialogs/oobe_adaptive_dialog.html"> -<link rel="import" href="../../components/dialogs/oobe_loading_dialog.html"> -<link rel="import" href="../../components/dialogs/oobe_modal_dialog.html"> +<!-- LOADING DIALOG --> +<oobe-loading-dialog id="loading" for-step="loading" role="dialog" + title-key="guestTosLoading" + aria-label$="[[i18nDynamic(locale, 'guestTosLoading')]]"> + <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> +</oobe-loading-dialog> -<dom-module id="guest-tos-element"> - <template> - <style include="oobe-dialog-host-styles"> - #termsTitle { - color: var(--google-grey-900); - font-family: var(--oobe-header-font-family); - font-size: 18px; - font-weight: var(--oobe-header-font-weight); - line-height: 24px; - margin-bottom: 4px; - } - - .tos-webview { - display: flex; - height: 470px; - } - </style> - - <!-- LOADING DIALOG --> - <oobe-loading-dialog id="loading" for-step="loading" role="dialog" - title-key="guestTosLoading" - aria-label$="[[i18nDynamic(locale, 'guestTosLoading')]]"> - <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> - </oobe-loading-dialog> - - <!-- Google EULA Dialog --> - <oobe-adaptive-dialog id="googleEulaDialog" for-step="google-eula" - role="dialog" - aria-label$="[[i18nDynamic(locale, 'guestTosGoogleEulaTitle')]]"> - <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> - <h1 slot="title"> - [[i18nDynamic(locale, 'guestTosGoogleEulaTitle')]] - </h1> - <div slot="content" class="flex layout vertical"> - <webview id="guestTosGoogleEulaWebview" role="document" - class="oobe-tos-webview tos-webview" - on-contentload="onGoogleEulaContentLoad_"> - </webview> - </div> - <div slot="bottom-buttons"> - <oobe-text-button id="googleEulaOkButton" - class="focus-on-show" inverse on-click="onTermsStepOkClick_" - text-key="guestTosOk"></oobe-text-button> - </div> - </oobe-adaptive-dialog> - - <!-- CrOS EULA Dialog --> - <oobe-adaptive-dialog id="crosEulaDialog" for-step="cros-eula" +<!-- Google EULA Dialog --> +<oobe-adaptive-dialog id="googleEulaDialog" for-step="google-eula" role="dialog" - aria-label$="[[i18nDynamic(locale, 'guestTosCrosEulaTitle')]]"> - <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> - <h1 slot="title"> - [[i18nDynamic(locale, 'guestTosCrosEulaTitle')]] - </h1> - <div slot="content" class="flex layout vertical"> - <webview id="guestTosCrosEulaWebview" role="document" - class="oobe-tos-webview tos-webview"> - </webview> - </div> - <div slot="bottom-buttons"> - <oobe-text-button id="crosEulaOkButton" - class="focus-on-show" inverse on-click="onTermsStepOkClick_" - text-key="guestTosOk"></oobe-text-button> - </div> - </oobe-adaptive-dialog> + aria-label$="[[i18nDynamic(locale, 'guestTosGoogleEulaTitle')]]"> + <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> + <h1 slot="title"> + [[i18nDynamic(locale, 'guestTosGoogleEulaTitle')]] + </h1> + <div slot="content" class="flex layout vertical"> + <webview id="guestTosGoogleEulaWebview" role="document" + class="oobe-tos-webview tos-webview" + on-contentload="onGoogleEulaContentLoad_"> + </webview> + </div> + <div slot="bottom-buttons"> + <oobe-text-button id="googleEulaOkButton" + class="focus-on-show" inverse on-click="onTermsStepOkClick_" + text-key="guestTosOk"></oobe-text-button> + </div> +</oobe-adaptive-dialog> - <!-- Loaded Dialog --> - <oobe-adaptive-dialog id="loaded" for-step="loaded" role="dialog" - aria-label$="[[i18nDynamic(locale, 'guestTosTitle')]]"> - <iron-icon slot="icon" icon="oobe-32:avatar"></iron-icon> - <h1 slot="title"> - [[i18nDynamic(locale, 'guestTosTitle')]] - </h1> - <div slot="content" class="landscape-header-aligned"> - <div id="termsTitle"> - [[i18nDynamic(locale, 'guestTosTermsTitle')]] - </div> - <div id="terms"> - <div inner-h-t-m-l="[[getTerms_(locale)]]"> - </div> - </div> +<!-- CrOS EULA Dialog --> +<oobe-adaptive-dialog id="crosEulaDialog" for-step="cros-eula" +role="dialog" +aria-label$="[[i18nDynamic(locale, 'guestTosCrosEulaTitle')]]"> + <iron-icon slot="icon" icon="oobe-32:googleg"></iron-icon> + <h1 slot="title"> + [[i18nDynamic(locale, 'guestTosCrosEulaTitle')]] + </h1> + <div slot="content" class="flex layout vertical"> + <webview id="guestTosCrosEulaWebview" role="document" + class="oobe-tos-webview tos-webview"> + </webview> + </div> + <div slot="bottom-buttons"> + <oobe-text-button id="crosEulaOkButton" + class="focus-on-show" inverse on-click="onTermsStepOkClick_" + text-key="guestTosOk"></oobe-text-button> + </div> +</oobe-adaptive-dialog> - <!-- Usage stats toggle row --> - <div id="usageStats" class="layout horizontal center oobe-optin-row"> - <div class="oobe-optin-content"> - <span id="usageTitle" class="oobe-optin-title"> - [[i18nDynamic(locale, 'guestTosUsageOptinTitle')]] - </span> - [[i18nDynamic(locale, 'guestTosUsageOptin')]] - <a id="usageLearnMore" on-click="onUsageLearnMoreClick_" - class="oobe-local-link" is="action-link"> - [[i18nDynamic(locale, 'guestTosLearnMore')]] - </a> - </div> - <cr-toggle id="usageOptin" checked="{{usageChecked}}" - aria-describedby="usageTitle"> - </cr-toggle> - </div> +<!-- Loaded Dialog --> +<oobe-adaptive-dialog id="loaded" for-step="loaded" role="dialog" +aria-label$="[[i18nDynamic(locale, 'guestTosTitle')]]"> + <iron-icon slot="icon" icon="oobe-32:avatar"></iron-icon> + <h1 slot="title"> + [[i18nDynamic(locale, 'guestTosTitle')]] + </h1> + <div slot="content" class="landscape-header-aligned"> + <div id="termsTitle"> + [[i18nDynamic(locale, 'guestTosTermsTitle')]] + </div> + <div id="terms"> + <div inner-h-t-m-l="[[getTerms_(locale)]]"> </div> - <div slot="back-navigation"> - <oobe-back-button on-click="onBackClick_"></oobe-back-button> - </div> - <div slot="bottom-buttons"> - <oobe-next-button id="acceptButton" inverse on-click="onAcceptClick_" - text-key="guestTosAccept" class="focus-on-show"> - </oobe-next-button> - </div> - </oobe-adaptive-dialog> + </div> - <oobe-modal-dialog id="usageLearnMorePopUp"> - <div slot="content"> - <span inner-h-t-m-l="[[getUsageLearnMoreText_(locale)]]"></span> + <!-- Usage stats toggle row --> + <div id="usageStats" class="layout horizontal center oobe-optin-row"> + <div class="oobe-optin-content"> + <span id="usageTitle" class="oobe-optin-title"> + [[i18nDynamic(locale, 'guestTosUsageOptinTitle')]] + </span> + [[i18nDynamic(locale, 'guestTosUsageOptin')]] + <a id="usageLearnMore" on-click="onUsageLearnMoreClick_" + class="oobe-local-link" is="action-link"> + [[i18nDynamic(locale, 'guestTosLearnMore')]] + </a> </div> - </oobe-modal-dialog> - </template> - <script src="guest_tos.js"></script> -</dom-module> + <cr-toggle id="usageOptin" checked="{{usageChecked}}" + aria-describedby="usageTitle"> + </cr-toggle> + </div> + </div> + <div slot="back-navigation"> + <oobe-back-button on-click="onBackClick_"></oobe-back-button> + </div> + <div slot="bottom-buttons"> + <oobe-next-button id="acceptButton" inverse on-click="onAcceptClick_" + text-key="guestTosAccept" class="focus-on-show"> + </oobe-next-button> + </div> +</oobe-adaptive-dialog> + +<oobe-modal-dialog id="usageLearnMorePopUp"> + <div slot="content"> + <span inner-h-t-m-l="[[getUsageLearnMoreText_(locale)]]"></span> + </div> +</oobe-modal-dialog>
diff --git a/chrome/browser/resources/chromeos/login/screens/common/guest_tos.js b/chrome/browser/resources/chromeos/login/screens/common/guest_tos.js index b5c5971..4ae84b1e 100644 --- a/chrome/browser/resources/chromeos/login/screens/common/guest_tos.js +++ b/chrome/browser/resources/chromeos/login/screens/common/guest_tos.js
@@ -6,7 +6,29 @@ * @fileoverview guest tos screen implementation. */ -/* #js_imports_placeholder */ +import '//resources/cr_elements/cr_shared_style.css.js'; +import '//resources/cr_elements/cr_toggle/cr_toggle.js'; +import '//resources/js/action_link.js'; +import '//resources/polymer/v3_0/iron-icon/iron-icon.js'; +import '../../components/common_styles/common_styles.m.js'; +import '../../components/common_styles/oobe_dialog_host_styles.m.js'; +import '../../components/oobe_icons.m.js'; +import '../../components/dialogs/oobe_loading_dialog.m.js'; +import '../../components/dialogs/oobe_modal_dialog.m.js'; + +import {html, mixinBehaviors, Polymer, PolymerElement} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {LoginScreenBehavior, LoginScreenBehaviorInterface} from '../../components/behaviors/login_screen_behavior.m.js'; +import {MultiStepBehavior, MultiStepBehaviorInterface} from '../../components/behaviors/multi_step_behavior.m.js'; +import {OobeI18nBehavior, OobeI18nBehaviorInterface} from '../../components/behaviors/oobe_i18n_behavior.m.js'; +import {OobeBackButton} from '../../components/buttons/oobe_back_button.js'; +import {OobeNextButton} from '../../components/buttons/oobe_next_button.js'; +import {OobeTextButton} from '../../components/buttons/oobe_text_button.js'; +import {OobeAdaptiveDialog} from '../../components/dialogs/oobe_adaptive_dialog.js'; +import {OOBE_UI_STATE} from '../../components/display_manager_types.m.js'; +import {WebViewHelper} from '../../components/web_view_helper.m.js'; +import {WebViewLoader} from '../../components/web_view_loader.m.js'; + // Enum that describes the current state of the Guest ToS screen const GuestTosScreenState = { @@ -35,9 +57,8 @@ * @implements {OobeI18nBehaviorInterface} * @implements {MultiStepBehaviorInterface} */ -const GuestTosScreenElementBase = Polymer.mixinBehaviors( - [OobeI18nBehavior, MultiStepBehavior, LoginScreenBehavior], - Polymer.Element); +const GuestTosScreenElementBase = mixinBehaviors( + [OobeI18nBehavior, MultiStepBehavior, LoginScreenBehavior], PolymerElement); /** * @polymer @@ -47,7 +68,9 @@ return 'guest-tos-element'; } - /* #html_template_placeholder */ + static get template() { + return html`{__html_template__}`; + } static get properties() { return { @@ -58,11 +81,6 @@ }; } - constructor() { - super(); - this.usageChecked = true; - } - /** @override */ defaultUIStep() { return GuestTosScreenState.LOADING;
diff --git a/chrome/browser/resources/downloads/BUILD.gn b/chrome/browser/resources/downloads/BUILD.gn index a806dad5..c701a409 100644 --- a/chrome/browser/resources/downloads/BUILD.gn +++ b/chrome/browser/resources/downloads/BUILD.gn
@@ -34,8 +34,10 @@ icons_html_files = [ "icons.html" ] mojo_files_deps = - [ "//chrome/browser/ui/webui/downloads:mojo_bindings_js__generator" ] - mojo_files = [ "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/downloads/downloads.mojom-webui.js" ] + [ "//chrome/browser/ui/webui/downloads:mojo_bindings_ts__generator" ] + mojo_files = [ + "$root_gen_dir/chrome/browser/ui/webui/downloads/downloads.mojom-webui.ts", + ] ts_composite = true ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
diff --git a/chrome/browser/resources/downloads/data.ts b/chrome/browser/resources/downloads/data.ts index a16da6f..90ee91d 100644 --- a/chrome/browser/resources/downloads/data.ts +++ b/chrome/browser/resources/downloads/data.ts
@@ -9,6 +9,6 @@ import {Data} from './downloads.mojom-webui.js'; -export class MojomData extends Data { +export interface MojomData extends Data { hideDate: boolean; }
diff --git a/chrome/browser/resources/downloads/tsconfig_base.json b/chrome/browser/resources/downloads/tsconfig_base.json index 3e71f763..afa0731 100644 --- a/chrome/browser/resources/downloads/tsconfig_base.json +++ b/chrome/browser/resources/downloads/tsconfig_base.json
@@ -1,7 +1,6 @@ { "extends": "../../../../tools/typescript/tsconfig_base.json", "compilerOptions": { - "allowJs": true, "noUncheckedIndexedAccess": false, "noUnusedLocals": false, "strictPropertyInitialization": false
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.html b/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.html index f3025e35..710b458 100644 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.html +++ b/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.html
@@ -4,7 +4,7 @@ icon-status="[[iconStatus_]]" label="[[headerString_]]" button-label="$i18n{safetyCheckReview}" - button-aria-label="[[buttonAriaLabel_]]" + button-aria-label="$i18n{safetyCheckNotificationPermissionReviewButtonAriaLabel}" on-button-click="onButtonClick_" role="presentation" class="two-line">
diff --git a/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.ts b/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.ts index 36878e3..9a01dde 100644 --- a/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.ts +++ b/chrome/browser/resources/settings/safety_check_page/safety_check_notification_permissions.ts
@@ -50,35 +50,25 @@ }, }, - sites_: { - type: Array, - observer: 'onSitesChanged_', - }, - headerString_: String, - - buttonAriaLabel_: String, }; } private iconStatus_: SafetyCheckIconStatus; private headerString_: string; - private buttonAriaLabel_: string; - private sites_: NotificationPermission[] = []; private siteSettingsBrowserProxy_: SiteSettingsPrefsBrowserProxy = SiteSettingsPrefsBrowserProxyImpl.getInstance(); - override async connectedCallback() { + override connectedCallback() { super.connectedCallback(); // Register for review notification permission list updates. this.addWebUIListener( 'notification-permission-review-list-maybe-changed', - (sites: NotificationPermission[]) => - this.onReviewNotificationPermissionListChanged_(sites)); + (sites: NotificationPermission[]) => this.onSitesChanged_(sites)); - this.sites_ = - await this.siteSettingsBrowserProxy_.getNotificationPermissionReview(); + this.siteSettingsBrowserProxy_.getNotificationPermissionReview().then( + this.onSitesChanged_.bind(this)); } private onButtonClick_() { @@ -87,20 +77,10 @@ /* removeSearch= */ true); } - private async onReviewNotificationPermissionListChanged_( - sites: NotificationPermission[]) { - this.sites_ = sites; - } - - private async onSitesChanged_() { + private async onSitesChanged_(sites: NotificationPermission[]) { this.headerString_ = await PluralStringProxyImpl.getInstance().getPluralString( - 'safetyCheckNotificationPermissionReviewHeaderLabel', - this.sites_.length); - this.buttonAriaLabel_ = - await PluralStringProxyImpl.getInstance().getPluralString( - 'safetyCheckNotificationPermissionReviewPrimaryLabel', - this.sites_!.length); + 'safetyCheckNotificationPermissionReviewHeaderLabel', sites.length); } }
diff --git a/chrome/browser/resources/settings/site_settings/review_notification_permissions.html b/chrome/browser/resources/settings/site_settings/review_notification_permissions.html index 89a50e5..00712aa 100644 --- a/chrome/browser/resources/settings/site_settings/review_notification_permissions.html +++ b/chrome/browser/resources/settings/site_settings/review_notification_permissions.html
@@ -29,6 +29,7 @@ } .header-group-wrapper { + flex: 1; margin-inline-start: 15px; } @@ -113,12 +114,12 @@ <template is="dom-if" if="[[!shouldShowCompletionInfo_]]"> <div id="review-header" class="header-with-icon"> <iron-icon role="img" icon="settings:notifications-none"></iron-icon> - <cr-expand-button id="expandButton" class="header-group-wrapper" no-hover - expanded="{{notificationPermissionReviewListExpanded_}}"> + <div class="header-group-wrapper"> <h2>[[headerString_]]</h2> - <div class="secondary"> - $i18n{safetyCheckNotificationPermissionReviewSecondaryLabel} - </div> + <div class="secondary">[[subtitleString_]]</div> + </div> + <cr-expand-button id="expandButton" no-hover + expanded="{{notificationPermissionReviewListExpanded_}}"> </cr-expand-button> </div> <iron-collapse class="notification-permissions-list" @@ -168,7 +169,7 @@ </template> <cr-toast id="undoToast" duration="5000"> <div id="undoNotification">[[toastText_]]</div> - <cr-button aria-label="$i18n{safetyCheckNotificationPermissionReviewUndo}" + <cr-button aria-label="$i18n{safetyCheckNotificationPermissionReviewUndo}" on-click="onUndoButtonClick_"> $i18n{safetyCheckNotificationPermissionReviewUndo} </cr-button>
diff --git a/chrome/browser/resources/settings/site_settings/review_notification_permissions.ts b/chrome/browser/resources/settings/site_settings/review_notification_permissions.ts index bc071117..b186371 100644 --- a/chrome/browser/resources/settings/site_settings/review_notification_permissions.ts +++ b/chrome/browser/resources/settings/site_settings/review_notification_permissions.ts
@@ -102,6 +102,9 @@ /* The string for the primary header label. */ headerString_: String, + /* The string for the subtitle. */ + subtitleString_: String, + /** * The text that will be shown in the toast element upon clicking one of * the actions. @@ -113,18 +116,19 @@ private sites_: NotificationPermission[]; private notificationPermissionReviewListExpanded_: boolean; private shouldShowCompletionInfo_: boolean; - private browserProxy_: SiteSettingsPrefsBrowserProxy = - SiteSettingsPrefsBrowserProxyImpl.getInstance(); private lastOrigins_: string[] = []; private lastUserAction_: Actions|null; private headerString_: string; + private subtitleString_: string; private sitesLoaded_: boolean = false; private modelUpdateDelayMsForTesting_: number|null = null; private toastText_: string|null; + private eventTracker_: EventTracker = new EventTracker(); + private shouldRefocusExpandButton_: boolean = false; + private browserProxy_: SiteSettingsPrefsBrowserProxy = + SiteSettingsPrefsBrowserProxyImpl.getInstance(); private metricsBrowserProxy_: MetricsBrowserProxy = MetricsBrowserProxyImpl.getInstance(); - private shouldRefocusExpandButton_: boolean = false; - private eventTracker_: EventTracker = new EventTracker(); override async connectedCallback() { super.connectedCallback(); @@ -427,6 +431,10 @@ await PluralStringProxyImpl.getInstance().getPluralString( 'safetyCheckNotificationPermissionReviewPrimaryLabel', this.sites_.length); + this.subtitleString_ = + await PluralStringProxyImpl.getInstance().getPluralString( + 'safetyCheckNotificationPermissionReviewSecondaryLabel', + this.sites_.length); /** * Focus on the expand button after the undo button is clicked and sites are * loaded again.
diff --git a/chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate.cc b/chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate.cc index 1761775..269e3b8 100644 --- a/chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate.cc +++ b/chrome/browser/safe_browsing/chrome_client_side_detection_host_delegate.cc
@@ -21,6 +21,7 @@ #include "components/safe_browsing/core/browser/db/database_manager.h" #include "components/safe_browsing/core/browser/sync/safe_browsing_primary_account_token_fetcher.h" #include "components/safe_browsing/core/browser/sync/sync_utils.h" +#include "components/signin/public/identity_manager/identity_manager.h" #include "content/public/browser/global_routing_id.h" namespace safe_browsing {
diff --git a/chrome/browser/sharesheet/sharesheet_service.cc b/chrome/browser/sharesheet/sharesheet_service.cc index 9e82405..a78557f 100644 --- a/chrome/browser/sharesheet/sharesheet_service.cc +++ b/chrome/browser/sharesheet/sharesheet_service.cc
@@ -128,6 +128,10 @@ std::move(action_cleanup_callback)); SharesheetMetrics::RecordSharesheetLaunchSource(source); + if (!native_window) { + std::move(delivered_callback).Run(SharesheetResult::kErrorWindowClosed); + return; + } auto* sharesheet_service_delegator = GetOrCreateDelegator(native_window); sharesheet_service_delegator->ShowNearbyShareBubbleForArc( std::move(intent), std::move(delivered_callback),
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_fetcher.cc b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_fetcher.cc new file mode 100644 index 0000000..3d2862e --- /dev/null +++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_fetcher.cc
@@ -0,0 +1,80 @@ +// 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/signin/bound_session_credentials/bound_session_cookie_fetcher.h" + +#include "base/callback.h" +#include "base/task/sequenced_task_runner.h" +#include "base/time/time.h" +#include "components/signin/public/base/signin_client.h" +#include "google_apis/gaia/gaia_urls.h" +#include "mojo/public/cpp/bindings/callback_helpers.h" +#include "net/cookies/canonical_cookie.h" +#include "services/network/public/mojom/cookie_manager.mojom.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +BoundSessionCookieFetcher::BoundSessionCookieFetcher( + SigninClient* client, + SetCookieCompleteCallback callback) + : client_(client), callback_(std::move(callback)) { + constexpr base::TimeDelta kFakeNetworkRequestEquivalentDelay( + base::Milliseconds(100)); + base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&BoundSessionCookieFetcher::StartSettingCookie, + weak_ptr_factory_.GetWeakPtr()), + kFakeNetworkRequestEquivalentDelay); +} + +void BoundSessionCookieFetcher::StartSettingCookie() { + constexpr char kSIDTSCookieName[] = "__Secure-1PSIDTS"; + constexpr char kFakeCookieValue[] = "FakeCookieValue"; + const base::TimeDelta kMaxAge = base::Minutes(10); + + base::Time now = base::Time::Now(); + base::Time expiration = now + kMaxAge; + GURL google_url = GaiaUrls::GetInstance()->secure_google_url(); + + // Create fake SIDTS cookie until the server endpoint is available. + std::unique_ptr<net::CanonicalCookie> new_cookie = + net::CanonicalCookie::CreateSanitizedCookie( + /*url=*/google_url, /*name=*/kSIDTSCookieName, + /*value=*/kFakeCookieValue, + /*domain=*/google_url.host(), /*path=*/"/", + /*creation_time=*/now, /*expiration_time=*/expiration, + /*last_access_time=*/now, /*secure=*/true, + /*http_only=*/true, net::CookieSameSite::UNSPECIFIED, + net::CookiePriority::COOKIE_PRIORITY_HIGH, + /*same_party=*/true, /*partition_key=*/absl::nullopt); + + DCHECK(new_cookie); + base::OnceCallback<void(net::CookieAccessResult)> callback = + base::BindOnce(&BoundSessionCookieFetcher::OnCookieSet, + weak_ptr_factory_.GetWeakPtr(), new_cookie->ExpiryDate()); + net::CookieOptions options; + options.set_include_httponly(); + // Permit it to set a SameSite cookie if it wants to. + options.set_same_site_cookie_context( + net::CookieOptions::SameSiteCookieContext::MakeInclusive()); + client_->GetCookieManager()->SetCanonicalCookie( + *new_cookie, google_url, options, + mojo::WrapCallbackWithDefaultInvokeIfNotRun( + std::move(callback), + net::CookieAccessResult(net::CookieInclusionStatus( + net::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)))); +} + +void BoundSessionCookieFetcher::OnCookieSet( + const base::Time& expiry_date, + net::CookieAccessResult access_result) { + bool success = access_result.status.IsInclude(); + if (!success) { + std::move(callback_).Run(absl::nullopt); + } else { + std::move(callback_).Run(expiry_date); + } + // |This| may be destroyed +} + +BoundSessionCookieFetcher::~BoundSessionCookieFetcher() = default;
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_fetcher.h b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_fetcher.h new file mode 100644 index 0000000..029e34a --- /dev/null +++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_fetcher.h
@@ -0,0 +1,36 @@ +// 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_SIGNIN_BOUND_SESSION_CREDENTIALS_BOUND_SESSION_COOKIE_FETCHER_H_ +#define CHROME_BROWSER_SIGNIN_BOUND_SESSION_CREDENTIALS_BOUND_SESSION_COOKIE_FETCHER_H_ + +#include "base/callback.h" +#include "base/memory/raw_ptr.h" +#include "base/time/time.h" +#include "net/cookies/canonical_cookie.h" +#include "third_party/abseil-cpp/absl/types/optional.h" + +class SigninClient; + +class BoundSessionCookieFetcher { + public: + // Returns the expected expiration date of the cookie. This is optional as + // set cookie might fail. + using SetCookieCompleteCallback = + base::OnceCallback<void(absl::optional<const base::Time>)>; + + BoundSessionCookieFetcher(SigninClient* client, + SetCookieCompleteCallback callback); + ~BoundSessionCookieFetcher(); + + private: + void StartSettingCookie(); + void OnCookieSet(const base::Time& expiry_date, + net::CookieAccessResult access_result); + + const raw_ptr<SigninClient> client_; + SetCookieCompleteCallback callback_; + base::WeakPtrFactory<BoundSessionCookieFetcher> weak_ptr_factory_{this}; +}; +#endif // CHROME_BROWSER_SIGNIN_BOUND_SESSION_CREDENTIALS_BOUND_SESSION_COOKIE_FETCHER_H_
diff --git a/chrome/browser/signin/bound_session_credentials/bound_session_cookie_fetcher_unittest.cc b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_fetcher_unittest.cc new file mode 100644 index 0000000..fb5c119e --- /dev/null +++ b/chrome/browser/signin/bound_session_credentials/bound_session_cookie_fetcher_unittest.cc
@@ -0,0 +1,90 @@ +// 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/signin/bound_session_credentials/bound_session_cookie_fetcher.h" + +#include "base/run_loop.h" +#include "base/test/task_environment.h" +#include "base/time/time.h" +#include "components/signin/public/base/test_signin_client.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" +#include "net/cookies/canonical_cookie.h" +#include "net/cookies/cookie_access_result.h" +#include "services/network/test/test_cookie_manager.h" +#include "testing/gtest/include/gtest/gtest.h" + +class FakeCookieManager : public network::TestCookieManager { + public: + void SetCanonicalCookie(const net::CanonicalCookie& cookie, + const GURL& source_url, + const net::CookieOptions& cookie_options, + SetCanonicalCookieCallback callback) override { + cookie_ = cookie; + if (callback) { + std::move(callback).Run(net::CookieAccessResult()); + } + } + + net::CanonicalCookie& cookie() { return cookie_; } + + private: + net::CanonicalCookie cookie_; +}; + +class BoundSessionCookieFetcherTest : public testing::Test { + public: + BoundSessionCookieFetcherTest() + : task_environment_( + base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME) { + std::unique_ptr<FakeCookieManager> fake_cookie_manager = + std::make_unique<FakeCookieManager>(); + cookie_manager_ = fake_cookie_manager.get(); + signin_client_.set_cookie_manager(std::move(fake_cookie_manager)); + } + + ~BoundSessionCookieFetcherTest() override = default; + + void InitializeFetcher(base::OnceClosure on_done) { + fetcher_ = std::make_unique<BoundSessionCookieFetcher>( + &signin_client_, + base::BindOnce(&BoundSessionCookieFetcherTest::OnCookieSet, + base::Unretained(this), std::move(on_done))); + } + + void OnCookieSet(base::OnceClosure on_done, + absl::optional<const base::Time> result) { + expected_expiry_date_ = result.value_or(base::Time()); + std::move(on_done).Run(); + } + + void VerifyCookie() { + EXPECT_TRUE(cookie_manager_); + constexpr char kSIDTSCookieName[] = "__Secure-1PSIDTS"; + constexpr char kFakeCookieValue[] = "FakeCookieValue"; + + net::CanonicalCookie& cookie = cookie_manager_->cookie(); + EXPECT_TRUE(cookie.IsCanonical()); + EXPECT_EQ(cookie.ExpiryDate(), expected_expiry_date_); + EXPECT_EQ(cookie.Domain(), ".google.com"); + EXPECT_EQ(cookie.Name(), kSIDTSCookieName); + EXPECT_EQ(cookie.Value(), kFakeCookieValue); + EXPECT_TRUE(cookie.IsExpired(base::Time::Now() + base::Minutes(10))); + } + + protected: + base::test::SingleThreadTaskEnvironment task_environment_; + base::Time expected_expiry_date_; + std::unique_ptr<BoundSessionCookieFetcher> fetcher_; + sync_preferences::TestingPrefServiceSyncable prefs_; + TestSigninClient signin_client_{&prefs_}; + FakeCookieManager* cookie_manager_ = nullptr; +}; + +TEST_F(BoundSessionCookieFetcherTest, SetSIDTSCookie) { + base::RunLoop run_loop; + InitializeFetcher(run_loop.QuitClosure()); + task_environment_.FastForwardBy(base::Milliseconds(100)); + run_loop.Run(); + VerifyCookie(); +}
diff --git a/chrome/browser/signin/dice_tab_helper_unittest.cc b/chrome/browser/signin/dice_tab_helper_unittest.cc index 33dcee7..a788f3a 100644 --- a/chrome/browser/signin/dice_tab_helper_unittest.cc +++ b/chrome/browser/signin/dice_tab_helper_unittest.cc
@@ -217,11 +217,10 @@ class DiceTabHelperPrerenderTest : public DiceTabHelperTest { public: DiceTabHelperPrerenderTest() { - feature_list_.InitWithFeatures( - {blink::features::kPrerender2}, + feature_list_.InitAndDisableFeature( // Disable the memory requirement of Prerender2 so the test can run on // any bot. - {blink::features::kPrerender2MemoryControls}); + blink::features::kPrerender2MemoryControls); } ~DiceTabHelperPrerenderTest() override = default;
diff --git a/chrome/browser/signin/reauth_tab_helper_unittest.cc b/chrome/browser/signin/reauth_tab_helper_unittest.cc index db77189..00191ec 100644 --- a/chrome/browser/signin/reauth_tab_helper_unittest.cc +++ b/chrome/browser/signin/reauth_tab_helper_unittest.cc
@@ -154,11 +154,10 @@ class ReauthTabHelperPrerenderTest : public ReauthTabHelperTest { public: ReauthTabHelperPrerenderTest() { - feature_list_.InitWithFeatures( - {blink::features::kPrerender2}, + feature_list_.InitAndDisableFeature( // Disable the memory requirement of Prerender2 so the test can run on // any bot. - {blink::features::kPrerender2MemoryControls}); + blink::features::kPrerender2MemoryControls); } private:
diff --git a/chrome/browser/site_isolation/site_details_browsertest.cc b/chrome/browser/site_isolation/site_details_browsertest.cc index 7faeeef..f03f2c6 100644 --- a/chrome/browser/site_isolation/site_details_browsertest.cc +++ b/chrome/browser/site_isolation/site_details_browsertest.cc
@@ -819,9 +819,7 @@ PrerenderSiteDetailsBrowserTest() : prerender_helper_( base::BindRepeating(&PrerenderSiteDetailsBrowserTest::web_contents, - base::Unretained(this))) { - feature_list_.InitAndEnableFeature(blink::features::kPrerender2); - } + base::Unretained(this))) {} ~PrerenderSiteDetailsBrowserTest() override = default; PrerenderSiteDetailsBrowserTest(const PrerenderSiteDetailsBrowserTest&) = @@ -842,9 +840,6 @@ return browser()->tab_strip_model()->GetActiveWebContents(); } content::test::PrerenderTestHelper prerender_helper_; - - private: - base::test::ScopedFeatureList feature_list_; }; IN_PROC_BROWSER_TEST_F(PrerenderSiteDetailsBrowserTest,
diff --git a/chrome/browser/sync/sync_encryption_keys_tab_helper_unittest.cc b/chrome/browser/sync/sync_encryption_keys_tab_helper_unittest.cc index 100c6fd..5d3b65f 100644 --- a/chrome/browser/sync/sync_encryption_keys_tab_helper_unittest.cc +++ b/chrome/browser/sync/sync_encryption_keys_tab_helper_unittest.cc
@@ -161,11 +161,10 @@ : public SyncEncryptionKeysTabHelperTest { public: SyncEncryptionKeysTabHelperPrerenderingTest() { - scoped_feature_list_.InitWithFeatures( - {blink::features::kPrerender2}, + scoped_feature_list_.InitAndDisableFeature( // Disable the memory requirement of Prerender2 so the test can run on // any bot. - {blink::features::kPrerender2MemoryControls}); + blink::features::kPrerender2MemoryControls); } ~SyncEncryptionKeysTabHelperPrerenderingTest() override = default;
diff --git a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java index be61137..681f59a 100644 --- a/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java +++ b/chrome/browser/touch_to_fill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewBinder.java
@@ -35,7 +35,6 @@ import androidx.appcompat.content.res.AppCompatResources; -import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.password_manager.PasswordManagerResourceProviderFactory; import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.FaviconOrFallback; import org.chromium.chrome.browser.touch_to_fill.TouchToFillProperties.ItemType; @@ -237,22 +236,14 @@ }); } else if (propertyKey == SHOW_SUBMIT_BUTTON) { TextView buttonTitleText = view.findViewById(R.id.touch_to_fill_button_title); - if (ChromeFeatureList.isEnabled(ChromeFeatureList.TOUCH_TO_FILL_PASSWORD_SUBMISSION)) { - buttonTitleText.setText(view.getContext().getString(model.get(SHOW_SUBMIT_BUTTON) - ? R.string.touch_to_fill_signin - : R.string.touch_to_fill_continue)); - } else { - buttonTitleText.setText(R.string.touch_to_fill_continue); - } + buttonTitleText.setText(view.getContext().getString(model.get(SHOW_SUBMIT_BUTTON) + ? R.string.touch_to_fill_signin + : R.string.touch_to_fill_continue)); } else if (propertyKey == SHOW_WEBAUTHN_SUBMIT_BUTTON) { TextView buttonTitleText = view.findViewById(R.id.touch_to_fill_button_title); - if (ChromeFeatureList.isEnabled(ChromeFeatureList.TOUCH_TO_FILL_PASSWORD_SUBMISSION)) { - buttonTitleText.setText(view.getContext().getString( - model.get(SHOW_WEBAUTHN_SUBMIT_BUTTON) ? R.string.touch_to_fill_signin - : R.string.touch_to_fill_continue)); - } else { - buttonTitleText.setText(R.string.touch_to_fill_continue); - } + buttonTitleText.setText(view.getContext().getString( + model.get(SHOW_WEBAUTHN_SUBMIT_BUTTON) ? R.string.touch_to_fill_signin + : R.string.touch_to_fill_continue)); } else if (propertyKey == FAVICON_OR_FALLBACK || propertyKey == FORMATTED_ORIGIN || propertyKey == CREDENTIAL || propertyKey == WEBAUTHN_CREDENTIAL || propertyKey == WEBAUTHN_FAVICON_OR_FALLBACK) { @@ -270,7 +261,6 @@ */ private static String getSubtitle(PropertyModel model, Context context) { if (model.get(SHOW_SUBMIT_SUBTITLE)) { - assert ChromeFeatureList.isEnabled(ChromeFeatureList.TOUCH_TO_FILL_PASSWORD_SUBMISSION); return String.format( context.getString(model.get(ORIGIN_SECURE) ? R.string.touch_to_fill_sheet_subtitle_submission
diff --git a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java index b4fb53259..bffb304 100644 --- a/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java +++ b/chrome/browser/touch_to_fill/android/javatests/src/org/chromium/chrome/browser/touch_to_fill/TouchToFillViewTest.java
@@ -376,9 +376,11 @@ @Test @MediumTest public void testButtonTitleWithoutAutoSubmission() { + final boolean showSubmitButton = false; TestThreadUtils.runOnUiThreadBlocking(() -> { mModel.get(SHEET_ITEMS) - .addAll(asList(buildCredentialItem(ANA), buildConfirmationButton(ANA, false))); + .addAll(asList(buildCredentialItem(ANA), + buildConfirmationButton(ANA, showSubmitButton))); mModel.set(VISIBLE, true); }); BottomSheetTestSupport.waitForOpen(mBottomSheetController);
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/BUILD.gn b/chrome/browser/touch_to_fill/payments/android/internal/BUILD.gn index 3e3eff5..da4bf5d 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/BUILD.gn +++ b/chrome/browser/touch_to_fill/payments/android/internal/BUILD.gn
@@ -42,3 +42,48 @@ "java/res/values/dimens.xml", ] } + +robolectric_library("junit") { + testonly = true + + sources = [ "java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerRobolectricTest.java" ] + + deps = [ + ":java", + "//base:base_java", + "//base:base_java_test_support", + "//base:base_junit_test_support", + "//chrome/browser/touch_to_fill/payments/android:public_java", + "//chrome/test/android:chrome_java_unit_test_support", + "//components/browser_ui/bottomsheet/android:java", + "//third_party/junit", + "//third_party/mockito:mockito_java", + "//ui/android:ui_java_test_support", + "//ui/android:ui_no_recycler_view_java", + ] +} + +android_library("javatests") { + testonly = true + + sources = [ "java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewTest.java" ] + + deps = [ + ":java", + "//base:base_java", + "//base:base_java_test_support", + "//chrome/android:chrome_java", + "//chrome/browser/flags:java", + "//chrome/browser/touch_to_fill/payments/android:public_java", + "//chrome/test/android:chrome_java_integration_test_support", + "//components/browser_ui/bottomsheet/android:java", + "//components/browser_ui/bottomsheet/android/test:java", + "//content/public/test/android:content_java_test_support", + "//third_party/android_deps:espresso_java", + "//third_party/androidx:androidx_test_runner_java", + "//third_party/hamcrest:hamcrest_library_java", + "//third_party/junit:junit", + "//third_party/mockito:mockito_java", + "//ui/android:ui_no_recycler_view_java", + ] +}
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/res/layout/touch_to_fill_credit_card_sheet.xml b/chrome/browser/touch_to_fill/payments/android/internal/java/res/layout/touch_to_fill_credit_card_sheet.xml index 2c4bd68..c6779a24 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/res/layout/touch_to_fill_credit_card_sheet.xml +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/res/layout/touch_to_fill_credit_card_sheet.xml
@@ -38,7 +38,6 @@ android:clipToPadding="false" android:divider="@null" tools:listitem="@layout/touch_to_fill_credit_card_sheet_item"/> - <!-- Divider --> <View style="@style/HorizontalDivider" android:layout_width="match_parent" @@ -59,6 +58,7 @@ android:paddingHorizontal="@dimen/ttf_for_payments_sheet_padding_horizontal" android:textAppearance="@style/TextAppearance.TextMedium.Primary" android:text="@string/autofill_scan_credit_card" + android:visibility="gone" app:drawableStartCompat="@drawable/ic_photo_camera" app:drawableTint="@color/default_icon_color_tint_list"/> -</RelativeLayout> \ No newline at end of file +</RelativeLayout>
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerBridge.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerBridge.java index 2515909b..10d681ef 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerBridge.java +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerBridge.java
@@ -38,8 +38,17 @@ } } + @Override + public void scanCreditCard() { + if (mNativeTouchToFillCreditCardViewController != 0) { + TouchToFillCreditCardControllerBridgeJni.get().scanCreditCard( + mNativeTouchToFillCreditCardViewController); + } + } + @NativeMethods interface Natives { void onDismissed(long nativeTouchToFillCreditCardViewController); + void scanCreditCard(long nativeTouchToFillCreditCardViewController); } }
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerRobolectricTest.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerRobolectricTest.java new file mode 100644 index 0000000..3c75e9d --- /dev/null +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardControllerRobolectricTest.java
@@ -0,0 +1,61 @@ +// 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. + +package org.chromium.chrome.browser.touch_to_fill.payments; + +import static org.mockito.Mockito.verify; + +import android.app.Activity; +import android.content.Context; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.Robolectric; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.ui.modelutil.PropertyModel; + +/** Tests for {@link TouchToFillCreditCardCoordinator} and {@link TouchToFillCreditCardMediator} */ +@RunWith(BaseRobolectricTestRunner.class) +public class TouchToFillCreditCardControllerRobolectricTest { + @Rule + public MockitoRule mMockitoRule = MockitoJUnit.rule(); + + private TouchToFillCreditCardCoordinator mCoordinator; + private PropertyModel mTouchToFillCreditCardModel; + Context mContext; + + @Mock + private BottomSheetController mBottomSheetController; + + @Mock + TouchToFillCreditCardComponent.Delegate mDelegateMock; + + public TouchToFillCreditCardControllerRobolectricTest() { + mCoordinator = new TouchToFillCreditCardCoordinator(); + mContext = Robolectric.buildActivity(Activity.class).get(); + } + + @Before + public void setUp() { + mCoordinator.initialize(mContext, mBottomSheetController, mDelegateMock); + mTouchToFillCreditCardModel = + mCoordinator.getTouchToFillCreditCardPropertyModelForTesting(); + } + + @Test + public void testScanNewCard() { + mCoordinator.showSheet(true); + Runnable scanNewCardCallback = mTouchToFillCreditCardModel.get( + TouchToFillCreditCardProperties.SCAN_CREDIT_CARD_CALLBACK); + scanNewCardCallback.run(); + verify(mDelegateMock).scanCreditCard(); + } +}
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardCoordinator.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardCoordinator.java index 429786c..90aff50 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardCoordinator.java +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardCoordinator.java
@@ -18,23 +18,28 @@ */ public class TouchToFillCreditCardCoordinator implements TouchToFillCreditCardComponent { private final TouchToFillCreditCardMediator mMediator = new TouchToFillCreditCardMediator(); + private PropertyModel mTouchToFillCreditCardModel; @Override public void initialize(Context context, BottomSheetController sheetController, TouchToFillCreditCardComponent.Delegate delegate) { - PropertyModel model = new PropertyModel.Builder(TouchToFillCreditCardProperties.ALL_KEYS) - .with(TouchToFillCreditCardProperties.VISIBLE, false) - .with(TouchToFillCreditCardProperties.DISMISS_HANDLER, - mMediator::onDismissed) - .build(); + mTouchToFillCreditCardModel = + new PropertyModel.Builder(TouchToFillCreditCardProperties.ALL_KEYS) + .with(TouchToFillCreditCardProperties.VISIBLE, false) + .with(TouchToFillCreditCardProperties.DISMISS_HANDLER, + mMediator::onDismissed) + .with(TouchToFillCreditCardProperties.SCAN_CREDIT_CARD_CALLBACK, + mMediator::scanCreditCard) + .build(); - mMediator.initialize(delegate, model); - setUpModelChangeProcessors(model, new TouchToFillCreditCardView(context, sheetController)); + mMediator.initialize(delegate, mTouchToFillCreditCardModel); + setUpModelChangeProcessors(mTouchToFillCreditCardModel, + new TouchToFillCreditCardView(context, sheetController)); } @Override - public void showSheet() { - mMediator.showSheet(); + public void showSheet(boolean shouldShowScanCreditCard) { + mMediator.showSheet(shouldShowScanCreditCard); } @Override @@ -52,4 +57,9 @@ PropertyModelChangeProcessor.create( model, view, TouchToFillCreditCardViewBinder::bindTouchToFillCreditCardView); } + + @VisibleForTesting + PropertyModel getTouchToFillCreditCardPropertyModelForTesting() { + return mTouchToFillCreditCardModel; + } }
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardMediator.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardMediator.java index 739431e..26c58ff 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardMediator.java +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardMediator.java
@@ -4,6 +4,7 @@ package org.chromium.chrome.browser.touch_to_fill.payments; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillCreditCardProperties.SHOULD_SHOW_SCAN_CREDIT_CARD; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillCreditCardProperties.VISIBLE; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; @@ -24,8 +25,9 @@ mModel = model; } - void showSheet() { + void showSheet(boolean shouldShowScanCreditCard) { mModel.set(VISIBLE, true); + mModel.set(SHOULD_SHOW_SCAN_CREDIT_CARD, shouldShowScanCreditCard); } void hideSheet() { @@ -37,4 +39,8 @@ mModel.set(VISIBLE, false); mDelegate.onDismissed(); } + + public void scanCreditCard() { + mDelegate.scanCreditCard(); + } }
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardProperties.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardProperties.java index db84708..3703887 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardProperties.java +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardProperties.java
@@ -7,6 +7,7 @@ import org.chromium.base.Callback; import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyModel; +import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey; /** * Properties defined here reflect the visible state of the TouchToFillCreditCard component. @@ -16,6 +17,11 @@ new PropertyModel.WritableBooleanPropertyKey("visible"); static final PropertyModel.ReadableObjectPropertyKey<Callback<Integer>> DISMISS_HANDLER = new PropertyModel.ReadableObjectPropertyKey<>("dismiss_handler"); + static final PropertyModel.WritableBooleanPropertyKey SHOULD_SHOW_SCAN_CREDIT_CARD = + new PropertyModel.WritableBooleanPropertyKey("should_show_scan_credit_card"); + static final PropertyModel.ReadableObjectPropertyKey<Runnable> SCAN_CREDIT_CARD_CALLBACK = + new ReadableObjectPropertyKey<>("scan_credit_card_callback"); - static final PropertyKey[] ALL_KEYS = {VISIBLE, DISMISS_HANDLER}; + static final PropertyKey[] ALL_KEYS = { + VISIBLE, DISMISS_HANDLER, SHOULD_SHOW_SCAN_CREDIT_CARD, SCAN_CREDIT_CARD_CALLBACK}; }
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardView.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardView.java index 8575af8..0c3d842 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardView.java +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardView.java
@@ -29,6 +29,7 @@ private final BottomSheetController mBottomSheetController; private final RelativeLayout mContentView; private Callback<Integer> mDismissHandler; + private Runnable mScanCreditCardHandler; // TODO(): show gpay logo if there is at least one card coming from GPay, // if there are only local cards show chrome logo private boolean mOnlyLocalCards; @@ -69,6 +70,17 @@ ContextUtils.getApplicationContext().getTheme())); } + void setScanCreditCardButton(boolean shouldShowScanCreditCard) { + View scanCreditCard = mContentView.findViewById(R.id.scan_new_card); + if (shouldShowScanCreditCard) { + scanCreditCard.setVisibility(View.VISIBLE); + scanCreditCard.setOnClickListener(unused -> mScanCreditCardHandler.run()); + } else { + scanCreditCard.setVisibility(View.GONE); + scanCreditCard.setOnClickListener(null); + } + } + /** * Sets a new listener that reacts to a dismisal event. * @@ -78,6 +90,10 @@ mDismissHandler = dismissHandler; } + void setScanCreditCardCallback(Runnable callback) { + mScanCreditCardHandler = callback; + } + /** * If set to true, requests to show the bottom sheet. Otherwise, requests to hide the sheet. *
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewBinder.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewBinder.java index 1cca5a2..0c9b810 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewBinder.java +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewBinder.java
@@ -5,6 +5,8 @@ package org.chromium.chrome.browser.touch_to_fill.payments; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillCreditCardProperties.DISMISS_HANDLER; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillCreditCardProperties.SCAN_CREDIT_CARD_CALLBACK; +import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillCreditCardProperties.SHOULD_SHOW_SCAN_CREDIT_CARD; import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillCreditCardProperties.VISIBLE; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; @@ -26,6 +28,10 @@ PropertyModel model, TouchToFillCreditCardView view, PropertyKey propertyKey) { if (propertyKey == DISMISS_HANDLER) { view.setDismissHandler(model.get(DISMISS_HANDLER)); + } else if (propertyKey == SHOULD_SHOW_SCAN_CREDIT_CARD) { + view.setScanCreditCardButton(model.get(SHOULD_SHOW_SCAN_CREDIT_CARD)); + } else if (propertyKey == SCAN_CREDIT_CARD_CALLBACK) { + view.setScanCreditCardCallback(model.get(SCAN_CREDIT_CARD_CALLBACK)); } else if (propertyKey == VISIBLE) { boolean visibilityChangeSuccessful = view.setVisible(model.get(VISIBLE)); if (!visibilityChangeSuccessful && model.get(VISIBLE)) {
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewBridge.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewBridge.java index 1841df7..dcd564c 100644 --- a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewBridge.java +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewBridge.java
@@ -43,8 +43,9 @@ } @CalledByNative - private void showSheet(PersonalDataManager.CreditCard[] cards) { - mComponent.showSheet(); + private void showSheet( + PersonalDataManager.CreditCard[] cards, boolean shouldShowScanCreditCard) { + mComponent.showSheet(shouldShowScanCreditCard); } @CalledByNative
diff --git a/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewTest.java b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewTest.java new file mode 100644 index 0000000..115d790 --- /dev/null +++ b/chrome/browser/touch_to_fill/payments/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardViewTest.java
@@ -0,0 +1,91 @@ +// 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. + +package org.chromium.chrome.browser.touch_to_fill.payments; + +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +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 org.hamcrest.Matchers.not; +import static org.mockito.Mockito.verify; + +import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking; + +import androidx.test.filters.MediumTest; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.quality.Strictness; + +import org.chromium.base.test.util.Batch; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.browser.flags.ChromeSwitches; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.chrome.test.ChromeTabbedActivityTestRule; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.SheetState; +import org.chromium.components.browser_ui.bottomsheet.BottomSheetTestSupport; + +/** Tests for {@link TouchToFillCreditCardView} */ +@RunWith(ChromeJUnit4ClassRunner.class) +@Batch(Batch.PER_CLASS) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class TouchToFillCreditCardViewTest { + private BottomSheetController mBottomSheetController; + private BottomSheetTestSupport mSheetSupport; + private TouchToFillCreditCardCoordinator mCoordinator; + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + + @Mock + private TouchToFillCreditCardComponent.Delegate mDelegateMock; + + @Rule + public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); + + @Before + public void setupTest() throws InterruptedException { + mActivityTestRule.startMainActivityOnBlankPage(); + mBottomSheetController = mActivityTestRule.getActivity() + .getRootUiCoordinatorForTesting() + .getBottomSheetController(); + mSheetSupport = new BottomSheetTestSupport(mBottomSheetController); + runOnUiThreadBlocking(() -> { + mCoordinator = new TouchToFillCreditCardCoordinator(); + mCoordinator.initialize( + mActivityTestRule.getActivity(), mBottomSheetController, mDelegateMock); + }); + } + + @Test + @MediumTest + public void testScanNewCardButtonIsHidden() { + runOnUiThreadBlocking(() -> mCoordinator.showSheet(false)); + BottomSheetTestSupport.waitForOpen(mBottomSheetController); + runOnUiThreadBlocking(() -> { mSheetSupport.setSheetState(SheetState.FULL, false); }); + + onView(withId(R.id.scan_new_card)).check(matches(not(isDisplayed()))); + } + + @Test + @MediumTest + public void testScanNewCardClick() { + runOnUiThreadBlocking(() -> mCoordinator.showSheet(true)); + BottomSheetTestSupport.waitForOpen(mBottomSheetController); + runOnUiThreadBlocking(() -> { mSheetSupport.setSheetState(SheetState.FULL, false); }); + + onView(withId(R.id.scan_new_card)).perform(click()); + + verify(mDelegateMock).scanCreditCard(); + } +}
diff --git a/chrome/browser/touch_to_fill/payments/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardComponent.java b/chrome/browser/touch_to_fill/payments/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardComponent.java index 688e778d..bf802561 100644 --- a/chrome/browser/touch_to_fill/payments/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardComponent.java +++ b/chrome/browser/touch_to_fill/payments/android/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillCreditCardComponent.java
@@ -21,6 +21,11 @@ * Called whenever the sheet is dismissed (by user or native). */ void onDismissed(); + + /** + * Called when user requests to scan a new credit card. + */ + void scanCreditCard(); } /** @@ -34,7 +39,7 @@ /** * Displays a new bottom sheet. */ - void showSheet(); + void showSheet(boolean shouldShowScanCreditCard); /** * Hides the bottom sheet if shown.
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.cc b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.cc index 39d6113..95e022f 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.cc +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include "chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h" - #include "chrome/browser/touch_to_fill/payments/android/jni_headers/TouchToFillCreditCardControllerBridge_jni.h" #include "chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view.h" #include "components/autofill/content/browser/content_autofill_driver.h" @@ -27,7 +26,8 @@ if (view_) return false; - if (!view->Show(this, std::move(cards_to_suggest))) { + if (!view->Show(this, std::move(cards_to_suggest), + delegate->ShouldShowScanCreditCard())) { java_object_.Reset(); return false; } @@ -57,6 +57,10 @@ java_object_.Reset(); } +void TouchToFillCreditCardController::ScanCreditCard(JNIEnv* env) { + delegate_->ScanCreditCard(); +} + base::android::ScopedJavaLocalRef<jobject> TouchToFillCreditCardController::GetJavaObject() { if (!java_object_) {
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h index 344c49e..8ccb2ce 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h
@@ -43,13 +43,16 @@ // Hides the surface if it is currently shown. void Hide(); + // TouchToFillCreditCardViewController: + // Called whenever the surface gets hidden (regardless of the cause). + void OnDismissed(JNIEnv* env) override; + // Calls credit card scanner + void ScanCreditCard(JNIEnv* env) override; + private: // Called after the surface gets shown or hidden. void SetShouldSuppressKeyboard(bool suppress); - // TouchToFillCreditCardViewController: - // Called whenever the surface gets hidden (regardless of the cause). - void OnDismissed(JNIEnv* env) override; // Gets or creates the Java counterpart. base::android::ScopedJavaLocalRef<jobject> GetJavaObject() override;
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller_unittest.cc b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller_unittest.cc index 84f04b4..85b66f8 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller_unittest.cc +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller_unittest.cc
@@ -7,7 +7,9 @@ #include "chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_controller.h" #include "chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view.h" +#include "chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_controller.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/core/browser/autofill_driver.h" #include "components/autofill/core/browser/autofill_test_utils.h" #include "components/autofill/core/browser/data_model/autofill_profile.h" @@ -19,25 +21,42 @@ namespace { using ::autofill::CreditCard; using ::testing::ElementsAreArray; +using ::testing::Return; class MockTouchToFillCreditCardViewImpl : public autofill::TouchToFillCreditCardView { public: - MockTouchToFillCreditCardViewImpl() = default; + MockTouchToFillCreditCardViewImpl() { + ON_CALL(*this, Show).WillByDefault(Return(true)); + } ~MockTouchToFillCreditCardViewImpl() override = default; MOCK_METHOD(bool, Show, (autofill::TouchToFillCreditCardViewController * controller, - base::span<const autofill::CreditCard* const> cards_to_suggest)); + base::span<const autofill::CreditCard* const> cards_to_suggest, + bool should_show_scan_credit_card)); MOCK_METHOD(void, Hide, ()); }; -// virtual AutofillDriver* GetDriver() +class MockContentAutofillDriver : public autofill::ContentAutofillDriver { + public: + MockContentAutofillDriver() + : autofill::ContentAutofillDriver(nullptr, nullptr) {} + MockContentAutofillDriver(const MockContentAutofillDriver&) = delete; + MockContentAutofillDriver& operator=(const MockContentAutofillDriver&) = + delete; + ~MockContentAutofillDriver() override = default; + + MOCK_METHOD(void, SetShouldSuppressKeyboard, (bool), (override)); +}; class MockTouchToFillDelegateImpl : public autofill::TouchToFillDelegate { public: - MockTouchToFillDelegateImpl() = default; + MockTouchToFillDelegateImpl() { + ON_CALL(*this, GetDriver).WillByDefault(Return(&driver_)); + ON_CALL(*this, ShouldShowScanCreditCard).WillByDefault(Return(true)); + } ~MockTouchToFillDelegateImpl() override = default; base::WeakPtr<MockTouchToFillDelegateImpl> GetWeakPointer() { @@ -50,8 +69,12 @@ const autofill::FormData& form, const autofill::FormFieldData& field)); MOCK_METHOD(autofill::AutofillDriver*, GetDriver, (), (override)); + MOCK_METHOD(bool, ShouldShowScanCreditCard, (), (override)); + MOCK_METHOD(void, ScanCreditCard, (), (override)); + MOCK_METHOD(void, OnCreditCardScanned, (const CreditCard& card), (override)); private: + MockContentAutofillDriver driver_; base::WeakPtrFactory<MockTouchToFillDelegateImpl> weak_factory_{this}; }; @@ -71,20 +94,27 @@ std::unique_ptr<MockTouchToFillCreditCardViewImpl> mock_view_; MockTouchToFillDelegateImpl mock_delegate_; + const CreditCard credit_card1_ = autofill::test::GetCreditCard(); + const CreditCard credit_card2_ = autofill::test::GetCreditCard2(); + const std::vector<const autofill::CreditCard*> credit_cards_ = { + &credit_card1_, &credit_card2_}; // The object to be tested. autofill::TouchToFillCreditCardController credit_card_controller_; }; TEST_F(TouchToFillCreditCardControllerTest, ShowPassesCardsToTheView) { - CreditCard credit_card1 = autofill::test::GetCreditCard(); - CreditCard credit_card2 = autofill::test::GetCreditCard2(); - std::vector<autofill::CreditCard*> credit_cards = {&credit_card1, - &credit_card2}; - // Test that the cards have ptopagated to the view. EXPECT_CALL(*mock_view_, - Show(&credit_card_controller_, ElementsAreArray(credit_cards))); + Show(&credit_card_controller_, ElementsAreArray(credit_cards_), + testing::Eq(true))); credit_card_controller_.Show(std::move(mock_view_), - mock_delegate_.GetWeakPointer(), credit_cards); + mock_delegate_.GetWeakPointer(), credit_cards_); +} + +TEST_F(TouchToFillCreditCardControllerTest, ScanCreditCardIsCalled) { + credit_card_controller_.Show(std::move(mock_view_), + mock_delegate_.GetWeakPointer(), credit_cards_); + EXPECT_CALL(mock_delegate_, ScanCreditCard); + credit_card_controller_.ScanCreditCard(nullptr); }
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view.h b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view.h index 88fdeddd..2cbdce6 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view.h +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view.h
@@ -20,7 +20,8 @@ virtual bool Show( TouchToFillCreditCardViewController* controller, - base::span<const autofill::CreditCard* const> cards_to_suggest) = 0; + base::span<const autofill::CreditCard* const> cards_to_suggest, + bool should_show_scan_credit_card) = 0; virtual void Hide() = 0; };
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_controller.h b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_controller.h index 5d3dfc54..2b833c4a 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_controller.h +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_controller.h
@@ -15,6 +15,7 @@ virtual ~TouchToFillCreditCardViewController() = default; virtual void OnDismissed(JNIEnv* env) = 0; + virtual void ScanCreditCard(JNIEnv* env) = 0; virtual base::android::ScopedJavaLocalRef<jobject> GetJavaObject() = 0; };
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_impl.cc b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_impl.cc index 07d7c4a..d7d3cc2b 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_impl.cc +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_impl.cc
@@ -28,7 +28,8 @@ bool TouchToFillCreditCardViewImpl::Show( TouchToFillCreditCardViewController* controller, - base::span<const autofill::CreditCard* const> cards_to_suggest) { + base::span<const autofill::CreditCard* const> cards_to_suggest, + bool should_show_scan_credit_card) { if (java_object_) return false; // Already shown. @@ -59,8 +60,8 @@ PersonalDataManagerAndroid::CreateJavaCreditCardFromNative( env, *cards_to_suggest[i])); } - Java_TouchToFillCreditCardViewBridge_showSheet(env, java_object_, - credit_cards_array); + Java_TouchToFillCreditCardViewBridge_showSheet( + env, java_object_, credit_cards_array, should_show_scan_credit_card); return true; }
diff --git a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_impl.h b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_impl.h index 2f3252dc..ed9a669 100644 --- a/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_impl.h +++ b/chrome/browser/touch_to_fill/payments/android/touch_to_fill_credit_card_view_impl.h
@@ -31,9 +31,9 @@ private: // TouchToFillCreditCardView: - bool Show( - TouchToFillCreditCardViewController* controller, - base::span<const autofill::CreditCard* const> cards_to_suggest) override; + bool Show(TouchToFillCreditCardViewController* controller, + base::span<const autofill::CreditCard* const> cards_to_suggest, + bool should_show_scan_credit_card) override; void Hide() override; // The corresponding Java TouchToFillCreditCardViewBridge.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index c9164ad..5246977 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -3781,8 +3781,6 @@ "cocoa/javascript_app_modal_dialog_cocoa.mm", "cocoa/key_equivalent_constants.h", "cocoa/key_equivalent_constants.mm", - "cocoa/keystone_infobar_delegate.h", - "cocoa/keystone_infobar_delegate.mm", "cocoa/l10n_util.h", "cocoa/l10n_util.mm", "cocoa/last_active_browser_cocoa.cc", @@ -3869,6 +3867,13 @@ "window_sizer/window_sizer_mac.mm", ] + if (enable_updater) { + sources += [ + "cocoa/keystone_infobar_delegate.h", + "cocoa/keystone_infobar_delegate.mm", + ] + } + allow_circular_includes_from += [ "//chrome/browser/apps/app_shim" ] deps += [
diff --git a/chrome/browser/ui/app_list/search/app_result.cc b/chrome/browser/ui/app_list/search/app_result.cc index ae18023..1ac0fbc 100644 --- a/chrome/browser/ui/app_list/search/app_result.cc +++ b/chrome/browser/ui/app_list/search/app_result.cc
@@ -16,7 +16,7 @@ : profile_(profile), app_id_(app_id), controller_(controller) { - SetDisplayType(ash::SearchResultDisplayType::kTile); + SetDisplayType(ash::SearchResultDisplayType::kList); SetResultType(ash::AppListSearchResultType::kInstalledApp); SetMetricsType(ash::SEARCH_RESULT_TYPE_BOUNDARY); SetIsRecommendation(is_recommendation);
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_shortcut_search_result.cc b/chrome/browser/ui/app_list/search/arc/arc_app_shortcut_search_result.cc index d9afa41..3b4b722 100644 --- a/chrome/browser/ui/app_list/search/arc/arc_app_shortcut_search_result.cc +++ b/chrome/browser/ui/app_list/search/arc/arc_app_shortcut_search_result.cc
@@ -46,7 +46,7 @@ SetCategory(Category::kAppShortcuts); SetAccessibleName(ComputeAccessibleName()); SetResultType(ash::AppListSearchResultType::kArcAppShortcut); - SetDisplayType(ash::SearchResultDisplayType::kTile); + SetDisplayType(ash::SearchResultDisplayType::kList); SetMetricsType(ash::PLAY_STORE_APP_SHORTCUT); SetIsRecommendation(is_recommendation);
diff --git a/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc index 46f809d6..1683755e 100644 --- a/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/arc/arc_app_shortcuts_search_provider_unittest.cc
@@ -121,7 +121,7 @@ for (size_t i = 0; i < results.size(); ++i) { EXPECT_EQ(base::StringPrintf("ShortLabel %zu", i), base::UTF16ToUTF8(results[i]->title())); - EXPECT_EQ(ash::SearchResultDisplayType::kTile, results[i]->display_type()); + EXPECT_EQ(ash::SearchResultDisplayType::kList, results[i]->display_type()); } }
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc index 2ce6769..4420e57 100644 --- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_provider_unittest.cc
@@ -108,7 +108,7 @@ SCOPED_TRACE(base::StringPrintf("Testing result %zu", i)); EXPECT_EQ(results[i]->title(), base::StrCat({kQuery, u" ", base::NumberToString16(i)})); - EXPECT_EQ(results[i]->display_type(), ash::SearchResultDisplayType::kTile); + EXPECT_EQ(results[i]->display_type(), ash::SearchResultDisplayType::kList); EXPECT_EQ(base::UTF16ToUTF8(results[i]->formatted_price()), base::StringPrintf("$%zu.22", i)); EXPECT_EQ(results[i]->rating(), i); @@ -149,7 +149,7 @@ SCOPED_TRACE(base::StringPrintf("Testing result %zu", i)); EXPECT_EQ(results[i]->title(), base::StrCat({kQuery, u" ", base::NumberToString16(i)})); - EXPECT_EQ(results[i]->display_type(), ash::SearchResultDisplayType::kTile); + EXPECT_EQ(results[i]->display_type(), ash::SearchResultDisplayType::kList); EXPECT_EQ(base::UTF16ToUTF8(results[i]->formatted_price()), base::StringPrintf("$%zu.22", i)); EXPECT_EQ(results[i]->rating(), i); @@ -186,7 +186,7 @@ SCOPED_TRACE(base::StringPrintf("Testing result %zu", i)); EXPECT_EQ(results[i]->title(), base::StrCat({kQuery, u" ", base::NumberToString16(i)})); - EXPECT_EQ(results[i]->display_type(), ash::SearchResultDisplayType::kTile); + EXPECT_EQ(results[i]->display_type(), ash::SearchResultDisplayType::kList); EXPECT_EQ(base::UTF16ToUTF8(results[i]->formatted_price()), ""); EXPECT_EQ(results[i]->rating(), -1); const bool is_instant_app = i % 2 == 0; @@ -223,7 +223,7 @@ SCOPED_TRACE(base::StringPrintf("Testing result %zu", i)); EXPECT_EQ(results[i]->title(), base::StrCat({kQuery, u" ", base::NumberToString16(i)})); - EXPECT_EQ(results[i]->display_type(), ash::SearchResultDisplayType::kTile); + EXPECT_EQ(results[i]->display_type(), ash::SearchResultDisplayType::kList); EXPECT_EQ(base::UTF16ToUTF8(results[i]->formatted_price()), base::StringPrintf("$%zu.22", i)); EXPECT_EQ(results[i]->rating(), i);
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc index a223238..4b96fae 100644 --- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc +++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
@@ -110,7 +110,7 @@ set_id(kPlayAppPrefix + crx_file::id_util::GenerateId(install_intent_uri().value())); SetCategory(Category::kPlayStore); - SetDisplayType(ash::SearchResultDisplayType::kTile); + SetDisplayType(ash::SearchResultDisplayType::kList); // TODO: The badge icon should be updated to pass through a vector icon and // color id rather than hardcoding the colors here. This will require // tweaking sizes/paddings so we can set use_badge_icon_background to true and
diff --git a/chrome/browser/ui/app_list/search/common/types_util.cc b/chrome/browser/ui/app_list/search/common/types_util.cc index 56a3a96..21dcebc 100644 --- a/chrome/browser/ui/app_list/search/common/types_util.cc +++ b/chrome/browser/ui/app_list/search/common/types_util.cc
@@ -180,12 +180,8 @@ return "None"; case ash::SearchResultDisplayType::kList: return "List"; - case ash::SearchResultDisplayType::kTile: - return "Tile"; case ash::SearchResultDisplayType::kAnswerCard: return "AnswerCard"; - case ash::SearchResultDisplayType::kChip: - return "Chip"; case ash::SearchResultDisplayType::kContinue: return "Continue"; case ash::SearchResultDisplayType::kRecentApps:
diff --git a/chrome/browser/ui/app_list/search/files/file_result.cc b/chrome/browser/ui/app_list/search/files/file_result.cc index 134a583..021fb73 100644 --- a/chrome/browser/ui/app_list/search/files/file_result.cc +++ b/chrome/browser/ui/app_list/search/files/file_result.cc
@@ -254,9 +254,7 @@ dark_light_mode_controller->IsDarkModeEnabled(); const bool dark_background = !is_dark_light_enabled || is_dark_mode_enabled; - if (display_type() == DisplayType::kChip) { - SetChipIcon(chromeos::GetChipIconForPath(filepath_, dark_background)); - } else if (display_type() == DisplayType::kContinue) { + if (display_type() == DisplayType::kContinue) { // For Continue Section, if dark/light mode is disabled, we should use the // icon and not the chip icon with a dark background as default. const gfx::ImageSkia chip_icon =
diff --git a/chrome/browser/ui/app_list/search/files/file_result_unittest.cc b/chrome/browser/ui/app_list/search/files/file_result_unittest.cc index 030bbe5..b6b0a5ad 100644 --- a/chrome/browser/ui/app_list/search/files/file_result_unittest.cc +++ b/chrome/browser/ui/app_list/search/files/file_result_unittest.cc
@@ -100,15 +100,6 @@ } TEST_F(FileResultTest, Icons) { - const base::FilePath chipPath("/my/test/file.Pdf"); - FileResult chipResult( - /*id=*/"zero_state_file://" + chipPath.value(), chipPath, u"some details", - ash::AppListSearchResultType::kZeroStateFile, - ash::SearchResultDisplayType::kChip, 0.2f, std::u16string(), - FileResult::Type::kFile, profile_.get()); - EXPECT_FALSE(chipResult.chip_icon().isNull()); - EXPECT_TRUE(chipResult.icon().icon.isNull()); - const base::FilePath excelPath("/my/test/mySheet.xlsx"); FileResult fileResult( /*id=*/"zero_state_file://" + excelPath.value(), excelPath,
diff --git a/chrome/browser/ui/app_list/search/help_app_zero_state_provider.cc b/chrome/browser/ui/app_list/search/help_app_zero_state_provider.cc index 3e9d0dc..8de2760d 100644 --- a/chrome/browser/ui/app_list/search/help_app_zero_state_provider.cc +++ b/chrome/browser/ui/app_list/search/help_app_zero_state_provider.cc
@@ -176,8 +176,7 @@ ash::AppListNotifier::Location location, const std::vector<ash::AppListNotifier::Result>& results, const std::u16string& query) { - if (location != ash::AppListNotifier::Location::kChip && - location != ash::AppListNotifier::Location::kContinue) { + if (location != ash::AppListNotifier::Location::kContinue) { return; }
diff --git a/chrome/browser/ui/app_list/search/search_controller_impl.cc b/chrome/browser/ui/app_list/search/search_controller_impl.cc index ab036ac..970c5bc 100644 --- a/chrome/browser/ui/app_list/search/search_controller_impl.cc +++ b/chrome/browser/ui/app_list/search/search_controller_impl.cc
@@ -314,14 +314,6 @@ std::vector<ChromeSearchResult*> all_results; for (const auto& type_results : results_) { for (const auto& result : type_results.second) { - // TODO(crbug.com/1385194): Category-based search combines apps into the - // results list, so redirect any kTile results to kList before updating - // the UI. Once SearchControllerImpl is the only search controller, - // this can be removed and all results can be created as kList. - if (result->display_type() == ash::SearchResultDisplayType::kTile) { - result->SetDisplayType(ash::SearchResultDisplayType::kList); - } - double score = result->scoring().FinalScore(); // Filter out results with negative relevance, which is the rankers'
diff --git a/chrome/browser/ui/app_list/search/search_metrics_manager.cc b/chrome/browser/ui/app_list/search/search_metrics_manager.cc index 13b652e3..fb0b1f7 100644 --- a/chrome/browser/ui/app_list/search/search_metrics_manager.cc +++ b/chrome/browser/ui/app_list/search/search_metrics_manager.cc
@@ -33,12 +33,8 @@ switch (location) { case Location::kList: return query.empty() ? "ListZeroState" : "ListSearch"; - case Location::kTile: - return query.empty() ? "AppsZeroState" : "AppsSearch"; case Location::kAnswerCard: return "AnswerCard"; - case Location::kChip: - return "Chip"; case Location::kRecentApps: return "RecentApps"; case Location::kContinue:
diff --git a/chrome/browser/ui/ash/sharesheet/sharesheet_bubble_view.cc b/chrome/browser/ui/ash/sharesheet/sharesheet_bubble_view.cc index 1cbd666a..c77b09e 100644 --- a/chrome/browser/ui/ash/sharesheet/sharesheet_bubble_view.cc +++ b/chrome/browser/ui/ash/sharesheet/sharesheet_bubble_view.cc
@@ -159,23 +159,12 @@ gfx::NativeWindow native_window, ::sharesheet::SharesheetServiceDelegator* delegator) : delegator_(delegator) { - CHECK(native_window); - CHECK(delegator); - SetID(SHARESHEET_BUBBLE_VIEW_ID); - // We set the dialog role because views::BubbleDialogDelegate defaults this to - // an alert dialog. This would make screen readers announce all of this dialog - // which is undesirable. - SetAccessibleRole(ax::mojom::Role::kDialog); - SetAccessibleTitle(l10n_util::GetStringUTF16(IDS_SHARESHEET_TITLE_LABEL)); - set_parent_window(native_window); - views::Widget* const widget = - views::Widget::GetWidgetForNativeWindow(native_window); - CHECK(widget); - parent_view_ = widget->GetRootView(); - CHECK(this); - parent_widget_observer_ = - std::make_unique<SharesheetParentWidgetObserver>(this, widget); - AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); + PerformLoggingAndChecks(native_window); + + SetUpDialog(); + + SetUpParentWindow(native_window); + CreateBubble(); } @@ -474,6 +463,48 @@ CloseWidgetWithAnimateFadeOut(reason); } +// --- Added for debugging purposes. Remove after bug fixed. + +void SharesheetBubbleView::PerformLoggingAndChecks( + gfx::NativeWindow native_window) { + if (!native_window) { + LOG(ERROR) << "Native_window value is null"; + } + CHECK(native_window); + if (!delegator_) { + LOG(ERROR) << "Delegator value is null"; + } + CHECK(delegator_); +} + +void SharesheetBubbleView::SetUpDialog() { + SetID(SHARESHEET_BUBBLE_VIEW_ID); + // We set the dialog role because views::BubbleDialogDelegate defaults this to + // an alert dialog. This would make screen readers announce all of this dialog + // which is undesirable. + SetAccessibleRole(ax::mojom::Role::kDialog); + SetAccessibleTitle(l10n_util::GetStringUTF16(IDS_SHARESHEET_TITLE_LABEL)); + AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); +} + +void SharesheetBubbleView::SetUpParentWindow(gfx::NativeWindow native_window) { + set_parent_window(native_window); + views::Widget* const widget = + views::Widget::GetWidgetForNativeWindow(native_window); + if (!widget) { + LOG(ERROR) << "Widget value is null"; + } + if (!widget->GetRootView()) { + LOG(ERROR) << "Widget RootView value is null"; + } + CHECK(widget); + parent_view_ = widget->GetRootView(); + parent_widget_observer_ = + std::make_unique<SharesheetParentWidgetObserver>(this, widget); +} + +// --- End of functions added for debugging. + bool SharesheetBubbleView::AcceleratorPressed( const ui::Accelerator& accelerator) { // We override this because when this is handled by the base class,
diff --git a/chrome/browser/ui/ash/sharesheet/sharesheet_bubble_view.h b/chrome/browser/ui/ash/sharesheet/sharesheet_bubble_view.h index 8c944fe..0315916 100644 --- a/chrome/browser/ui/ash/sharesheet/sharesheet_bubble_view.h +++ b/chrome/browser/ui/ash/sharesheet/sharesheet_bubble_view.h
@@ -7,6 +7,7 @@ #include <vector> +#include "ash/ash_export.h" #include "ash/public/cpp/tablet_mode.h" #include "ash/public/cpp/tablet_mode_observer.h" #include "chrome/browser/sharesheet/sharesheet_types.h" @@ -57,6 +58,14 @@ void ResizeBubble(const int& width, const int& height); void CloseBubble(views::Widget::ClosedReason reason); + // --- Added for debugging purposes. Remove after bug fixed. + + ASH_EXPORT void PerformLoggingAndChecks(gfx::NativeWindow native_window); + ASH_EXPORT void SetUpDialog(); + ASH_EXPORT void SetUpParentWindow(gfx::NativeWindow native_window); + + // --- End of functions added for debugging. + private: class SharesheetParentWidgetObserver;
diff --git a/chrome/browser/ui/profile_picker.cc b/chrome/browser/ui/profile_picker.cc index 7e248a24..bcabd50 100644 --- a/chrome/browser/ui/profile_picker.cc +++ b/chrome/browser/ui/profile_picker.cc
@@ -50,8 +50,7 @@ #if BUILDFLAG(IS_CHROMEOS_LACROS) NotifyAccountSelected(std::string()); NotifyFirstRunExited(FirstRunExitStatus::kQuitEarly, - FirstRunExitSource::kParamDestructor, - base::OnceClosure()); + FirstRunExitSource::kParamDestructor); #endif } @@ -114,12 +113,12 @@ return params; } -void ProfilePicker::Params::NotifyFirstRunExited( - FirstRunExitStatus exit_status, +void ProfilePicker::Params::NotifyFirstRunExited(FirstRunExitStatus exit_status #if BUILDFLAG(IS_CHROMEOS_LACROS) - FirstRunExitSource exit_source, + , + FirstRunExitSource exit_source #endif - base::OnceClosure maybe_callback) { +) { if (!first_run_exited_callback_) return; @@ -129,8 +128,7 @@ << " from source=" << static_cast<int>(exit_source); #endif - std::move(first_run_exited_callback_) - .Run(exit_status, std::move(maybe_callback)); + std::move(first_run_exited_callback_).Run(exit_status); } bool ProfilePicker::Params::CanReusePickerWindow(const Params& other) const {
diff --git a/chrome/browser/ui/profile_picker.h b/chrome/browser/ui/profile_picker.h index 9d23557c9..f2faf24 100644 --- a/chrome/browser/ui/profile_picker.h +++ b/chrome/browser/ui/profile_picker.h
@@ -39,8 +39,7 @@ kQuitEarly = 2, }; using FirstRunExitedCallback = - base::OnceCallback<void(FirstRunExitStatus status, - base::OnceClosure callback)>; + base::OnceCallback<void(FirstRunExitStatus status)>; #if BUILDFLAG(IS_CHROMEOS_LACROS) // Added for bug investigation purposes. @@ -53,8 +52,7 @@ }; using DebugFirstRunExitedCallback = base::OnceCallback<void(FirstRunExitStatus status, - FirstRunExitSource source, - base::OnceClosure callback)>; + FirstRunExitSource source)>; #endif // Only work when passed as the argument 'on_select_profile_target_url' to @@ -150,23 +148,22 @@ // expect it to be the main profile path. // `first_run_exited_callback` is called when the first run experience is // exited, with a `FirstRunExitStatus` indicating how the user responded to - // it, and an optional callback that must be run if the user has proceeded - // to the browser after the FRE. + // it. static Params ForFirstRun(const base::FilePath& profile_path, FirstRunExitedCallback first_run_exited_callback); - // Calls `first_run_exited_callback_`, forwarding `exit_status` and - // `maybe_callback`. See `ForFirstRun()` for more - // details. + // Calls `first_run_exited_callback_`, forwarding `exit_status`.See + // `ForFirstRun()` for more details. // // If this method is not called by the time this `Param` is destroyed, an // intent to quit will be assumed and `first_run_exited_callback_` will be // called by the destructor with quit-related arguments. - void NotifyFirstRunExited(FirstRunExitStatus exit_status, + void NotifyFirstRunExited(FirstRunExitStatus exit_status #if BUILDFLAG(IS_CHROMEOS_LACROS) - FirstRunExitSource exit_source, + , + FirstRunExitSource exit_source #endif - base::OnceClosure maybe_callback); + ); // Returns whether the current profile picker window can be reused for // different parameters. If this returns false, the picker cannot be reused
diff --git a/chrome/browser/ui/profile_picker_unittest.cc b/chrome/browser/ui/profile_picker_unittest.cc index 541146a..2b81212 100644 --- a/chrome/browser/ui/profile_picker_unittest.cc +++ b/chrome/browser/ui/profile_picker_unittest.cc
@@ -214,8 +214,8 @@ } TEST_F(ProfilePickerParamsTest, ForFirstRun_Exit) { - testing::StrictMock<base::MockOnceCallback<void( - ProfilePicker::FirstRunExitStatus, base::OnceClosure)>> + testing::StrictMock< + base::MockOnceCallback<void(ProfilePicker::FirstRunExitStatus)>> callback; { ProfilePicker::Params params = ProfilePicker::Params::ForFirstRun( @@ -223,25 +223,23 @@ EXPECT_EQ(base::FilePath::FromASCII(chrome::kInitialProfile), params.profile_path().BaseName()); // The callback is called at destruction. - EXPECT_CALL(callback, Run(ProfilePicker::FirstRunExitStatus::kQuitEarly, - ::testing::_)); + EXPECT_CALL(callback, Run(ProfilePicker::FirstRunExitStatus::kQuitEarly)); } } TEST_F(ProfilePickerParamsTest, ForFirstRun_Notify) { - testing::StrictMock<base::MockOnceCallback<void( - ProfilePicker::FirstRunExitStatus, base::OnceClosure)>> + testing::StrictMock< + base::MockOnceCallback<void(ProfilePicker::FirstRunExitStatus)>> callback; { ProfilePicker::Params params = ProfilePicker::Params::ForFirstRun( ProfileManager::GetPrimaryUserProfilePath(), callback.Get()); EXPECT_EQ(base::FilePath::FromASCII(chrome::kInitialProfile), params.profile_path().BaseName()); - EXPECT_CALL(callback, Run(ProfilePicker::FirstRunExitStatus::kCompleted, - ::testing::_)); + EXPECT_CALL(callback, Run(ProfilePicker::FirstRunExitStatus::kCompleted)); params.NotifyFirstRunExited( ProfilePicker::FirstRunExitStatus::kCompleted, - ProfilePicker::FirstRunExitSource::kFlowFinished, base::DoNothing()); + ProfilePicker::FirstRunExitSource::kFlowFinished); } } #endif
diff --git a/chrome/browser/ui/startup/first_run_service.cc b/chrome/browser/ui/startup/first_run_service.cc index 2b51065a..38d3377 100644 --- a/chrome/browser/ui/startup/first_run_service.cc +++ b/chrome/browser/ui/startup/first_run_service.cc
@@ -85,12 +85,9 @@ // they were trying to do before they stopped to show the FRE. If the FRE's // `status` is not `ProfilePicker::FirstRunExitStatus::kCompleted`, that // `original_intent_callback` will be called with `proceed` set to false, -// otherwise it will be called with true. `post_first_run_callback` will be -// executed for completed flows, to perform tasks that the FRE requires after -// the interrupted task is resumed. +// otherwise it will be called with true. void OnFirstRunHasExited(ResumeTaskCallback original_intent_callback, - ProfilePicker::FirstRunExitStatus status, - base::OnceClosure post_first_run_callback) { + ProfilePicker::FirstRunExitStatus status) { if (status != ProfilePicker::FirstRunExitStatus::kQuitEarly) { // The user got to the last step, we can mark the FRE as finished, whether // we eventually proceed with the original intent or not. @@ -101,11 +98,6 @@ LOG_IF(ERROR, !proceed) << "Not proceeding FirstRun: " << static_cast<int>(status); std::move(original_intent_callback).Run(proceed); - - if (proceed) { - DCHECK(post_first_run_callback); - std::move(post_first_run_callback).Run(); - } } } // namespace
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc index 8cae23d..6d143c95 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -73,8 +73,10 @@ #if BUILDFLAG(IS_MAC) #include "base/mac/mac_util.h" +#if BUILDFLAG(ENABLE_UPDATER) #include "chrome/browser/ui/cocoa/keystone_infobar_delegate.h" #endif +#endif // BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) #include "chrome/browser/win/conflicts/incompatible_applications_updater.h" @@ -204,7 +206,7 @@ web_app::MaybeInstallAppFromCommandLine(*command_line_, *profile); -#if BUILDFLAG(IS_MAC) +#if BUILDFLAG(IS_MAC) && BUILDFLAG(ENABLE_UPDATER) if (process_startup == chrome::startup::IsProcessStartup::kYes) { // Check whether the auto-update system needs to be promoted from user // to system.
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc index 3a5f476..fcfeeffc 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_editor_view.cc
@@ -46,6 +46,10 @@ #include "ui/views/widget/widget.h" #include "url/gurl.h" +#if !BUILDFLAG(IS_MAC) +#include "ui/aura/window.h" +#endif // !BUILDFLAG(IS_MAC) + using bookmarks::BookmarkExpandedStateTracker; using bookmarks::BookmarkModel; using bookmarks::BookmarkNode;
diff --git a/chrome/browser/ui/views/profiles/first_run_flow_controller_dice.cc b/chrome/browser/ui/views/profiles/first_run_flow_controller_dice.cc index 971f488..6a5f91c 100644 --- a/chrome/browser/ui/views/profiles/first_run_flow_controller_dice.cc +++ b/chrome/browser/ui/views/profiles/first_run_flow_controller_dice.cc
@@ -156,16 +156,23 @@ /*enable_animations=*/true)); } -FirstRunFlowControllerDice::~FirstRunFlowControllerDice() = default; +FirstRunFlowControllerDice::~FirstRunFlowControllerDice() { + if (first_run_exited_callback_) { + std::move(first_run_exited_callback_) + .Run(ProfilePicker::FirstRunExitStatus::kQuitAtEnd); + } +} + +bool FirstRunFlowControllerDice::PreFinishWithBrowser() { + DCHECK(first_run_exited_callback_); + std::move(first_run_exited_callback_) + .Run(ProfilePicker::FirstRunExitStatus::kCompleted); + return true; +} void FirstRunFlowControllerDice::HandleIntroSigninChoice(bool sign_in) { if (!sign_in) { - std::move(first_run_exited_callback_) - .Run(ProfilePicker::FirstRunExitStatus::kCompleted, - base::BindOnce( - &FirstRunFlowControllerDice::FinishFlowAndRunInBrowser, - weak_ptr_factory_.GetWeakPtr(), profile_, - PostHostClearedCallback())); + FinishFlowAndRunInBrowser(profile_, PostHostClearedCallback()); return; }
diff --git a/chrome/browser/ui/views/profiles/first_run_flow_controller_dice.h b/chrome/browser/ui/views/profiles/first_run_flow_controller_dice.h index 21c561f1..047c429 100644 --- a/chrome/browser/ui/views/profiles/first_run_flow_controller_dice.h +++ b/chrome/browser/ui/views/profiles/first_run_flow_controller_dice.h
@@ -33,6 +33,10 @@ ProfilePicker::FirstRunExitedCallback first_run_exited_callback); ~FirstRunFlowControllerDice() override; + protected: + // ProfileManagementFlowController: + bool PreFinishWithBrowser() override; + private: void HandleIntroSigninChoice(bool sign_in);
diff --git a/chrome/browser/ui/views/profiles/first_run_flow_controller_lacros.cc b/chrome/browser/ui/views/profiles/first_run_flow_controller_lacros.cc index 29241ea..0372600 100644 --- a/chrome/browser/ui/views/profiles/first_run_flow_controller_lacros.cc +++ b/chrome/browser/ui/views/profiles/first_run_flow_controller_lacros.cc
@@ -143,7 +143,7 @@ // the `this` will own and outlive. base::Unretained(this)); auto finish_flow_callback = FinishFlowCallback( - base::BindOnce(&FirstRunFlowControllerLacros::ExitFlowAndRun, + base::BindOnce(&FirstRunFlowControllerLacros::FinishFlowAndRunInBrowser, // Unretained ok: the callback is passed to a step that // the `this` will own and outlive. base::Unretained(this), @@ -169,34 +169,17 @@ .Run(sync_confirmation_seen_ ? ProfilePicker::FirstRunExitStatus::kQuitAtEnd : ProfilePicker::FirstRunExitStatus::kQuitEarly, - ProfilePicker::FirstRunExitSource::kControllerDestructor, - // Since the flow is exited already, we don't have anything to - // close or finish setting up, and the callback won't be executed - // anyway. - /*maybe_callback=*/base::OnceClosure()); + ProfilePicker::FirstRunExitSource::kControllerDestructor); + // Since the flow is exited already, we don't have anything to close or + // finish setting up. } } -void FirstRunFlowControllerLacros::ExitFlowAndRun( - Profile* profile, - PostHostClearedCallback callback) { - // We don't call `FinishFlowAndRunInBrowser()` directly, as - // `first_run_exited_callback_` should make a browser window available when - // it runs. If there is no browser, then we will create it as a fallback. - // TODO(crbug.com/1383969): Races with Ash to open a window. Find another way. - auto finish_flow_callback = - base::BindOnce(&FirstRunFlowControllerLacros::FinishFlowAndRunInBrowser, - // Unretained ok: the flow will be closed when we run - // `finish_flow_callback`, so `this` will still be alive. - base::Unretained(this), - // Unretained ok: the flow keeps the profile alive and - // `first_run_exited_callback_` will open a browser for it. - base::Unretained(profile), std::move(callback)); - +bool FirstRunFlowControllerLacros::PreFinishWithBrowser() { std::move(first_run_exited_callback_) .Run(ProfilePicker::FirstRunExitStatus::kCompleted, - ProfilePicker::FirstRunExitSource::kFlowFinished, - std::move(finish_flow_callback)); + ProfilePicker::FirstRunExitSource::kFlowFinished); + return true; } void FirstRunFlowControllerLacros::MarkSyncConfirmationSeen() {
diff --git a/chrome/browser/ui/views/profiles/first_run_flow_controller_lacros.h b/chrome/browser/ui/views/profiles/first_run_flow_controller_lacros.h index 2033e6f..f40e911 100644 --- a/chrome/browser/ui/views/profiles/first_run_flow_controller_lacros.h +++ b/chrome/browser/ui/views/profiles/first_run_flow_controller_lacros.h
@@ -26,8 +26,11 @@ ~FirstRunFlowControllerLacros() override; + protected: + // ProfileManagementFlowController: + bool PreFinishWithBrowser() override; + private: - void ExitFlowAndRun(Profile* profile, PostHostClearedCallback callback); void MarkSyncConfirmationSeen(); // Captures the operation that the user expected to run at the time we chose
diff --git a/chrome/browser/ui/views/profiles/profile_management_flow_controller.cc b/chrome/browser/ui/views/profiles/profile_management_flow_controller.cc index 188f74c..352797e 100644 --- a/chrome/browser/ui/views/profiles/profile_management_flow_controller.cc +++ b/chrome/browser/ui/views/profiles/profile_management_flow_controller.cc
@@ -85,11 +85,19 @@ std::move(clear_host_callback_.value()).Run(); } +bool ProfileManagementFlowController::PreFinishWithBrowser() { + return false; +} + void ProfileManagementFlowController::FinishFlowAndRunInBrowser( Profile* profile, PostHostClearedCallback post_host_cleared_callback) { DCHECK(clear_host_callback_.value()); // The host shouldn't be cleared yet. + // TODO(crbug.com/1383969): Handle the return value and don't open a browser + // if it is already going to be opened. + PreFinishWithBrowser(); + base::OnceCallback<void(Profile*)> post_browser_open_callback = base::IgnoreArgs<Profile*>(std::move(clear_host_callback_.value())); if (!post_host_cleared_callback->is_null()) {
diff --git a/chrome/browser/ui/views/profiles/profile_management_flow_controller.h b/chrome/browser/ui/views/profiles/profile_management_flow_controller.h index 6289a81..888c796 100644 --- a/chrome/browser/ui/views/profiles/profile_management_flow_controller.h +++ b/chrome/browser/ui/views/profiles/profile_management_flow_controller.h
@@ -105,6 +105,14 @@ void FinishFlowAndRunInBrowser(Profile* profile, PostHostClearedCallback callback); + // Will be called at the beginning of `FinishFlowAndRunInBrowser`. + // + // Subclasses should override it if they want to perform some additional + // operations when the flow is closing. If they are going to open a browser + // themselves, they should return `true`. The default implementation does + // nothing and returns `false`. + virtual bool PreFinishWithBrowser(); + Step current_step() const { return current_step_; } Step initial_step() const { return initial_step_; }
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.cc b/chrome/browser/ui/views/profiles/profile_picker_view.cc index f74b67d..0923cbd 100644 --- a/chrome/browser/ui/views/profiles/profile_picker_view.cc +++ b/chrome/browser/ui/views/profiles/profile_picker_view.cc
@@ -372,7 +372,7 @@ params_.NotifyAccountSelected(std::string()); params_.NotifyFirstRunExited( ProfilePicker::FirstRunExitStatus::kQuitEarly, - ProfilePicker::FirstRunExitSource::kReusingWindow, base::OnceClosure()); + ProfilePicker::FirstRunExitSource::kReusingWindow); #endif params_ = std::move(params);
diff --git a/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc b/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc index a97471d..867b7a3e 100644 --- a/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc +++ b/chrome/browser/ui/views/toolbar/chrome_labs_view_controller.cc
@@ -29,6 +29,7 @@ #include "chrome/common/buildflags.h" #include "components/flags_ui/feature_entry.h" #include "components/flags_ui/flags_state.h" +#include "components/flags_ui/flags_storage.h" #include "components/prefs/scoped_user_pref_update.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac.cc index 4144d136..f37b013 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac.cc
@@ -376,81 +376,5 @@ helper_.CheckWindowNotCreated(); } -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerWindowed_118FileHandlerFoo_118FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kWindowed); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerBrowser_118FileHandlerFoo_118FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kBrowser); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - } // namespace } // namespace web_app::integration_tests
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc index ffad6f58..1787af9 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_mac_win_linux.cc
@@ -64,6 +64,29 @@ helper_.CheckSiteNotHandlesFile(Site::kStandalone, FileExtension::kBar); } +IN_PROC_BROWSER_TEST_F(WebAppIntegration, CheckLaunchFileExpectDialog) { + helper_.InstallMenuOption(InstallableSite::kFileHandler); + helper_.ClosePwa(); + helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, + AllowDenyOptions::kAllow, + AskAgainOptions::kAskAgain); + helper_.CheckWindowCreated(); +} + +IN_PROC_BROWSER_TEST_F(WebAppIntegration, CheckLaunchFileExpectNoDialog_Allow) { + helper_.InstallOmniboxIcon(InstallableSite::kFileHandler); + helper_.ClosePwa(); + // Open the file and set AskAgainOption to kRemember. + helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, + AllowDenyOptions::kAllow, + AskAgainOptions::kRemember); + helper_.ClosePwa(); + // Open the file again. + helper_.LaunchFileExpectNoDialog(Site::kFileHandler, + FilesOptions::kOneFooFile); + helper_.CheckWindowCreated(); +} + IN_PROC_BROWSER_TEST_F(WebAppIntegration, CheckLaunchFileExpectNoDialog_Deny) { helper_.InstallOmniboxIcon(InstallableSite::kFileHandler); helper_.ClosePwa(); @@ -1468,6 +1491,82 @@ IN_PROC_BROWSER_TEST_F( WebAppIntegration, + WAI_29FileHandlerBrowser_118FileHandlerFoo_118FileHandlerBar) { + // Test contents are generated by script. Please do not modify! + // See `docs/webapps/why-is-this-test-failing.md` or + // `docs/webapps/integration-testing-framework` for more info. + // Sheriffs: Disabling this test is supported. + helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kBrowser); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); +} + +IN_PROC_BROWSER_TEST_F( + WebAppIntegration, + WAI_32FileHandlerWithShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar) { + // Test contents are generated by script. Please do not modify! + // See `docs/webapps/why-is-this-test-failing.md` or + // `docs/webapps/integration-testing-framework` for more info. + // Sheriffs: Disabling this test is supported. + helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, + WindowOptions::kWindowed, InstallMode::kWebApp); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); +} + +IN_PROC_BROWSER_TEST_F( + WebAppIntegration, + WAI_32FileHandlerWithShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar) { + // Test contents are generated by script. Please do not modify! + // See `docs/webapps/why-is-this-test-failing.md` or + // `docs/webapps/integration-testing-framework` for more info. + // Sheriffs: Disabling this test is supported. + helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, + WindowOptions::kBrowser, InstallMode::kWebApp); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); +} + +IN_PROC_BROWSER_TEST_F( + WebAppIntegration, + WAI_32FileHandlerNoShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar) { + // Test contents are generated by script. Please do not modify! + // See `docs/webapps/why-is-this-test-failing.md` or + // `docs/webapps/integration-testing-framework` for more info. + // Sheriffs: Disabling this test is supported. + helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, + WindowOptions::kWindowed, InstallMode::kWebApp); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); +} + +IN_PROC_BROWSER_TEST_F( + WebAppIntegration, + WAI_32FileHandlerNoShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar) { + // Test contents are generated by script. Please do not modify! + // See `docs/webapps/why-is-this-test-failing.md` or + // `docs/webapps/integration-testing-framework` for more info. + // Sheriffs: Disabling this test is supported. + helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, + WindowOptions::kBrowser, InstallMode::kWebApp); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); +} + +IN_PROC_BROWSER_TEST_F( + WebAppIntegration, + WAI_29FileHandlerWindowed_118FileHandlerFoo_118FileHandlerBar) { + // Test contents are generated by script. Please do not modify! + // See `docs/webapps/why-is-this-test-failing.md` or + // `docs/webapps/integration-testing-framework` for more info. + // Sheriffs: Disabling this test is supported. + helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kWindowed); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); + helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); +} + +IN_PROC_BROWSER_TEST_F( + WebAppIntegration, WAI_32StandaloneNoShortcutWindowedWebApp_12Standalone_101Standalone_111Standalone) { // Test contents are generated by script. Please do not modify! // See `docs/webapps/why-is-this-test-failing.md` or
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_win_linux.cc b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_win_linux.cc index b4dcd7f..b7e2cfb 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_win_linux.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_browsertest_win_linux.cc
@@ -11,28 +11,6 @@ using WebAppIntegration = WebAppIntegrationTest; // Manual tests: -IN_PROC_BROWSER_TEST_F(WebAppIntegration, CheckLaunchFileExpectDialog) { - helper_.InstallMenuOption(InstallableSite::kFileHandler); - helper_.ClosePwa(); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); - helper_.CheckWindowCreated(); -} - -IN_PROC_BROWSER_TEST_F(WebAppIntegration, CheckLaunchFileExpectNoDialog_Allow) { - helper_.InstallOmniboxIcon(InstallableSite::kFileHandler); - helper_.ClosePwa(); - // Open the file and set AskAgainOption to kRemember. - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kRemember); - helper_.CheckWindowCreated(); - // Open the file again. - helper_.LaunchFileExpectNoDialog(Site::kFileHandler, - FilesOptions::kOneFooFile); - helper_.CheckWindowCreated(); -} // Generated tests: @@ -341,747 +319,5 @@ helper_.CheckWindowCreated(); } -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerWindowed_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kWindowed); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerWindowed_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleFooFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kWindowed); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleFooFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerWindowed_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneBarFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kWindowed); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneBarFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerWindowed_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleBarFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kWindowed); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleBarFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerWindowed_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowRemember_121FileHandlerOneFooFile) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kWindowed); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kRemember); - helper_.LaunchFileExpectNoDialog(Site::kFileHandler, - FilesOptions::kOneFooFile); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerWindowed_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyAskAgain_127_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kWindowed); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kAskAgain); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerWindowed_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyRemember_127_122FileHandlerFoo_122FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kWindowed); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kRemember); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerBrowser_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kBrowser); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerBrowser_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleFooFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kBrowser); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleFooFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerBrowser_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneBarFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kBrowser); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneBarFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerBrowser_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleBarFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kBrowser); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleBarFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerBrowser_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowRemember_121FileHandlerOneFooFile) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kBrowser); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kRemember); - helper_.LaunchFileExpectNoDialog(Site::kFileHandler, - FilesOptions::kOneFooFile); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerBrowser_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyAskAgain_127_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kBrowser); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kAskAgain); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_29FileHandlerBrowser_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyRemember_127_122FileHandlerFoo_122FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.CreateShortcut(Site::kFileHandler, WindowOptions::kBrowser); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kRemember); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleFooFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleFooFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneBarFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneBarFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleBarFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleBarFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowRemember_121FileHandlerOneFooFile) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kRemember); - helper_.LaunchFileExpectNoDialog(Site::kFileHandler, - FilesOptions::kOneFooFile); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyAskAgain_127_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kAskAgain); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyRemember_127_122FileHandlerFoo_122FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kRemember); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleFooFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleFooFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneBarFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneBarFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleBarFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleBarFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowRemember_121FileHandlerOneFooFile) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kRemember); - helper_.LaunchFileExpectNoDialog(Site::kFileHandler, - FilesOptions::kOneFooFile); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyAskAgain_127_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kAskAgain); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerWithShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyRemember_127_122FileHandlerFoo_122FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kWithShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kRemember); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleFooFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleFooFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneBarFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneBarFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleBarFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleBarFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowRemember_121FileHandlerOneFooFile) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kRemember); - helper_.LaunchFileExpectNoDialog(Site::kFileHandler, - FilesOptions::kOneFooFile); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyAskAgain_127_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kAskAgain); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutWindowedWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyRemember_127_122FileHandlerFoo_122FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kWindowed, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kRemember); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleFooFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleFooFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneBarFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneBarFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerMultipleBarFilesAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog( - Site::kFileHandler, FilesOptions::kMultipleBarFiles, - AllowDenyOptions::kAllow, AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowRemember_121FileHandlerOneFooFile) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kRemember); - helper_.LaunchFileExpectNoDialog(Site::kFileHandler, - FilesOptions::kOneFooFile); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyAskAgain_127_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileAllowAskAgain) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kAskAgain); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kAllow, - AskAgainOptions::kAskAgain); -} - -IN_PROC_BROWSER_TEST_F( - WebAppIntegration, - WAI_32FileHandlerNoShortcutBrowserWebApp_118FileHandlerFoo_118FileHandlerBar_120FileHandlerOneFooFileDenyRemember_127_122FileHandlerFoo_122FileHandlerBar) { - // Test contents are generated by script. Please do not modify! - // See `docs/webapps/why-is-this-test-failing.md` or - // `docs/webapps/integration-testing-framework` for more info. - // Sheriffs: Disabling this test is supported. - helper_.InstallPolicyApp(Site::kFileHandler, ShortcutOptions::kNoShortcut, - WindowOptions::kBrowser, InstallMode::kWebApp); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteHandlesFile(Site::kFileHandler, FileExtension::kBar); - helper_.LaunchFileExpectDialog(Site::kFileHandler, FilesOptions::kOneFooFile, - AllowDenyOptions::kDeny, - AskAgainOptions::kRemember); - helper_.CheckWindowNotCreated(); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kFoo); - helper_.CheckSiteNotHandlesFile(Site::kFileHandler, FileExtension::kBar); -} - } // namespace } // namespace web_app::integration_tests
diff --git a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc index 073a55a..ed367f1 100644 --- a/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc +++ b/chrome/browser/ui/views/web_apps/web_app_integration_test_driver.cc
@@ -274,9 +274,7 @@ .relative_manifest_id = "webapps_integration/file_handler/basic.html", .app_name = "File Handler", .wco_not_enabled_title = u"File Handler", - .icon_color = SK_ColorBLACK, - .alternate_titles = {"File Handler - Text Handler", - "File Handler - Image Handler"}}}, + .icon_color = SK_ColorBLACK}}, {Site::kNoServiceWorker, {.relative_url = "/webapps_integration/site_no_service_worker/basic.html", .relative_manifest_id = @@ -1186,10 +1184,10 @@ FileHandlerLaunchDialogView::SetDefaultRememberSelectionForTesting( ask_again == AskAgainOptions::kRemember); - base::RunLoop run_loop; - web_app::startup::SetStartupDoneCallbackForTesting(run_loop.QuitClosure()); LaunchFile(site, files_options); + BrowserAddedWaiter browser_added_waiter; + // Check the file handling dialog shows up. views::Widget* widget = waiter.WaitIfNeededAndGet(); ASSERT_TRUE(widget != nullptr); @@ -1208,7 +1206,12 @@ widget->CloseWithReason(close_reason); destroyed_waiter.Wait(); - run_loop.Run(); + if (allow_deny == AllowDenyOptions::kAllow) { + browser_added_waiter.Wait(); + app_browser_ = browser_added_waiter.browser_added(); + ActivateBrowserAndWait(app_browser_); + EXPECT_EQ(app_browser()->app_controller()->app_id(), app_id); + } AfterStateChangeAction(); } @@ -1217,15 +1220,17 @@ FilesOptions files_options) { BeforeStateChangeAction(__FUNCTION__); AppId app_id = GetAppIdBySiteMode(site); - base::RunLoop run_loop; - web_app::startup::SetStartupDoneCallbackForTesting(run_loop.QuitClosure()); + BrowserAddedWaiter browser_added_waiter; LaunchFile(site, files_options); // If the user previously denied access to open files with this app, a window // is still opened for the app. The only difference is that no files would // have been passed to the app. Either way, we should always wait for a - // window / browser to be added. - run_loop.Run(); + // browser to be added. + browser_added_waiter.Wait(); + app_browser_ = browser_added_waiter.browser_added(); + ActivateBrowserAndWait(app_browser_); + EXPECT_EQ(app_browser()->app_controller()->app_id(), app_id); AfterStateChangeAction(); }
diff --git a/chrome/browser/ui/webui/app_home/app_home.mojom b/chrome/browser/ui/webui/app_home/app_home.mojom index 5d3fb2c..d551dd0 100644 --- a/chrome/browser/ui/webui/app_home/app_home.mojom +++ b/chrome/browser/ui/webui/app_home/app_home.mojom
@@ -29,6 +29,8 @@ UninstallApp(string app_id); // Open app’s site setting page. ShowAppSettings(string app_id); + // Create shortcut link for app. + CreateAppShortcut(string app_id) => (); }; // The `Page` interface is used for sending mojom action messsage
diff --git a/chrome/browser/ui/webui/app_home/app_home_page_handler.cc b/chrome/browser/ui/webui/app_home/app_home_page_handler.cc index 7fb56f99..761ab30 100644 --- a/chrome/browser/ui/webui/app_home/app_home_page_handler.cc +++ b/chrome/browser/ui/webui/app_home/app_home_page_handler.cc
@@ -3,11 +3,16 @@ // found in the LICENSE file. #include "chrome/browser/ui/webui/app_home/app_home_page_handler.h" +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/functional/callback_helpers.h" +#include "base/metrics/histogram_functions.h" #include "chrome/browser/apps/app_service/app_icon/app_icon_source.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_ui_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/apps/app_info_dialog.h" +#include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/chrome_pages.h" @@ -84,6 +89,35 @@ base::DoNothing()); } +void AppHomePageHandler::CreateWebAppShortcut(const std::string& app_id, + base::OnceClosure done) { + Browser* browser = GetCurrentBrowser(); + chrome::ShowCreateChromeAppShortcutsDialog( + browser->window()->GetNativeWindow(), browser->profile(), app_id, + base::BindOnce( + [](base::OnceClosure done, bool success) { + base::UmaHistogramBoolean( + "Apps.AppInfoDialog.CreateWebAppShortcutSuccess", success); + std::move(done).Run(); + }, + std::move(done))); +} + +void AppHomePageHandler::CreateExtensionAppShortcut( + const extensions::Extension* extension, + base::OnceClosure done) { + Browser* browser = GetCurrentBrowser(); + chrome::ShowCreateChromeAppShortcutsDialog( + browser->window()->GetNativeWindow(), browser->profile(), extension, + base::BindOnce( + [](base::OnceClosure done, bool success) { + base::UmaHistogramBoolean( + "Apps.AppInfoDialog.CreateExtensionShortcutSuccess", success); + std::move(done).Run(); + }, + std::move(done))); +} + app_home::mojom::AppInfoPtr AppHomePageHandler::CreateAppInfoPtrFromWebApp( const web_app::AppId& app_id) { auto& registrar = web_app_provider_->registrar(); @@ -290,4 +324,22 @@ } } +void AppHomePageHandler::CreateAppShortcut(const std::string& app_id, + CreateAppShortcutCallback callback) { + if (web_app_provider_->registrar().IsInstalled(app_id) && + !IsYoutubeExtension(app_id)) { + CreateWebAppShortcut(app_id, std::move(callback)); + return; + } + + const Extension* extension = + extensions::ExtensionRegistry::Get(extension_service_->profile()) + ->GetExtensionById(app_id, + extensions::ExtensionRegistry::ENABLED | + extensions::ExtensionRegistry::DISABLED | + extensions::ExtensionRegistry::TERMINATED); + if (extension) + CreateExtensionAppShortcut(extension, std::move(callback)); +} + } // namespace webapps
diff --git a/chrome/browser/ui/webui/app_home/app_home_page_handler.h b/chrome/browser/ui/webui/app_home/app_home_page_handler.h index 301aefc40..a5d5303 100644 --- a/chrome/browser/ui/webui/app_home/app_home_page_handler.h +++ b/chrome/browser/ui/webui/app_home/app_home_page_handler.h
@@ -66,6 +66,8 @@ void GetApps(GetAppsCallback callback) override; void UninstallApp(const std::string& app_id) override; void ShowAppSettings(const std::string& app_id) override; + void CreateAppShortcut(const std::string& app_id, + CreateAppShortcutCallback callback) override; private: Browser* GetCurrentBrowser(); @@ -83,6 +85,9 @@ void ShowWebAppSettings(const std::string& app_id); void ShowExtensionAppSettings(const extensions::Extension* extension); + void CreateWebAppShortcut(const std::string& app_id, base::OnceClosure done); + void CreateExtensionAppShortcut(const extensions::Extension* extension, + base::OnceClosure done); void UninstallWebApp(const std::string& web_app_id); void UninstallExtensionApp(const extensions::Extension* extension); void FillWebAppInfoList(std::vector<app_home::mojom::AppInfoPtr>* result);
diff --git a/chrome/browser/ui/webui/app_home/app_home_page_handler_browsertest.cc b/chrome/browser/ui/webui/app_home/app_home_page_handler_browsertest.cc index 1dfe6ab..c0330b5 100644 --- a/chrome/browser/ui/webui/app_home/app_home_page_handler_browsertest.cc +++ b/chrome/browser/ui/webui/app_home/app_home_page_handler_browsertest.cc
@@ -12,15 +12,20 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/webui/app_home/app_home.mojom.h" #include "chrome/browser/ui/webui/app_home/mock_app_home_page.h" +#include "chrome/browser/web_applications/os_integration/web_app_shortcut.h" #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" #include "chrome/common/webui_url_constants.h" #include "chrome/test/base/in_process_browser_test.h" +#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" #include "content/public/test/test_web_ui.h" #include "extensions/browser/extension_dialog_auto_confirm.h" #include "extensions/common/extension_builder.h" #include "testing/gmock/include/gmock/gmock.h" +#include "ui/views/test/dialog_test.h" +#include "ui/views/widget/any_widget_observer.h" +#include "ui/views/widget/widget.h" using web_app::AppId; using GetAppsCallback = @@ -34,6 +39,30 @@ constexpr char kTestManifestUrl[] = "https://www.example.com/manifest.json"; constexpr char kTestAppName[] = "Test App"; +#if !BUILDFLAG(IS_MAC) +void FlushShortcutTasks() { + // Execute the UI thread task runner before and after the shortcut task runner + // to ensure that tasks get to the shortcut runner, and then any scheduled + // replies on the UI thread get run. + { + base::RunLoop loop; + content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, loop.QuitClosure()); + loop.Run(); + } + { + base::RunLoop loop; + web_app::internals::GetShortcutIOTaskRunner()->PostTask(FROM_HERE, + loop.QuitClosure()); + loop.Run(); + } + { + base::RunLoop loop; + content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, loop.QuitClosure()); + loop.Run(); + } +} +#endif + class TestAppHomePageHandler : public AppHomePageHandler { public: TestAppHomePageHandler(content::WebUI* web_ui, @@ -329,4 +358,54 @@ GURL url = browser()->tab_strip_model()->GetActiveWebContents()->GetURL(); EXPECT_EQ(url, GURL(chrome::kChromeUIWebAppSettingsURL + installed_app_id)); } + +IN_PROC_BROWSER_TEST_F(AppHomePageHandlerTest, CreateWebAppShortcut) { + std::unique_ptr<TestAppHomePageHandler> page_handler = + GetAppHomePageHandler(); + + // First, install a test web app for test. + EXPECT_CALL(page_, AddApp(MatchAppName(kTestAppName))); + AppId installed_app_id = InstallTestWebApp(); + page_handler->Wait(); + +#if BUILDFLAG(IS_MAC) + base::RunLoop loop; + page_handler->CreateAppShortcut(installed_app_id, loop.QuitClosure()); + loop.Run(); +#else + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "CreateChromeApplicationShortcutView"); + page_handler->CreateAppShortcut(installed_app_id, base::DoNothing()); + FlushShortcutTasks(); + views::Widget* widget = waiter.WaitIfNeededAndGet(); + ASSERT_TRUE(widget != nullptr); + views::test::AcceptDialog(widget); +#endif +} + +IN_PROC_BROWSER_TEST_F(AppHomePageHandlerTest, CreateExtensionAppShortcut) { + std::unique_ptr<TestAppHomePageHandler> page_handler = + GetAppHomePageHandler(); + + // First, install a test extension app for test. + EXPECT_CALL(page_, AddApp(MatchAppName(kTestAppName))); + scoped_refptr<const extensions::Extension> extension = + InstallTestExtensionApp(); + page_handler->Wait(); + +#if BUILDFLAG(IS_MAC) + base::RunLoop loop; + page_handler->CreateAppShortcut(extension->id(), loop.QuitClosure()); + loop.Run(); +#else + views::NamedWidgetShownWaiter waiter(views::test::AnyWidgetTestPasskey{}, + "CreateChromeApplicationShortcutView"); + page_handler->CreateAppShortcut(extension->id(), base::DoNothing()); + FlushShortcutTasks(); + views::Widget* widget = waiter.WaitIfNeededAndGet(); + ASSERT_TRUE(widget != nullptr); + views::test::AcceptDialog(widget); +#endif +} + } // namespace webapps
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom index 3b03743..c8cbc0e 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload.mojom
@@ -11,6 +11,8 @@ kSetUpOneDrive, kUploadToGoogleDrive, kUploadToOneDrive, + kConfirmOrUploadToGoogleDrive, + kConfirmOrUploadToOneDrive, }; // Options for which sub-page/flow we want to show. @@ -21,6 +23,10 @@ kOneDriveSetup, // Set up Google Drive (one-page confirmation screen). kGoogleDriveSetup, + // Confirm that the user wants to move the file to OneDrive. + kMoveConfirmationOneDrive, + // Confirm that the user wants to move the file to Google Drive. + kMoveConfirmationGoogleDrive, }; // Contains the arguments used to set up the dialog. @@ -55,4 +61,8 @@ // Set Office as the default file handler for office files and mark the // setup as complete so that it does not need to be started again. SetOfficeAsDefaultHandler(); + + // Set the preference for whether we should always move office files without + // asking the user first. + SetAlwaysMoveOfficeFiles(bool always_move); };
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc index 1db5928..81bf8c7 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.cc
@@ -78,6 +78,23 @@ } } +void ConfirmMoveOrStartUpload( + Profile* profile, + const std::vector<storage::FileSystemURL>& file_urls, + const CloudProvider cloud_provider) { + if (file_manager::file_tasks::AlwaysMoveOfficeFiles(profile)) { + return StartUpload(profile, file_urls, cloud_provider); + } + + if (cloud_provider == CloudProvider::kGoogleDrive) { + CloudUploadDialog::Show(profile, file_urls, + mojom::DialogPage::kMoveConfirmationGoogleDrive); + } else if (cloud_provider == CloudProvider::kOneDrive) { + CloudUploadDialog::Show(profile, file_urls, + mojom::DialogPage::kMoveConfirmationOneDrive); + } +} + void OnDialogComplete(Profile* profile, const std::vector<storage::FileSystemURL>& file_urls, const std::string& action) { @@ -86,7 +103,7 @@ using file_manager::file_tasks::SetPowerPointFileHandler; using file_manager::file_tasks::SetWordFileHandler; - if (action == kUserActionUploadToGoogleDrive) { + if (action == kUserActionConfirmOrUploadToGoogleDrive) { SetWordFileHandler(profile, file_manager::file_tasks::kActionIdWebDriveOfficeWord); SetExcelFileHandler(profile, @@ -94,9 +111,13 @@ SetPowerPointFileHandler( profile, file_manager::file_tasks::kActionIdWebDriveOfficePowerPoint); SetOfficeSetupComplete(profile); + ConfirmMoveOrStartUpload(profile, file_urls, CloudProvider::kGoogleDrive); + } else if (action == kUserActionConfirmOrUploadToOneDrive) { + // Default handlers have already been set by this point for Office/OneDrive. + ConfirmMoveOrStartUpload(profile, file_urls, CloudProvider::kOneDrive); + } else if (action == kUserActionUploadToGoogleDrive) { StartUpload(profile, file_urls, CloudProvider::kGoogleDrive); } else if (action == kUserActionUploadToOneDrive) { - // Default handlers have already been set by this point for Office/OneDrive. StartUpload(profile, file_urls, CloudProvider::kOneDrive); } else if (action == kUserActionSetUpGoogleDrive) { CloudUploadDialog::Show(profile, file_urls, @@ -126,7 +147,7 @@ if (empty_selection) { return false; } - StartUpload(profile, file_urls, cloud_provider); + ConfirmMoveOrStartUpload(profile, file_urls, cloud_provider); return true; } @@ -200,6 +221,9 @@ const int kDialogWidthForDriveSetup = 512; const int kDialogHeightForDriveSetup = 220; + +const int kDialogWidthForMoveConfirmation = 448; +const int kDialogHeightForMoveConfirmation = 228; } // namespace void CloudUploadDialog::GetDialogSize(gfx::Size* size) const { @@ -219,6 +243,12 @@ size->set_height(kDialogHeightForDriveSetup); return; } + case mojom::DialogPage::kMoveConfirmationGoogleDrive: + case mojom::DialogPage::kMoveConfirmationOneDrive: { + size->set_width(kDialogWidthForMoveConfirmation); + size->set_height(kDialogHeightForMoveConfirmation); + return; + } } }
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h index bee2ea6..eb8c354 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_dialog.h
@@ -22,6 +22,10 @@ const char kUserActionSetUpOneDrive[] = "setup-onedrive"; const char kUserActionUploadToGoogleDrive[] = "upload-drive"; const char kUserActionUploadToOneDrive[] = "upload-onedrive"; +const char kUserActionConfirmOrUploadToGoogleDrive[] = + "confirm-or-upload-google-drive"; +const char kUserActionConfirmOrUploadToOneDrive[] = + "confirm-or-upload-onedrive"; // Either OneDrive for the Office PWA or Drive for Drive Web editing. enum class CloudProvider {
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc index d35ba59..0a5b085 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.cc
@@ -71,4 +71,8 @@ file_manager::file_tasks::SetOfficeSetupComplete(profile_); } +void CloudUploadPageHandler::SetAlwaysMoveOfficeFiles(bool always_move) { + file_manager::file_tasks::SetAlwaysMoveOfficeFiles(profile_, always_move); +} + } // namespace ash::cloud_upload
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.h b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.h index 92f69a0..517e614 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.h +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_page_handler.h
@@ -43,6 +43,7 @@ void IsOfficePWAInstalled(IsOfficePWAInstalledCallback callback) override; void RespondAndClose(mojom::UserAction action) override; void SetOfficeAsDefaultHandler() override; + void SetAlwaysMoveOfficeFiles(bool always_move) override; private: Profile* profile_;
diff --git a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_ui.cc b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_ui.cc index 26d20db7..cd21bda 100644 --- a/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_ui.cc +++ b/chrome/browser/ui/webui/ash/cloud_upload/cloud_upload_ui.cc
@@ -79,6 +79,12 @@ case mojom::UserAction::kUploadToOneDrive: args.Append(kUserActionUploadToOneDrive); break; + case mojom::UserAction::kConfirmOrUploadToGoogleDrive: + args.Append(kUserActionConfirmOrUploadToGoogleDrive); + break; + case mojom::UserAction::kConfirmOrUploadToOneDrive: + args.Append(kUserActionConfirmOrUploadToOneDrive); + break; } ui::MojoWebDialogUI::CloseDialog(args); }
diff --git a/chrome/browser/ui/webui/ash/drive_internals_ui.cc b/chrome/browser/ui/webui/ash/drive_internals_ui.cc index af240d73..ab7133f 100644 --- a/chrome/browser/ui/webui/ash/drive_internals_ui.cc +++ b/chrome/browser/ui/webui/ash/drive_internals_ui.cc
@@ -291,6 +291,10 @@ weak_ptr_factory_.GetWeakPtr(), drivefs::mojom::MirrorPathStatus::kStop)); web_ui()->RegisterMessageCallback( + "setBulkPinningEnabled", + base::BindRepeating(&DriveInternalsWebUIHandler::SetBulkPinningEnabled, + weak_ptr_factory_.GetWeakPtr())); + web_ui()->RegisterMessageCallback( "enableTracing", base::BindRepeating(&DriveInternalsWebUIHandler::SetTracingEnabled, weak_ptr_factory_.GetWeakPtr(), true)); @@ -369,6 +373,7 @@ UpdateDriveDebugSection(); UpdateMirrorSyncSection(); + UpdateBulkPinningSection(); // When the drive-internals page is reloaded by the reload key, the page // content is recreated, but this WebUI object is not (instead, OnPageLoaded @@ -580,6 +585,19 @@ base::Value(drive::FileErrorToString(status))); } + void UpdateBulkPinningSection() { + if (!features::IsDriveFsBulkPinningEnabled()) { + SetSectionEnabled("bulk-pinning-section", false); + return; + } + + SetSectionEnabled("bulk-pinning-section", true); + + bool bulk_pinning_enabled = profile()->GetPrefs()->GetBoolean( + drive::prefs::kDriveFsBulkPinningEnabled); + MaybeCallJavascript("updateBulkPinning", base::Value(bulk_pinning_enabled)); + } + // Called when GetDeveloperMode() is complete. void OnGetDeveloperMode(bool enabled) { developer_mode_ = enabled; @@ -771,6 +789,21 @@ } } + void SetBulkPinningEnabled(const base::Value::List& args) { + AllowJavascript(); + drive::DriveIntegrationService* integration_service = + GetIntegrationService(); + if (!integration_service) { + return; + } + + if (args.size() == 1 && args[0].is_bool()) { + bool enabled = args[0].GetBool(); + profile()->GetPrefs()->SetBoolean( + drive::prefs::kDriveFsBulkPinningEnabled, enabled); + } + } + // Called when the "Startup Arguments" field on the page is submitted. void SetStartupArguments(const base::Value::List& args) { AllowJavascript();
diff --git a/chrome/browser/ui/webui/downloads/BUILD.gn b/chrome/browser/ui/webui/downloads/BUILD.gn index 279fd0e..0bb8b1c 100644 --- a/chrome/browser/ui/webui/downloads/BUILD.gn +++ b/chrome/browser/ui/webui/downloads/BUILD.gn
@@ -9,4 +9,5 @@ mojom("mojo_bindings") { sources = [ "downloads.mojom" ] webui_module_path = "/" + use_typescript_sources = true }
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc index 0edb7b2..7c09a90 100644 --- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -2005,8 +2005,6 @@ IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_PRIMARY_LABEL}, {"safetyCheckExtensionsButtonAriaLabel", IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BUTTON_ARIA_LABEL}, - {"safetyCheckNotificationPermissionReviewSecondaryLabel", - IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_SECONDARY_LABEL}, {"safetyCheckNotificationPermissionReviewIgnoredToastLabel", IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_IGNORED_TOAST_LABEL}, {"safetyCheckNotificationPermissionReviewBlockedToastLabel", @@ -2035,6 +2033,8 @@ IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSION_REVIEW_BLOCK_ALL_LABEL}, {"safetyCheckUnusedSitePermissionsHeaderAriaLabel", IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_HEADER_ARIA_LABEL}, + {"safetyCheckNotificationPermissionReviewButtonAriaLabel", + IDS_SETTINGS_SAFETY_CHECK_NOTIFICATION_PERMISSIONS_REVIEW_BUTTON_ARIA_LABEL}, #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) {"safetyCheckChromeCleanerPrimaryLabel", IDS_SETTINGS_SAFETY_CHECK_CHROME_CLEANER_PRIMARY_LABEL},
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc index 3570e83..248787a7 100644 --- a/chrome/browser/ui/webui/settings/settings_ui.cc +++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -406,6 +406,9 @@ plural_string_handler->AddLocalizedString( "safetyCheckUnusedSitePermissionsHeaderLabel", IDS_SETTINGS_SAFETY_CHECK_UNUSED_SITE_PERMISSIONS_HEADER_LABEL); + plural_string_handler->AddLocalizedString( + "safetyCheckNotificationPermissionReviewSecondaryLabel", + IDS_SETTINGS_SAFETY_CHECK_REVIEW_NOTIFICATION_PERMISSIONS_SECONDARY_LABEL); web_ui->AddMessageHandler(std::move(plural_string_handler)); // Add the metrics handler to write uma stats.
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 943fd1f..c841b63 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
@@ -143,13 +143,9 @@ return; } -#if BUILDFLAG(IS_CHROMEOS) - // On ChromeOS, we only verify integrity at install-time. On other OSes, - // we verify integrity once per session. - std::move(integrity_callback) - .Run(SignedWebBundleReader::SignatureVerificationAction:: - ContinueAndSkipSignatureVerification()); -#else + // TODO(crbug.com/1366309): On ChromeOS, we should only verify signatures at + // install-time. Until this is implemented, we will verify signatures on + // ChromeOS once per session. if (verified_files_.contains(web_bundle_path)) { // If we already verified the signatures of this Signed Web Bundle during // the current browser session, we trust that the Signed Web Bundle has not @@ -162,7 +158,6 @@ .Run(SignedWebBundleReader::SignatureVerificationAction:: ContinueAndVerifySignatures()); } -#endif } void IsolatedWebAppReaderRegistry::OnIntegrityBlockAndMetadataRead(
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 55893a5..cc980d8b 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
@@ -355,11 +355,7 @@ EXPECT_EQ(result->head()->response_code, 200); } -#if BUILDFLAG(IS_CHROMEOS) - EXPECT_EQ(num_signature_verifications, 0ul); -#else EXPECT_EQ(num_signature_verifications, 1ul); -#endif // Verify that the cache cleanup timer has started. EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 1ul) @@ -380,11 +376,7 @@ EXPECT_EQ(result->head()->response_code, 200); } -#if BUILDFLAG(IS_CHROMEOS) - EXPECT_EQ(num_signature_verifications, 0ul); -#else EXPECT_EQ(num_signature_verifications, 1ul); -#endif // Verify that the cache cleanup timer is still running. EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 1ul) @@ -417,13 +409,9 @@ EXPECT_EQ(result->head()->response_code, 200); } -#if BUILDFLAG(IS_CHROMEOS) - EXPECT_EQ(num_signature_verifications, 0ul); -#else // Signatures should not have been verified again, since we only verify them // once per session per file path. EXPECT_EQ(num_signature_verifications, 1ul); -#endif // Verify that the cache cleanup timer has started again. EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 1ul) @@ -543,23 +531,6 @@ FulfillIntegrityBlock(); -#if BUILDFLAG(IS_CHROMEOS) - // On ChromeOS, signatures are only verified at installation-time, thus the - // `FakeSignatureVerifier` set up above will never be called. - // TODO(crbug.com/1366309): Make sure signatures are actually verified during - // installation once installation is implemented. - FulfillMetadata(); - FulfillResponse(resource_request); - - ReadResult result = read_response_future.Take(); - ASSERT_TRUE(result.has_value()) << result.error().message; - - histogram_tester.ExpectBucketCount( - "WebApp.Isolated.ReadIntegrityBlockAndMetadataStatus", - IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus:: - kSuccess, - 1); -#else ReadResult result = read_response_future.Take(); ASSERT_FALSE(result.has_value()); EXPECT_EQ(result.error().type, @@ -573,7 +544,6 @@ IsolatedWebAppReaderRegistry::ReadIntegrityBlockAndMetadataStatus:: kSignatureVerificationError, 1); -#endif // BUILDFLAG(IS_CHROMEOS) } INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/web_applications/web_app_icon_downloader_unittest.cc b/chrome/browser/web_applications/web_app_icon_downloader_unittest.cc index 2aaab132..8d1a913 100644 --- a/chrome/browser/web_applications/web_app_icon_downloader_unittest.cc +++ b/chrome/browser/web_applications/web_app_icon_downloader_unittest.cc
@@ -411,10 +411,9 @@ class WebAppIconDownloaderPrerenderTest : public WebAppIconDownloaderTest { public: WebAppIconDownloaderPrerenderTest() { - scoped_feature_list_.InitWithFeatures( - {blink::features::kPrerender2}, + scoped_feature_list_.InitAndDisableFeature( // This feature is to run test on any bot. - {blink::features::kPrerender2MemoryControls}); + blink::features::kPrerender2MemoryControls); } private:
diff --git a/chrome/browser/webauthn/authenticator_request_scheduler_unittest.cc b/chrome/browser/webauthn/authenticator_request_scheduler_unittest.cc index 2d82bdd..5e428607d 100644 --- a/chrome/browser/webauthn/authenticator_request_scheduler_unittest.cc +++ b/chrome/browser/webauthn/authenticator_request_scheduler_unittest.cc
@@ -86,11 +86,10 @@ : public AuthenticatorRequestSchedulerTest { public: AuthenticatorRequestSchedulerPrerenderTest() { - scoped_feature_list_.InitWithFeatures( - {blink::features::kPrerender2}, + scoped_feature_list_.InitAndDisableFeature( // Disable the memory requirement of Prerender2 so the test can run on // any bot. - {blink::features::kPrerender2MemoryControls}); + blink::features::kPrerender2MemoryControls); } ~AuthenticatorRequestSchedulerPrerenderTest() override = default;
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index ba0b400..a64800d 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1669226354-3aba619386ea79bbf76dfcf352f4c07cc3e891b2.profdata +chrome-linux-main-1669269205-374bccde97d17507fb132bd7d2e1e6c948bbcec9.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index d929044..628c1933 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1669226354-a033b34198972286de177e47c7f34244d10f7533.profdata +chrome-mac-arm-main-1669269205-a70107538c807752a4af0982ab148bfe3fe0e9c2.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 6e38fe6..017bfac 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1669226354-d808bb044fa2957e0b8096006c2631ccb72a9d22.profdata +chrome-mac-main-1669288813-e77f895892d143c17ddb81e03bf475645e7d23c5.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index 381b74f..284b131 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1669215337-f8119f6a2c27dea3d944627c637d7a6359d27ba4.profdata +chrome-win32-main-1669288813-c6197658b6949a6abafcd9e81bd33a9d52f20571.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 267f6d3a..2cf01ff2 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1669226354-2dc46fdc1f9ddcef2c0e19d351d1c4d52f1b0d50.profdata +chrome-win64-main-1669280396-20922a4e7dbdb60a960caeb9517c8a24c3f86f40.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn index e645c4b..9e21641 100644 --- a/chrome/common/BUILD.gn +++ b/chrome/common/BUILD.gn
@@ -51,6 +51,7 @@ "ENABLE_WEBUI_CERTIFICATE_VIEWER=$enable_webui_certificate_viewer", "ENABLE_WEBUI_TAB_STRIP=$enable_webui_tab_strip", "OPTIMIZE_WEBUI=$optimize_webui", + "ENABLE_BOUND_SESSION_CREDENTIALS=$enable_bound_session_credentials", ] }
diff --git a/chrome/common/extensions/api/extension.json b/chrome/common/extensions/api/extension.json index 4799d4c..a64ee51 100644 --- a/chrome/common/extensions/api/extension.json +++ b/chrome/common/extensions/api/extension.json
@@ -89,7 +89,7 @@ "type": { "$ref": "ViewType", "optional": true, - "description": "The type of view to get. If omitted, returns all views (including background pages and tabs). Valid values: 'tab', 'notification', 'popup'." + "description": "The type of view to get. If omitted, returns all views (including background pages and tabs)." }, "windowId": { "type": "integer",
diff --git a/chrome/common/extensions/api/input_method_private.json b/chrome/common/extensions/api/input_method_private.json index f1b6baa3..6d7ebdf 100644 --- a/chrome/common/extensions/api/input_method_private.json +++ b/chrome/common/extensions/api/input_method_private.json
@@ -314,22 +314,6 @@ } ] }, { - "name": "notifyImeMenuItemActivated", - "type": "function", - "description": "Fires the input.ime.onMenuItemActivated event.", - "parameters": [ - { - "name": "engineID", - "type": "string", - "description": "ID of the engine to use." - }, - { - "name": "name", - "type": "string", - "description": "Name of the MenuItem which was activated" - } - ] - }, { "name": "showInputView", "type": "function", "description": "Shows the input view window. If the input view window is already shown, this function will do nothing.",
diff --git a/chrome/common/features.gni b/chrome/common/features.gni index 1c172ac..7aa0949 100644 --- a/chrome/common/features.gni +++ b/chrome/common/features.gni
@@ -72,6 +72,10 @@ # Enables the webui certificate viewer dialog. enable_webui_certificate_viewer = toolkit_views + # Compile time flag for bound session Credentials. + # Warning: This must not be enabled in official builds. + enable_bound_session_credentials = false + # optimize_webui was moved to ui/base/ui_features.gni }
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index dde9ee2..49ba1092 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -1942,6 +1942,9 @@ // Whether the office files setup flow has ever been completed by the user. const char kOfficeSetupComplete[] = "filebrowser.office.setup_complete"; + +// Whether we should always move office files without prompting the user first. +const char kOfficeFilesAlwaysMove[] = "filebrowser.office.always_move"; #endif // A flag to enable/disable the Shared Clipboard feature which enables users to
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 77bceeb..10760b1 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -637,6 +637,7 @@ #if BUILDFLAG(IS_CHROMEOS_ASH) extern const char kDefaultHandlersForFileExtensions[]; extern const char kOfficeSetupComplete[]; +extern const char kOfficeFilesAlwaysMove[]; #endif extern const char kSharedClipboardEnabled[];
diff --git a/chrome/common/profiler/unwind_util.cc b/chrome/common/profiler/unwind_util.cc index 0add095..a42ae1f 100644 --- a/chrome/common/profiler/unwind_util.cc +++ b/chrome/common/profiler/unwind_util.cc
@@ -5,6 +5,7 @@ #include "chrome/common/profiler/unwind_util.h" #include <memory> +#include <type_traits> #include <vector> #include "base/android/library_loader/anchor_functions.h" @@ -30,24 +31,41 @@ #define ANDROID_ARM32_UNWINDING_SUPPORTED 0 #endif +#if BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_ARM64) && \ + BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) +#define ANDROID_ARM64_UNWINDING_SUPPORTED 1 +#else +#define ANDROID_ARM64_UNWINDING_SUPPORTED 0 +#endif + +#if ANDROID_ARM32_UNWINDING_SUPPORTED || ANDROID_ARM64_UNWINDING_SUPPORTED +#define ANDROID_UNWINDING_SUPPORTED 1 +#else +#define ANDROID_UNWINDING_SUPPORTED 0 +#endif + +#if ANDROID_UNWINDING_SUPPORTED +#include "chrome/android/modules/stack_unwinder/public/module.h" +#endif // ANDROID_UNWINDING_SUPPORTED + #if ANDROID_ARM32_UNWINDING_SUPPORTED #include "base/android/apk_assets.h" #include "base/files/memory_mapped_file.h" #include "base/profiler/arm_cfi_table.h" -#include "chrome/android/modules/stack_unwinder/public/module.h" - -#if BUILDFLAG(USE_ANDROID_UNWINDER_V2) #include "base/profiler/chrome_unwinder_android_v2.h" -#else -#include "base/profiler/chrome_unwinder_android.h" -#endif +#endif // ANDROID_ARM32_UNWINDING_SUPPORTED +#if ANDROID_ARM64_UNWINDING_SUPPORTED +#include "base/profiler/frame_pointer_unwinder.h" +#endif // ANDROID_ARM64_UNWINDING_SUPPORTED + +#if ANDROID_UNWINDING_SUPPORTED extern "C" { // The address of |__executable_start| is the base address of the executable or // shared library. extern char __executable_start; } -#endif // ANDROID_ARM32_UNWINDING_SUPPORTED +#endif // ANDROID_UNWINDING_SUPPORTED // See `RequestUnwindPrerequisitesInstallation` below. BASE_FEATURE(kInstallAndroidUnwindDfm, @@ -56,8 +74,8 @@ namespace { +// Encapsulates the setup required to create the Chrome unwinder on Android. #if ANDROID_ARM32_UNWINDING_SUPPORTED -#if BUILDFLAG(USE_ANDROID_UNWINDER_V2) class ChromeUnwinderCreator { public: ChromeUnwinderCreator() { @@ -86,40 +104,25 @@ private: base::MemoryMappedFile chrome_cfi_file_; }; -#else // BUILDFLAG(USE_ANDROID_UNWINDER_V2) -// Encapsulates the setup required to create the Chrome unwinder on Android. +#elif ANDROID_ARM64_UNWINDING_SUPPORTED // ANDROID_ARM32_UNWINDING_SUPPORTED class ChromeUnwinderCreator { public: - ChromeUnwinderCreator() { - constexpr char kCfiFileName[] = "assets/unwind_cfi_32"; - constexpr char kSplitName[] = "stack_unwinder"; - - base::MemoryMappedFile::Region cfi_region; - int fd = base::android::OpenApkAsset(kCfiFileName, kSplitName, &cfi_region); - DCHECK_GE(fd, 0); - bool mapped_file_ok = - chrome_cfi_file_.Initialize(base::File(fd), cfi_region); - DCHECK(mapped_file_ok); - chrome_cfi_table_ = base::ArmCFITable::Parse( - {chrome_cfi_file_.data(), chrome_cfi_file_.length()}); - DCHECK(chrome_cfi_table_); - } - - ChromeUnwinderCreator(const ChromeUnwinderCreator&) = delete; - ChromeUnwinderCreator& operator=(const ChromeUnwinderCreator&) = delete; - std::unique_ptr<base::Unwinder> Create() { - return std::make_unique<base::ChromeUnwinderAndroid>( - chrome_cfi_table_.get(), - reinterpret_cast<uintptr_t>(&__executable_start)); + return std::make_unique<base::FramePointerUnwinder>(); } - private: - base::MemoryMappedFile chrome_cfi_file_; - std::unique_ptr<base::ArmCFITable> chrome_cfi_table_; + // Since this class is trivially destructible, it cannot be wrapped in + // `base::NoDestructor`. However, other versions of this class *are* wrapped + // in `base::NoDestructor`. These overloads allow consistently calling member + // functions, regardless of whether a version of this class is wrapped in + // `base::NoDestructor` or not (please see `CreateCoreUnwinders` below for + // more context). + const ChromeUnwinderCreator* operator->() const { return this; } + ChromeUnwinderCreator* operator->() { return this; } }; -#endif // BUILDFLAG(USE_ANDROID_UNWINDER_V2) +#endif // ANDROID_ARM32_UNWINDING_SUPPORTED +#if ANDROID_UNWINDING_SUPPORTED // Encapsulates the setup required to create the Android native unwinder. class NativeUnwinderCreator { public: @@ -146,7 +149,10 @@ static base::NoDestructor<NativeUnwinderCreator> native_unwinder_creator( stack_unwinder_module); - static base::NoDestructor<ChromeUnwinderCreator> chrome_unwinder_creator; + static std::conditional< + std::is_trivially_destructible_v<ChromeUnwinderCreator>, + ChromeUnwinderCreator, base::NoDestructor<ChromeUnwinderCreator>>::type + chrome_unwinder_creator; // Note order matters: the more general unwinder must appear first in the // vector. @@ -176,7 +182,7 @@ return stack_unwinder::Module::IsInstalled(); } }; -#endif // ANDROID_ARM32_UNWINDING_SUPPORTED +#endif // ANDROID_UNWINDING_SUPPORTED } // namespace @@ -188,7 +194,7 @@ if (AreUnwindPrerequisitesAvailable(channel, prerequites_delegate)) { return; } -#if ANDROID_ARM32_UNWINDING_SUPPORTED && defined(OFFICIAL_BUILD) && \ +#if (ANDROID_UNWINDING_SUPPORTED) && defined(OFFICIAL_BUILD) && \ BUILDFLAG(GOOGLE_CHROME_BRANDING) ModuleUnwindPrerequisitesDelegate default_delegate; if (prerequites_delegate == nullptr) { @@ -224,7 +230,7 @@ // prerequisites are always considered to be available for non-Android // platforms. #if BUILDFLAG(IS_ANDROID) -#if ANDROID_ARM32_UNWINDING_SUPPORTED +#if ANDROID_UNWINDING_SUPPORTED #if defined(OFFICIAL_BUILD) && BUILDFLAG(GOOGLE_CHROME_BRANDING) // Sometimes, DFMs can be installed even if not requested by Chrome // explicitly (for instance, in some app stores). Therefore, even if the @@ -241,32 +247,32 @@ prerequites_delegate = &default_delegate; } return prerequites_delegate->AreAvailable(channel); -#else // ANDROID_ARM32_UNWINDING_SUPPORTED +#else // ANDROID_UNWINDING_SUPPORTED return false; -#endif // ANDROID_ARM32_UNWINDING_SUPPORTED +#endif // ANDROID_UNWINDING_SUPPORTED #else // BUILDFLAG(IS_ANDROID) return true; #endif // BUILDFLAG(IS_ANDROID) } -#if ANDROID_ARM32_UNWINDING_SUPPORTED +#if ANDROID_UNWINDING_SUPPORTED stack_unwinder::Module* GetOrLoadModule() { DCHECK(AreUnwindPrerequisitesAvailable(chrome::GetChannel())); static base::NoDestructor<std::unique_ptr<stack_unwinder::Module>> stack_unwinder_module(stack_unwinder::Module::Load()); return stack_unwinder_module.get()->get(); } -#endif // ANDROID_ARM32_UNWINDING_SUPPORTED +#endif // ANDROID_UNWINDING_SUPPORTED base::StackSamplingProfiler::UnwindersFactory CreateCoreUnwindersFactory() { if (!AreUnwindPrerequisitesAvailable(chrome::GetChannel())) { return base::StackSamplingProfiler::UnwindersFactory(); } -#if ANDROID_ARM32_UNWINDING_SUPPORTED +#if ANDROID_UNWINDING_SUPPORTED return base::BindOnce(CreateCoreUnwinders, GetOrLoadModule()); -#else // ANDROID_ARM32_UNWINDING_SUPPORTED +#else // ANDROID_UNWINDING_SUPPORTED return base::StackSamplingProfiler::UnwindersFactory(); -#endif // ANDROID_ARM32_UNWINDING_SUPPORTED +#endif // ANDROID_UNWINDING_SUPPORTED } base::StackSamplingProfiler::UnwindersFactory @@ -274,9 +280,9 @@ if (!AreUnwindPrerequisitesAvailable(chrome::GetChannel())) { return base::StackSamplingProfiler::UnwindersFactory(); } -#if ANDROID_ARM32_UNWINDING_SUPPORTED +#if ANDROID_UNWINDING_SUPPORTED return base::BindOnce(CreateLibunwindstackUnwinders, GetOrLoadModule()); -#else // ANDROID_ARM32_UNWINDING_SUPPORTED +#else // ANDROID_UNWINDING_SUPPORTED return base::StackSamplingProfiler::UnwindersFactory(); -#endif // ANDROID_ARM32_UNWINDING_SUPPORTED +#endif // ANDROID_UNWINDING_SUPPORTED }
diff --git a/chrome/common/profiler/unwind_util_unittest.cc b/chrome/common/profiler/unwind_util_unittest.cc index c1fa0b2..19c8542 100644 --- a/chrome/common/profiler/unwind_util_unittest.cc +++ b/chrome/common/profiler/unwind_util_unittest.cc
@@ -17,6 +17,14 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#if BUILDFLAG(IS_ANDROID) && \ + ((defined(ARCH_CPU_ARMEL) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)) || \ + defined(ARCH_CPU_ARM64)) +#define ANDROID_UNWINDING_SUPPORTED 1 +#else +#define ANDROID_UNWINDING_SUPPORTED 0 +#endif + namespace { using ::testing::_; @@ -110,7 +118,7 @@ {version_info::Channel::STABLE, &false_mock_delegate, false}, {version_info::Channel::UNKNOWN, &false_mock_delegate, false}, -#if defined(ARCH_CPU_ARMEL) && BUILDFLAG(ENABLE_ARM_CFI_TABLE) +#if ANDROID_UNWINDING_SUPPORTED {version_info::Channel::CANARY, &true_mock_delegate, true}, {version_info::Channel::DEV, &true_mock_delegate, true}, {version_info::Channel::BETA, &true_mock_delegate, true}, @@ -125,14 +133,14 @@ {version_info::Channel::STABLE, &true_mock_delegate, true}, {version_info::Channel::UNKNOWN, &true_mock_delegate, true}, #endif // defined(OFFICIAL_BUILD) && BUILDFLAG(GOOGLE_CHROME_BRANDING) -#else // defined(ARCH_CPU_ARMEL) && BUILDFLAG(ENABLE_ARM_CFI_TABLE) - // Unwinding on non-ARM32 platforms is not currently supported for Android. +#else // ANDROID_UNWINDING_SUPPORTED + // Unwinding on any other platforms is not currently supported for Android. {version_info::Channel::CANARY, &true_mock_delegate, false}, {version_info::Channel::DEV, &true_mock_delegate, false}, {version_info::Channel::BETA, &true_mock_delegate, false}, {version_info::Channel::STABLE, &true_mock_delegate, false}, {version_info::Channel::UNKNOWN, &true_mock_delegate, false}, -#endif // defined(ARCH_CPU_ARMEL) && BUILDFLAG(ENABLE_ARM_CFI_TABLE) +#endif // ANDROID_UNWINDING_SUPPORTED #else // BUILDFLAG(IS_ANDROID) // Non-Android platforms' unwinders do not need any specific prerequisites // beyond what is already bundled and available with Chrome. Therefore,
diff --git a/chrome/install_static/BUILD.gn b/chrome/install_static/BUILD.gn index 4a0c972..1de210a 100644 --- a/chrome/install_static/BUILD.gn +++ b/chrome/install_static/BUILD.gn
@@ -28,6 +28,7 @@ public_deps = [ ":buildflags", "//build:branding_buildflags", + "//chrome/browser/chrome_for_testing:buildflags", "//chrome/chrome_elf:nt_registry", ] @@ -58,6 +59,11 @@ "google_chrome_install_modes.cc", "google_chrome_install_modes.h", ] + } else if (is_chrome_for_testing_branded) { + sources += [ + "google_chrome_for_testing_install_modes.cc", + "google_chrome_for_testing_install_modes.h", + ] } else { sources += [ "chromium_install_modes.cc",
diff --git a/chrome/install_static/DEPS b/chrome/install_static/DEPS index 1a9c8e8..d0c776c 100644 --- a/chrome/install_static/DEPS +++ b/chrome/install_static/DEPS
@@ -8,6 +8,8 @@ "+base/win/windows_types.h", # Nothing from chrome. "-chrome", + # Except Chrome for Testing. + "+chrome/browser/chrome_for_testing/buildflags.h", # For the app icon resource identifiers. "+chrome/app/chrome_dll_resource.h", # All registry access should go through nt_registry.
diff --git a/chrome/install_static/chromium_install_modes.cc b/chrome/install_static/chromium_install_modes.cc index 38740b5..b3d7a13 100644 --- a/chrome/install_static/chromium_install_modes.cc +++ b/chrome/install_static/chromium_install_modes.cc
@@ -33,7 +33,7 @@ L"", // Empty install_suffix for the primary install mode. .logo_suffix = L"", // No logo suffix for the primary install mode. .app_guid = - L"", // Empty app_guid since no integraion with Google Update. + L"", // Empty app_guid since no integration with Google Update. .base_app_name = L"Chromium", // A distinct base_app_name. .base_app_id = L"Chromium", // A distinct base_app_id. .prog_id_prefix = L"ChromiumHTM", // ProgID prefix.
diff --git a/chrome/install_static/google_chrome_for_testing_install_modes.cc b/chrome/install_static/google_chrome_for_testing_install_modes.cc new file mode 100644 index 0000000..02290bd --- /dev/null +++ b/chrome/install_static/google_chrome_for_testing_install_modes.cc
@@ -0,0 +1,86 @@ +// 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. + +// Brand-specific constants and install modes for Google Chrome for Testing. + +#include "chrome/install_static/google_chrome_for_testing_install_modes.h" + +#include <stdlib.h> + +#include "chrome/app/chrome_dll_resource.h" +#include "chrome/common/chrome_icon_resources_win.h" +#include "chrome/install_static/install_modes.h" + +namespace install_static { + +const wchar_t kCompanyPathName[] = L"Google"; + +const wchar_t kProductPathName[] = L"Chrome for Testing"; + +const size_t kProductPathNameLength = _countof(kProductPathName) - 1; + +const char kSafeBrowsingName[] = "googlechromefortesting"; + +const InstallConstants kInstallModes[] = { + // The primary install mode for stable Google Chrome. + { + .size = sizeof(kInstallModes[0]), + .index = GOOGLE_CHROME_FOR_TESTING_INDEX, // The one and only mode for + // Google Chrome for Testing. + .install_switch = + "", // No install switch for the primary install mode. + .install_suffix = + L"", // Empty install_suffix for the primary install mode. + .logo_suffix = L"", // No logo suffix for the primary install mode. + .app_guid = + L"", // Empty app_guid since no integration with Google Update. + .base_app_name = + L"Google Chrome for Testing", // A distinct base_app_name. + .base_app_id = L"ChromeforTesting", // A distinct base_app_id. + .prog_id_prefix = L"CfTHTML", // ProgID prefix. + .prog_id_description = + L"Chrome for Testing HTML Document", // ProgID description. + .active_setup_guid = + L"{E25CFD4E-D9D4-4123-936A-286FBB19BA5B}", // Active Setup GUID. + .legacy_command_execute_clsid = L"", // CommandExecuteImpl CLSID. + .toast_activator_clsid = {0x77ED8F9B, + 0xE27A, + 0x499F, + {0x8E, 0x2F, 0xD7, 0xC0, 0x41, 0x57, 0xCF, + 0x64}}, // Toast Activator CLSID. + // {77ED8F9B-E27A-499F-8E2F-D7C04157CF64} + .elevator_clsid = {0x724349BF, + 0xE1CF, + 0x4481, + {0xA6, 0x4D, 0x8C, 0xD1, 0x01, 0x83, 0xCA, + 0x03}}, // Elevator CLSID. + // {724349BF-E1CF-4481-A64D-8CD10183CA03} + .elevator_iid = {0x3DC48E97, + 0x47D0, + 0x476F, + {0x8F, 0x89, 0x07, 0x92, 0xFC, 0x61, 0x15, + 0x67}}, // IElevator IID and TypeLib + // {3DC48E97-47D0-476F-8F89-0792FC611567} + .default_channel_name = + L"", // Empty default channel name since no update integration. + .channel_strategy = ChannelStrategy::UNSUPPORTED, + .supports_system_level = + false, // Does not support system-level installs. + .supports_set_as_default_browser = + false, // Does not support in-product set as default browser UX. + .supports_retention_experiments = + false, // Does not support retention experiments. + .app_icon_resource_index = + icon_resources::kApplicationIndex, // App icon resource index. + .app_icon_resource_id = IDR_MAINFRAME, // App icon resource id. + .sandbox_sid_prefix = + L"S-1-15-2-3251537155-1984446955-2931258699-841473695-1938553385-" + L"924012153-", // App container sid prefix for sandbox. + }, +}; + +static_assert(_countof(kInstallModes) == NUM_INSTALL_MODES, + "Imbalance between kInstallModes and InstallConstantIndex"); + +} // namespace install_static
diff --git a/chrome/install_static/google_chrome_for_testing_install_modes.h b/chrome/install_static/google_chrome_for_testing_install_modes.h new file mode 100644 index 0000000..fb77d4c --- /dev/null +++ b/chrome/install_static/google_chrome_for_testing_install_modes.h
@@ -0,0 +1,21 @@ +// 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. + +// Brand-specific types and constants for Google Chrome for Testing + +#ifndef CHROME_INSTALL_STATIC_GOOGLE_CHROME_FOR_TESTING_INSTALL_MODES_H_ +#define CHROME_INSTALL_STATIC_GOOGLE_CHROME_FOR_TESTING_INSTALL_MODES_H_ + +namespace install_static { + +// Note: This list of indices must be kept in sync with the brand-specific +// resource strings in chrome/installer/util/prebuild/create_string_rc. +enum InstallConstantIndex { + GOOGLE_CHROME_FOR_TESTING_INDEX, + NUM_INSTALL_MODES, +}; + +} // namespace install_static + +#endif // CHROME_INSTALL_STATIC_GOOGLE_CHROME_FOR_TESTING_INSTALL_MODES_H_
diff --git a/chrome/install_static/install_modes.h b/chrome/install_static/install_modes.h index 53cbe32..d4c95bee 100644 --- a/chrome/install_static/install_modes.h +++ b/chrome/install_static/install_modes.h
@@ -31,6 +31,7 @@ #include <string> #include "build/branding_buildflags.h" +#include "chrome/browser/chrome_for_testing/buildflags.h" #include "chrome/install_static/install_constants.h" // Include the brand-specific values. Each of these must define: @@ -40,6 +41,8 @@ // kInstallModes. #if BUILDFLAG(GOOGLE_CHROME_BRANDING) #include "chrome/install_static/google_chrome_install_modes.h" +#elif BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING) +#include "chrome/install_static/google_chrome_for_testing_install_modes.h" #else #include "chrome/install_static/chromium_install_modes.h" #endif
diff --git a/chrome/install_static/install_util_unittest.cc b/chrome/install_static/install_util_unittest.cc index 6181720..1f08ae7 100644 --- a/chrome/install_static/install_util_unittest.cc +++ b/chrome/install_static/install_util_unittest.cc
@@ -12,6 +12,7 @@ #include "base/test/test_reg_util_win.h" #include "base/win/win_util.h" #include "build/branding_buildflags.h" +#include "chrome/browser/chrome_for_testing/buildflags.h" #include "chrome/chrome_elf/nt_registry/nt_registry.h" #include "chrome/install_static/buildflags.h" #include "chrome/install_static/install_details.h" @@ -741,6 +742,13 @@ InstallStaticUtilTest, testing::Combine(testing::Values(CANARY_INDEX), testing::Values("user"))); +#elif BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING) +// Chrome for Testing is only at user level. +INSTANTIATE_TEST_SUITE_P( + ChromeForTesting, + InstallStaticUtilTest, + testing::Combine(testing::Values(GOOGLE_CHROME_FOR_TESTING_INDEX), + testing::Values("user"))); #else // BUILDFLAG(GOOGLE_CHROME_BRANDING) // Chromium supports user and system levels. INSTANTIATE_TEST_SUITE_P(Chromium,
diff --git a/chrome/install_static/product_install_details_unittest.cc b/chrome/install_static/product_install_details_unittest.cc index 6273e1b..5e46301 100644 --- a/chrome/install_static/product_install_details_unittest.cc +++ b/chrome/install_static/product_install_details_unittest.cc
@@ -14,6 +14,7 @@ #include "base/win/registry.h" #include "base/win/windows_version.h" #include "build/branding_buildflags.h" +#include "chrome/browser/chrome_for_testing/buildflags.h" #include "chrome/chrome_elf/nt_registry/nt_registry.h" #include "chrome/install_static/buildflags.h" #include "chrome/install_static/install_constants.h" @@ -185,6 +186,16 @@ L"canary", }, }; +#elif BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING) +constexpr TestData kTestData[] = { + { + L"C:\\Users\\user\\AppData\\Local\\Google\\Chrome for " + L"Testing\\Application\\chrome.exe", + GOOGLE_CHROME_FOR_TESTING_INDEX, + false, + L"", + }, +}; #else // BUILDFLAG(GOOGLE_CHROME_BRANDING) constexpr TestData kTestData[] = { {
diff --git a/chrome/installer/setup/DEPS b/chrome/installer/setup/DEPS index a3e1542e..5eed528 100644 --- a/chrome/installer/setup/DEPS +++ b/chrome/installer/setup/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+chrome/browser/chrome_for_testing/buildflags.h", "+chrome/browser/enterprise/connectors/device_trust/key_management/installer/key_rotation_manager.h", "+chrome/browser/enterprise/connectors/device_trust/key_management/installer/management_service/rotate_util.h", "+chrome/browser/enterprise/connectors/device_trust/key_management/core/network/win_key_network_delegate.h",
diff --git a/chrome/installer/setup/install_unittest.cc b/chrome/installer/setup/install_unittest.cc index 8738aff9..7e945f3 100644 --- a/chrome/installer/setup/install_unittest.cc +++ b/chrome/installer/setup/install_unittest.cc
@@ -24,6 +24,7 @@ #include "base/win/scoped_com_initializer.h" #include "base/win/shortcut.h" #include "build/branding_buildflags.h" +#include "chrome/browser/chrome_for_testing/buildflags.h" #include "chrome/install_static/install_details.h" #include "chrome/install_static/install_modes.h" #include "chrome/install_static/test/scoped_install_details.h" @@ -197,6 +198,13 @@ CreateVisualElementsManifestTest, testing::Combine(testing::Values(install_static::CANARY_INDEX), testing::Values(kExpectedCanaryManifest))); +#elif BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING) +INSTANTIATE_TEST_SUITE_P( + ChromeForTesting, + CreateVisualElementsManifestTest, + testing::Combine( + testing::Values(install_static::GOOGLE_CHROME_FOR_TESTING_INDEX), + testing::Values(kExpectedPrimaryManifest))); #else INSTANTIATE_TEST_SUITE_P( Chromium,
diff --git a/chrome/installer/setup/install_worker_unittest.cc b/chrome/installer/setup/install_worker_unittest.cc index 3940cde..e33e315 100644 --- a/chrome/installer/setup/install_worker_unittest.cc +++ b/chrome/installer/setup/install_worker_unittest.cc
@@ -15,6 +15,7 @@ #include "base/win/registry.h" #include "base/win/win_util.h" #include "base/win/windows_version.h" +#include "chrome/browser/chrome_for_testing/buildflags.h" #include "chrome/common/chrome_constants.h" #include "chrome/install_static/install_util.h" #include "chrome/install_static/test/scoped_install_details.h" @@ -271,6 +272,8 @@ // Tests //------------------------------------------------------------------------------ +// Chrome for Testing does not support system-level installations. +#if !BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING) TEST_F(InstallWorkerTest, TestInstallChromeSystem) { const bool system_level = true; NiceMock<MockWorkItemList> work_item_list; @@ -318,6 +321,7 @@ AddInstallWorkItems(install_params, &work_item_list); } +#endif // Tests for installer::AddUpdateBrandCodeWorkItem(). //------------------------------------------------------------------------------ @@ -519,7 +523,7 @@ value_name == path_with_another_dll.value()) { continue; } - FAIL() << "Invalid registry value encountered: " << value_name;; + FAIL() << "Invalid registry value encountered: " << value_name; } } }
diff --git a/chrome/installer/setup/setup_install_details_unittest.cc b/chrome/installer/setup/setup_install_details_unittest.cc index bc56916..76a69f0 100644 --- a/chrome/installer/setup/setup_install_details_unittest.cc +++ b/chrome/installer/setup/setup_install_details_unittest.cc
@@ -10,6 +10,7 @@ #include "base/memory/raw_ref.h" #include "base/test/test_reg_util_win.h" #include "build/branding_buildflags.h" +#include "chrome/browser/chrome_for_testing/buildflags.h" #include "chrome/chrome_elf/nt_registry/nt_registry.h" #include "chrome/install_static/buildflags.h" #include "chrome/install_static/install_details.h" @@ -431,6 +432,26 @@ L"extended", // Expect the channel override. }, }; +#elif BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING) +constexpr TestData kTestData[] = { + // User-level test cases. + { + L"setup.exe", // User-level, primary mode. + L"", // New install. + install_static::GOOGLE_CHROME_FOR_TESTING_INDEX, // Expect primary + // mode. + false, // Expect user-level. + L"", // Expect empty channel. + }, + { + L"setup.exe", // User-level, primary mode. + L"--uninstall", // Updating an existing install. + install_static::GOOGLE_CHROME_FOR_TESTING_INDEX, // Expect primary + // mode. + false, // Expect user-level. + L"", // Expect empty channel. + }, +}; #else // BUILDFLAG(GOOGLE_CHROME_BRANDING) constexpr TestData kTestData[] = { // User-level test cases.
diff --git a/chrome/installer/util/DEPS b/chrome/installer/util/DEPS index 3f2ad350..3feedd5 100644 --- a/chrome/installer/util/DEPS +++ b/chrome/installer/util/DEPS
@@ -1,4 +1,5 @@ include_rules = [ + "+chrome/browser/chrome_for_testing/buildflags.h", # This file is generated but otherwise would be excluded because of the # "-chrome" rule in a parent dir. "+chrome/grit/chromium_strings.h",
diff --git a/chrome/installer/util/beacons_unittest.cc b/chrome/installer/util/beacons_unittest.cc index 32c9e66..9af6ca71 100644 --- a/chrome/installer/util/beacons_unittest.cc +++ b/chrome/installer/util/beacons_unittest.cc
@@ -12,6 +12,7 @@ #include "base/win/registry.h" #include "base/win/win_util.h" #include "build/branding_buildflags.h" +#include "chrome/browser/chrome_for_testing/buildflags.h" #include "chrome/install_static/install_details.h" #include "chrome/install_static/install_modes.h" #include "chrome/install_static/test/scoped_install_details.h" @@ -248,6 +249,14 @@ DefaultBrowserBeaconTest, testing::Combine(testing::Values(install_static::CANARY_INDEX), testing::Values("user"))); +#elif BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING) +// Chrome for Testing is only at user level. +INSTANTIATE_TEST_SUITE_P( + ChromeForTesting, + DefaultBrowserBeaconTest, + testing::Combine( + testing::Values(install_static::GOOGLE_CHROME_FOR_TESTING_INDEX), + testing::Values("user"))); #else // BUILDFLAG(GOOGLE_CHROME_BRANDING) // Chromium supports user and system levels. INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/installer/util/prebuild/create_installer_string_rc.py b/chrome/installer/util/prebuild/create_installer_string_rc.py index 7c64273..9b174616 100755 --- a/chrome/installer/util/prebuild/create_installer_string_rc.py +++ b/chrome/installer/util/prebuild/create_installer_string_rc.py
@@ -50,6 +50,9 @@ 'IDS_APP_SHORTCUTS_SUBDIR_NAME_DEV', 'IDS_APP_SHORTCUTS_SUBDIR_NAME_CANARY', ], + 'google_chrome_for_testing': [ + 'IDS_APP_SHORTCUTS_SUBDIR_NAME', + ], 'chromium': [ 'IDS_APP_SHORTCUTS_SUBDIR_NAME', ], @@ -61,6 +64,9 @@ 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_DEV', 'IDS_INBOUND_MDNS_RULE_DESCRIPTION_CANARY', ], + 'google_chrome_for_testing': [ + 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', + ], 'chromium': [ 'IDS_INBOUND_MDNS_RULE_DESCRIPTION', ], @@ -72,6 +78,9 @@ 'IDS_INBOUND_MDNS_RULE_NAME_DEV', 'IDS_INBOUND_MDNS_RULE_NAME_CANARY', ], + 'google_chrome_for_testing': [ + 'IDS_INBOUND_MDNS_RULE_NAME', + ], 'chromium': [ 'IDS_INBOUND_MDNS_RULE_NAME', ], @@ -87,6 +96,9 @@ 'IDS_SHORTCUT_NAME_DEV', 'IDS_SXS_SHORTCUT_NAME', ], + 'google_chrome_for_testing': [ + 'IDS_PRODUCT_NAME', + ], 'chromium': [ 'IDS_PRODUCT_NAME', ],
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index b00cfbb..f680b4e 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -6392,6 +6392,10 @@ ] } + if (enable_bound_session_credentials) { + sources += [ "../browser/signin/bound_session_credentials/bound_session_cookie_fetcher_unittest.cc" ] + } + if (enable_offline_pages) { sources += [ "../browser/offline_pages/background_loader_offliner_unittest.cc",
diff --git a/chrome/test/data/extensions/api_test/input_method/ime_menu2/background.js b/chrome/test/data/extensions/api_test/input_method/ime_menu2/background.js index 44627a2..24fe763 100644 --- a/chrome/test/data/extensions/api_test/input_method/ime_menu2/background.js +++ b/chrome/test/data/extensions/api_test/input_method/ime_menu2/background.js
@@ -100,24 +100,5 @@ engineID: 'test', items: menuItemsUpdate }); - }, - function testNotifyMenuItems() { - var onMenuItemActivatedCount = 0; - chrome.input.ime.onMenuItemActivated.addListener( - function(engineID, name) { - chrome.test.assertEq('test', engineID); - if (onMenuItemActivatedCount == 0) { - chrome.test.assertEq('menu_a', name); - ++onMenuItemActivatedCount; - } - else { - chrome.test.assertEq('menu_b', name); - chrome.test.sendMessage('get_menu_activated'); - chrome.test.succeed(); - } - } - ); - chrome.inputMethodPrivate.notifyImeMenuItemActivated('test', 'menu_a'); - chrome.inputMethodPrivate.notifyImeMenuItemActivated('test', 'menu_b'); } ]);
diff --git a/chrome/test/data/webapps_integration/file_handler/bar_handler.html b/chrome/test/data/webapps_integration/file_handler/image_handler.html similarity index 100% rename from chrome/test/data/webapps_integration/file_handler/bar_handler.html rename to chrome/test/data/webapps_integration/file_handler/image_handler.html
diff --git a/chrome/test/data/webapps_integration/file_handler/foo_handler.html b/chrome/test/data/webapps_integration/file_handler/text_handler.html similarity index 100% rename from chrome/test/data/webapps_integration/file_handler/foo_handler.html rename to chrome/test/data/webapps_integration/file_handler/text_handler.html
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 5f629dc..1935f46 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -230,6 +230,7 @@ "chromeos/crostini_upgrader_browsertest.js", "chromeos/diagnostics/diagnostics_browsertest.js", "chromeos/firmware_update/firmware_update_browsertest.js", + "chromeos/office_fallback/office_fallback_browsertest.js", "chromeos/os_feedback_ui/os_feedback_browsertest.js", "chromeos/scanning/scanning_app_browsertest.js", "chromeos/shimless_rma/shimless_rma_browsertest.js", @@ -599,6 +600,7 @@ "chromeos/ash_common:build_grdp", "chromeos/cloud_upload:build_grdp", "chromeos/manage_mirrorsync:build_grdp", + "chromeos/office_fallback:build_grdp", "chromeos/personalization_app:build_grdp", "chromeos/print_management:build_grdp", "chromeos/shortcut_customization:build_grdp", @@ -611,6 +613,7 @@ grdp_files += [ "$target_gen_dir/chromeos/ash_common/resources.grdp", "$target_gen_dir/chromeos/cloud_upload/resources.grdp", + "$target_gen_dir/chromeos/office_fallback/resources.grdp", "$target_gen_dir/chromeos/personalization_app/resources.grdp", "$target_gen_dir/chromeos/shortcut_customization/resources.grdp", "$target_gen_dir/chromeos/print_management/resources.grdp",
diff --git a/chrome/test/data/webui/app_home/test_app_home_browser_proxy.ts b/chrome/test/data/webui/app_home/test_app_home_browser_proxy.ts index 883b1cbd..4da0133 100644 --- a/chrome/test/data/webui/app_home/test_app_home_browser_proxy.ts +++ b/chrome/test/data/webui/app_home/test_app_home_browser_proxy.ts
@@ -23,6 +23,10 @@ uninstallApp(_appId: string) {} showAppSettings(_appId: string) {} + + createAppShortcut(_appId: string) { + return Promise.resolve(); + } } export class TestAppHomeBrowserProxy implements BrowserProxy {
diff --git a/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_app_test.ts b/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_app_test.ts index 9286277..4c4e6d2d 100644 --- a/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_app_test.ts +++ b/chrome/test/data/webui/chromeos/cloud_upload/cloud_upload_app_test.ts
@@ -216,7 +216,7 @@ await testProxy.handler.whenCalled('respondAndClose'); assertEquals(1, testProxy.handler.getCallCount('respondAndClose')); assertDeepEquals( - [UserAction.kUploadToOneDrive], + [UserAction.kConfirmOrUploadToOneDrive], testProxy.handler.getArgs('respondAndClose')); });
diff --git a/chrome/test/data/webui/chromeos/office_fallback/.gitignore b/chrome/test/data/webui/chromeos/office_fallback/.gitignore new file mode 100644 index 0000000..ec7fda7 --- /dev/null +++ b/chrome/test/data/webui/chromeos/office_fallback/.gitignore
@@ -0,0 +1,2 @@ +# Generated from ash/webui/personalization_app/tools/gen_tsconfig.py +tsconfig.json
diff --git a/chrome/test/data/webui/chromeos/office_fallback/BUILD.gn b/chrome/test/data/webui/chromeos/office_fallback/BUILD.gn new file mode 100644 index 0000000..4cc43e5 --- /dev/null +++ b/chrome/test/data/webui/chromeos/office_fallback/BUILD.gn
@@ -0,0 +1,36 @@ +# 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. + +import("//tools/typescript/ts_library.gni") +import("//ui/webui/resources/tools/generate_grd.gni") + +ts_library("build_ts") { + root_dir = "." + out_dir = "$target_gen_dir/tsc" + tsconfig_base = "tsconfig_base.json" + in_files = [ "office_fallback_app_test.ts" ] + path_mappings = [ + "chrome://office-fallback/*|" + + rebase_path( + "$root_gen_dir/ash/webui/common/resources/office_fallback/tsc/*", + target_gen_dir), + "chrome://webui-test/*|" + + rebase_path("$root_gen_dir/chrome/test/data/webui/tsc/*", + target_gen_dir), + ] + deps = [ + "../..:build_ts", + "//ash/webui/common/resources/office_fallback:build_ts", + ] +} + +generate_grd("build_grdp") { + grd_prefix = "webui_chromeos_office_fallback" + out_grd = "$target_gen_dir/resources.grdp" + + deps = [ ":build_ts" ] + manifest_files = + filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ]) + resource_path_prefix = "chromeos/office_fallback" +}
diff --git a/chrome/test/data/webui/chromeos/office_fallback/DIR_METADATA b/chrome/test/data/webui/chromeos/office_fallback/DIR_METADATA new file mode 100644 index 0000000..e9400b8 --- /dev/null +++ b/chrome/test/data/webui/chromeos/office_fallback/DIR_METADATA
@@ -0,0 +1 @@ +mixins: "//ui/file_manager/COMMON_METADATA"
diff --git a/chrome/test/data/webui/chromeos/office_fallback/OWNERS b/chrome/test/data/webui/chromeos/office_fallback/OWNERS new file mode 100644 index 0000000..73220a8 --- /dev/null +++ b/chrome/test/data/webui/chromeos/office_fallback/OWNERS
@@ -0,0 +1 @@ +file://ui/file_manager/OWNERS
diff --git a/chrome/test/data/webui/chromeos/office_fallback/office_fallback_app_test.ts b/chrome/test/data/webui/chromeos/office_fallback/office_fallback_app_test.ts new file mode 100644 index 0000000..64e502a --- /dev/null +++ b/chrome/test/data/webui/chromeos/office_fallback/office_fallback_app_test.ts
@@ -0,0 +1,161 @@ +// 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. + +import 'chrome://office-fallback/office_fallback_dialog.js'; + +import {DialogChoice, PageHandlerRemote} from 'chrome://office-fallback/office_fallback.mojom-webui.js'; +import {OfficeFallbackBrowserProxy} from 'chrome://office-fallback/office_fallback_browser_proxy.js'; +import type {OfficeFallbackElement} from 'chrome://office-fallback/office_fallback_dialog.js'; +import {assertDeepEquals, assertEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; +import {TestBrowserProxy} from 'chrome://webui-test/test_browser_proxy.js'; + +interface ProxyOptions { + fileNames?: string[]; + taskTitle: string; + // The string will be converted to enum FallbackReason from + // office_fallback_dialog.ts in the mapping in + // OfficeFallbackElement.stringToFailureReason. + fallbackReason: string; +} + +/** + * A test OfficeFallbackBrowserProxy implementation that enables to mock various + * mojo responses. + */ +class OfficeFallbackTestBrowserProxy implements OfficeFallbackBrowserProxy { + handler: PageHandlerRemote&TestBrowserProxy; + dialogArgs: string; + + constructor(options: ProxyOptions) { + this.handler = TestBrowserProxy.fromClass(PageHandlerRemote); + // Creating JSON string as in OfficeFallbackDialog::GetDialogArgs(). + const args = { + 'fileNames': options.fileNames, + 'fallbackReason': options.fallbackReason, + 'taskTitle': options.taskTitle, + }; + this.dialogArgs = JSON.stringify(args); + } + + // JSON-encoded dialog arguments. + getDialogArguments(): string { + return this.dialogArgs; + } +} + +suite('<office-fallback>', () => { + // Holds the <cloud-upload> app. + let container: HTMLDivElement; + // The <office-fallback> app. + let officeFallbackApp: OfficeFallbackElement; + // The BrowserProxy element to make assertions on when mojo methods are + // called. + let testProxy: OfficeFallbackTestBrowserProxy; + + const setUp = async (options: ProxyOptions) => { + testProxy = new OfficeFallbackTestBrowserProxy(options); + OfficeFallbackBrowserProxy.setInstance(testProxy); + + // Creates and attaches the <office-fallback> element to the DOM tree. + officeFallbackApp = document.createElement('office-fallback'); + container.appendChild(officeFallbackApp); + }; + + /** + * Runs prior to all the tests running, attaches a div to enable isolated + * clearing and attaching of the web component. + */ + suiteSetup(() => { + container = document.createElement('div'); + document.body.appendChild(container); + }); + + + /** + * Runs after each test. Removes all elements from the <div> that holds + * the <cloud-upload> component. + */ + teardown(() => { + container.innerHTML = ''; + testProxy.handler.reset(); + }); + + /** + * Tests that clicking the "quick office" button triggers the right `close` + * mojo request. + */ + test('Open in offline editor button', async () => { + await setUp({ + fileNames: ['file.docx'], + taskTitle: 'testTitle', + fallbackReason: 'Offline', + }); + + officeFallbackApp.$('#quick-office-button').click(); + await testProxy.handler.whenCalled('close'); + assertEquals(1, testProxy.handler.getCallCount('close')); + assertDeepEquals( + [DialogChoice.kQuickOffice], testProxy.handler.getArgs('close')); + }); + + /** + * Tests that clicking the "try again" button triggers the right `close` + * mojo request. + */ + test('Try again button', async () => { + await setUp({ + fileNames: ['file.docx'], + taskTitle: 'testTitle', + fallbackReason: 'Drive Unavailable', + }); + + officeFallbackApp.$('#try-again-button').click(); + await testProxy.handler.whenCalled('close'); + assertEquals(1, testProxy.handler.getCallCount('close')); + assertDeepEquals( + [DialogChoice.kTryAgain], testProxy.handler.getArgs('close')); + }); + + /** + * Tests that clicking the "close" button triggers the right `close` + * mojo request. + */ + test('Close button', async () => { + await setUp({ + fileNames: ['file.docx'], + taskTitle: 'testTitle', + fallbackReason: 'OneDrive Unavailable', + }); + + officeFallbackApp.$('#cancel-button').click(); + await testProxy.handler.whenCalled('close'); + assertEquals(1, testProxy.handler.getCallCount('close')); + assertDeepEquals( + [DialogChoice.kCancel], testProxy.handler.getArgs('close')); + }); + + + /** + * Tests that the fileNames are displayed correctly in the title. + */ + test('fileNames', async () => { + let fileName = `file1.docx`; + const fileNames = [fileName]; + for (let i = 2; i < 12; i++) { + fileName = `file${i}.docx`; + fileNames.push(fileName); + } + + await setUp({ + fileNames: fileNames, + taskTitle: 'testTitle', + fallbackReason: 'Offline', + }); + + const title = officeFallbackApp.$('#title').innerText; + fileNames.forEach((fileName) => { + assertTrue(title.includes(fileName)); + }); + }); +}); \ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/office_fallback/office_fallback_browsertest.js b/chrome/test/data/webui/chromeos/office_fallback/office_fallback_browsertest.js new file mode 100644 index 0000000..4ddebf9 --- /dev/null +++ b/chrome/test/data/webui/chromeos/office_fallback/office_fallback_browsertest.js
@@ -0,0 +1,26 @@ +// 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. + +/** + * @fileoverview Test suite for chrome://office-fallback. Tests the entire page + * instead of individual components. + */ + +GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']); + +GEN('#include "ash/constants/ash_features.h"'); +GEN('#include "content/public/test/browser_test.h"'); + +var OfficeFallbackAppBrowserTest = class extends PolymerTest { + get browsePreload() { + return 'chrome://office-fallback/test_loader.html?module=chromeos/' + + 'office_fallback/office_fallback_app_test.js'; + } + + get featureList() { + return {enabled: ['ash::features::kUploadOfficeToCloud']}; + } +}; + +TEST_F('OfficeFallbackAppBrowserTest', 'All', () => mocha.run()); \ No newline at end of file
diff --git a/chrome/test/data/webui/chromeos/office_fallback/tsconfig_base.json b/chrome/test/data/webui/chromeos/office_fallback/tsconfig_base.json new file mode 100644 index 0000000..c11d0a444 --- /dev/null +++ b/chrome/test/data/webui/chromeos/office_fallback/tsconfig_base.json
@@ -0,0 +1,10 @@ +{ + "extends": "../../../../../../tools/typescript/tsconfig_base.json", + "compilerOptions": { + "allowJs": true, + "typeRoots": [ + "../../../../../../third_party/node/node_modules/@types" + ], + "types": ["mocha", "trusted-types"] + } +}
diff --git a/chrome/test/data/webui/settings/review_notification_permissions_test.ts b/chrome/test/data/webui/settings/review_notification_permissions_test.ts index ac767d5..dbbcb52 100644 --- a/chrome/test/data/webui/settings/review_notification_permissions_test.ts +++ b/chrome/test/data/webui/settings/review_notification_permissions_test.ts
@@ -465,9 +465,6 @@ }); /** - * TODO(crbug/1374908): Re-enable the commented parts. This is failing on - * buildbots. - * * Tests whether header string updated based on the notification permission * list size for plural and singular case. */ @@ -480,11 +477,13 @@ assertEquals(2, entries.length); const headerElement = - testElement.shadowRoot!.querySelector('#expandButton h2'); + testElement.shadowRoot!.querySelector('#review-header h2'); assertTrue(headerElement !== null); - // assertEquals( - // 'Review 2 sites that recently sent a lot of notifications', - // headerElement.textContent!.trim()); + + const headerStringTwo = + await PluralStringProxyImpl.getInstance().getPluralString( + 'safetyCheckNotificationPermissionReviewPrimaryLabel', 2); + assertEquals(headerStringTwo, headerElement.textContent!.trim()); // Check header string for singular case. webUIListenerCallback( @@ -497,8 +496,9 @@ entries = getEntries(); assertEquals(1, entries.length); - // assertEquals( - // 'Review 1 site that recently sent a lot of notifications', - // headerElement.textContent!.trim()); + const headerStringOne = + await PluralStringProxyImpl.getInstance().getPluralString( + 'safetyCheckNotificationPermissionReviewPrimaryLabel', 1); + assertEquals(headerStringOne, headerElement.textContent!.trim()); }); });
diff --git a/chrome/test/data/webui/settings/safety_check_permissions_test.ts b/chrome/test/data/webui/settings/safety_check_permissions_test.ts index 9f498f7..3efdd83 100644 --- a/chrome/test/data/webui/settings/safety_check_permissions_test.ts +++ b/chrome/test/data/webui/settings/safety_check_permissions_test.ts
@@ -137,8 +137,7 @@ iconStatus: SafetyCheckIconStatus.NOTIFICATION_PERMISSIONS, label: 'Review <b>2 sites</b> that recently sent a lot of notifications', buttonLabel: 'Review', - buttonAriaLabel: - 'Review 2 sites that recently sent a lot of notifications', + buttonAriaLabel: 'Review notification permissions', }); // User clicks review button. @@ -174,8 +173,7 @@ iconStatus: SafetyCheckIconStatus.NOTIFICATION_PERMISSIONS, label: 'Review <b>1 site</b> that recently sent a lot of notifications', buttonLabel: 'Review', - buttonAriaLabel: - 'Review 1 site that recently sent a lot of notifications', + buttonAriaLabel: 'Review notification permissions', }); // User clicks review button.
diff --git a/chrome/test/webapps/coverage/coverage_linux.tsv b/chrome/test/webapps/coverage/coverage_linux.tsv index 10e9698..564e728 100644 --- a/chrome/test/webapps/coverage/coverage_linux.tsv +++ b/chrome/test/webapps/coverage/coverage_linux.tsv
@@ -1,5 +1,5 @@ # This is a generated file. -# Full coverage: 66%, with partial coverage: 89% +# Full coverage: 62%, with partial coverage: 85% create_shortcut_Standalone_Windowed🌕 launch_from_menu_option_Standalone🌕 check_app_title_Standalone_StandaloneOriginal🌑 create_shortcut_Standalone_Windowed🌕 launch_from_launch_icon_Standalone🌕 check_app_title_Standalone_StandaloneOriginal🌑 create_shortcut_Standalone_Windowed🌕 launch_from_chrome_apps_Standalone🌓 check_app_title_Standalone_StandaloneOriginal🌑 @@ -1168,136 +1168,136 @@ install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌕 launch_file_expect_no_dialog_FileHandler_OneFooFile🌕 check_pwa_window_created_FileHandler_One🌑 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 check_window_not_created🌕 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌕 check_window_not_created🌕 check_site_not_handles_file_FileHandler_Foo🌕 check_site_not_handles_file_FileHandler_Bar🌕 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌑 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_Remember🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 check_window_not_created🌑 check_site_handles_file_FileHandler_Foo🌑 check_site_handles_file_FileHandler_Bar🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_AskAgain🌑 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌑 +create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 +create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 +install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Deny_Remember🌑 check_window_not_created🌑 check_site_not_handles_file_FileHandler_Foo🌑 check_site_not_handles_file_FileHandler_Bar🌑 create_shortcut_FileHandler_Windowed🌕 add_file_handling_policy_approval_FileHandler🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 create_shortcut_FileHandler_Browser🌕 add_file_handling_policy_approval_FileHandler🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑 install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 add_file_handling_policy_approval_FileHandler🌑 launch_file_expect_no_dialog_FileHandler_OneFooFile🌑 check_pwa_window_created_FileHandler_One🌑
diff --git a/chrome/test/webapps/coverage/coverage_win.tsv b/chrome/test/webapps/coverage/coverage_win.tsv index 2e83db7..eb76fe2 100644 --- a/chrome/test/webapps/coverage/coverage_win.tsv +++ b/chrome/test/webapps/coverage/coverage_win.tsv
@@ -1,5 +1,5 @@ # This is a generated file. -# Full coverage: 68%, with partial coverage: 91% +# Full coverage: 63%, with partial coverage: 87% create_shortcut_Standalone_Windowed🌕 launch_from_menu_option_Standalone🌕 check_app_title_Standalone_StandaloneOriginal🌑 create_shortcut_Standalone_Windowed🌕 launch_from_launch_icon_Standalone🌕 check_app_title_Standalone_StandaloneOriginal🌑 create_shortcut_Standalone_Windowed🌕 launch_from_chrome_apps_Standalone🌓 check_app_title_Standalone_StandaloneOriginal🌑 @@ -1168,136 +1168,136 @@ install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 check_site_handles_file_FileHandler_Foo🌕 check_site_handles_file_FileHandler_Bar🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneFooFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneFooFile🌑 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleFooFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_MultipleFooFiles🌑 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_OneBarFile_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_One🌑 check_files_loaded_in_site_FileHandler_OneBarFile🌑 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 -create_shortcut_FileHandler_Windowed🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -create_shortcut_FileHandler_Browser🌕 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_NoShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_WithShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_NoShortcut_Windowed_WebApp🌓 launch_file_expect_dialog_FileHandler_MultipleBarFiles_Allow_AskAgain🌕 check_pwa_window_created_FileHandler_Two🌑 check_files_loaded_in_site_FileHandler_MultipleBarFiles🌑 -install_policy_app_FileHandler_WithShortcut_Browser_WebApp🌓 launch_file_expect_dialog_FileHa