diff --git a/.clang-format b/.clang-format index 4d839d95..5a40766 100644 --- a/.clang-format +++ b/.clang-format
@@ -10,6 +10,7 @@ # TODO(crbug.com/1392808): Remove when InsertBraces has been upstreamed into # the Chromium style (is implied by BasedOnStyle: Chromium). InsertBraces: true +InsertNewlineAtEOF: true # Make sure code like: # IPC_BEGIN_MESSAGE_MAP()
diff --git a/DEPS b/DEPS index cb84694..617c4de 100644 --- a/DEPS +++ b/DEPS
@@ -304,15 +304,15 @@ # 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': '90f653a7233ead5d7b648b1eb360b725987a85a8', + 'skia_revision': '4f1cae66791c60dc6584f6cecbd58c533965a7ac', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '379e492a67ce6ce01f75fb8475f0715577cde249', + 'v8_revision': 'a34243892380ef2bba92a69af3bf7cb422a3755d', # 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': 'ad52f12e5943aff75499ab979bd5322c850114e0', + 'angle_revision': '888ca8d9e307db9936747ca5411a168b5b7669dd', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -375,7 +375,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'c82a855930faff1001ebe2298e75ca5a91f29391', + 'catapult_revision': 'f6395b16b47ca583919ef1061a65981d3e799c32', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling CrossBench # and whatever else without interference from each other. @@ -431,7 +431,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'e8e3f9ada51ddfd611f56fbe6a835b9fb341e331', + 'dawn_revision': '7605d59518e9db1871b0fd13796ca5d323406f94', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -495,7 +495,7 @@ # If you change this, also update the libc++ revision in # //buildtools/deps_revisions.gni. - 'libcxx_revision': 'af83f5d2fada265d8b5adc0a23a29e060907b3e7', + 'libcxx_revision': 'e44019bfac2b2d3ebe1618628884f85c8600e322', # GN CIPD package version. 'gn_version': 'git_revision:41fef642de70ecdcaaa26be96d56a0398f95abd4', @@ -790,7 +790,7 @@ 'src/clank': { 'url': Var('chrome_git') + '/clank/internal/apps.git' + '@' + - 'bac2761c87c46aa392b7c8d18be2c288d3ea943b', + '25a0e75cf4d417f53269c6c6c7aaee7206c6785e', 'condition': 'checkout_android and checkout_src_internal', }, @@ -987,7 +987,7 @@ }, 'src/third_party/androidx_javascriptengine/src': { - 'url': Var('chromium_git') + '/aosp/platform/frameworks/support/javascriptengine/javascriptengine/src.git' + '@' + '82ad02be1a83694592b1c32a974d44cd1da2238b', + 'url': Var('chromium_git') + '/aosp/platform/frameworks/support/javascriptengine/javascriptengine/src.git' + '@' + '5fa7f8147a178691325db20142005742070335dc', 'condition': 'checkout_android', }, @@ -1198,7 +1198,7 @@ # Tools used when building Chrome for Chrome OS. This affects both the Simple # Chrome workflow, as well as the chromeos-chrome ebuild. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '529b06282255290815da45b70a43b91eec1fdbaf', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'cfda6f1ab8b692fad1e5f0a9fc2cee273f19afbb', 'condition': 'checkout_chromeos', }, @@ -1702,7 +1702,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + 'a0ad54d66f52deece55b502bcef0e7451e92cb7c', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b4b873ba9cfeec866c5baf2097167fe6afdf71cb', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1847,7 +1847,7 @@ 'dep_type': 'cipd', }, - 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@379ee8599f0f7da141df2bce100d8ac921403a38', + 'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@623f01c24c99282845b5984880739d76fee13aa9', 'src/third_party/vulkan_memory_allocator': Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + 'ebe84bec02c041d28f902da0214bf442743fc907', @@ -1884,10 +1884,10 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd1b65aa5a88f6efd900604dfcda840154e9f16e2', 'src/third_party/webgpu-cts/src': - Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '147f559d72a3c9642d192466dcaaf245cb720649', + Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'dd474b33f85d63f950fedef2ba889d914c58652d', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '452d94047b5cdce41fdbdad2bec3f24f603dfcf4', + Var('webrtc_git') + '/src.git' + '@' + '6bdb285e2163e70b8f7d4e698b26dcea357e6616', # 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. @@ -1964,7 +1964,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': Var('chrome_git') + '/chrome/src-internal.git@189bc195d4504e8c6cd28310a6b9f0489d454b1b', + 'url': Var('chrome_git') + '/chrome/src-internal.git@ca3fc12c31cde3d7b3672864a5fa77bea98f6874', 'condition': 'checkout_src_internal', }, @@ -2005,7 +2005,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'F64OcssxqyabjGLRpcDbljcEv_sa8tvyZ3NgfJve04EC', + 'version': 'ACYRoNlTD56wvqxxbQBDo3y6aEWjdqhEP9mRWNFcoCYC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 3684c4bb..295cbb6f 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -1170,7 +1170,7 @@ [_THIRD_PARTY_EXCEPT_BLINK], # Don't warn in third_party folders. ), BanRule( - r'/^\s*(import|export|module)\b', + r'/^\s*(export\s|import\s+["<:\w]|module(;|\s+[:\w]))', ( 'Modules are disallowed for now due to lack of toolchain support.', ),
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java index b36f9ab7..6559049e 100644 --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -288,9 +288,6 @@ "Controls whether wake ups are possible for canceled tasks."), Flag.baseFeature(BaseFeatures.REMOVE_CANCELED_TASKS_IN_TASK_QUEUE, "Controls whether or not canceled delayed tasks are removed from task queues."), - Flag.baseFeature(BaseFeatures.ALWAYS_ABANDON_SCHEDULED_TASK, - "Controls whether or not the scheduled task is always abandoned when a timer " - + "is stopped or resets."), Flag.baseFeature(BlinkFeatures.VIEW_TRANSITION, "Enables the experimental View Transitions API." + " See https://github.com/WICG/view-transitions/blob/main/explainer.md."),
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 041e77c6..be838b69 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
@@ -5,15 +5,21 @@ package org.chromium.android_webview.js_sandbox.service; import android.content.res.AssetFileDescriptor; +import android.os.RemoteException; import androidx.javascriptengine.common.Utils; +import org.chromium.android_webview.js_sandbox.common.IJsSandboxConsoleCallback; import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolate; import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateCallback; import org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateSyncCallback; +import org.chromium.base.Log; +import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; +import java.util.concurrent.atomic.AtomicReference; + import javax.annotation.concurrent.GuardedBy; /** @@ -22,17 +28,24 @@ @JNINamespace("android_webview") public class JsSandboxIsolate extends IJsSandboxIsolate.Stub { private static final String TAG = "JsSandboxIsolate"; + // mLock must never be held whilst (synchronously) calling back into the client/embedding + // application, otherwise it's entirely possible for the embedder to then call back into service + // code (on another thread) and then try to take mLock again and therefore deadlock. private final Object mLock = new Object(); + private final JsSandboxService mService; + private final AtomicReference<IJsSandboxConsoleCallback> mConsoleCallback = + new AtomicReference<IJsSandboxConsoleCallback>(); @GuardedBy("mLock") private long mJsSandboxIsolate; - JsSandboxIsolate() { - mJsSandboxIsolate = JsSandboxIsolateJni.get().createNativeJsSandboxIsolateWrapper(0); + JsSandboxIsolate(JsSandboxService service) { + this(service, 0); } - JsSandboxIsolate(long maxHeapSizeBytes) { - mJsSandboxIsolate = - JsSandboxIsolateJni.get().createNativeJsSandboxIsolateWrapper(maxHeapSizeBytes); + JsSandboxIsolate(JsSandboxService service, long maxHeapSizeBytes) { + mService = service; + mJsSandboxIsolate = JsSandboxIsolateJni.get().createNativeJsSandboxIsolateWrapper( + this, maxHeapSizeBytes); } @Override @@ -86,13 +99,66 @@ } } + // Called by isolate thread + @CalledByNative + public void consoleMessage(int contextGroupId, int level, String message, String source, + int line, int column, String trace) { + final IJsSandboxConsoleCallback callback = mConsoleCallback.get(); + if (callback == null) { + return; + } + final int messageLimit = 32768; + final int sourceLimit = 4096; + final int traceLimit = 16384; + if (message != null && message.length() > messageLimit) { + message = message.substring(0, messageLimit); + } + if (source != null && source.length() > sourceLimit) { + source = source.substring(0, sourceLimit); + } + if (trace != null && trace.length() > traceLimit) { + trace = trace.substring(0, traceLimit); + } + try { + callback.consoleMessage(contextGroupId, level, message, source, line, column, trace); + } catch (RemoteException e) { + Log.e(TAG, "consoleMessage notification failed", e); + } + } + + // Called by isolate thread + @CalledByNative + public void consoleClear(int contextGroupId) { + final IJsSandboxConsoleCallback callback = mConsoleCallback.get(); + if (callback == null) { + return; + } + try { + callback.consoleClear(contextGroupId); + } catch (RemoteException e) { + Log.e(TAG, "consoleClear notification failed", e); + } + } + + @Override + public void setConsoleCallback(IJsSandboxConsoleCallback callback) { + synchronized (mLock) { + if (mJsSandboxIsolate == 0) { + throw new IllegalStateException("setConsoleCallback() called after close()"); + } + mConsoleCallback.set(callback); + JsSandboxIsolateJni.get().setConsoleEnabled(mJsSandboxIsolate, this, callback != null); + } + } + public static void initializeEnvironment() { JsSandboxIsolateJni.get().initializeEnvironment(); } @NativeMethods public interface Natives { - long createNativeJsSandboxIsolateWrapper(long maxHeapSizeBytes); + long createNativeJsSandboxIsolateWrapper( + JsSandboxIsolate jsSandboxIsolate, long maxHeapSizeBytes); void initializeEnvironment(); @@ -107,5 +173,8 @@ boolean provideNamedData(long nativeJsSandboxIsolate, JsSandboxIsolate caller, String name, int fd, int length); + + void setConsoleEnabled( + long nativeJsSandboxIsolate, JsSandboxIsolate caller, boolean enable); } }
diff --git a/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxService.java b/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxService.java index ceace0a..dbee55e 100644 --- a/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxService.java +++ b/android_webview/js_sandbox/java/src/org/chromium/android_webview/js_sandbox/service/JsSandboxService.java
@@ -25,17 +25,27 @@ static final List<String> SUPPORTED_FEATURES = Arrays.asList( IJsSandboxService.ISOLATE_TERMINATION, IJsSandboxService.WASM_FROM_ARRAY_BUFFER, IJsSandboxService.ISOLATE_MAX_HEAP_SIZE_LIMIT, - IJsSandboxService.EVALUATE_WITHOUT_TRANSACTION_LIMIT); + IJsSandboxService.EVALUATE_WITHOUT_TRANSACTION_LIMIT, + IJsSandboxService.CONSOLE_MESSAGING); + + /** + * Feature for {@link #isClientSideFeatureSupported(String)}. + * <p> + * When this feature is present, consoleMessage and consoleClear notifications are supported by + * the client. + * @hide + */ + public static final String JS_FEATURE_CONSOLE_MESSAGING = "JS_FEATURE_CONSOLE_MESSAGING"; private final IJsSandboxService.Stub mBinder = new IJsSandboxService.Stub() { @Override public IJsSandboxIsolate createIsolate() { - return new JsSandboxIsolate(); + return new JsSandboxIsolate(JsSandboxService.this); } @Override public IJsSandboxIsolate createIsolateWithMaxHeapSizeBytes(long maxHeapSizeBytes) { - return new JsSandboxIsolate(maxHeapSizeBytes); + return new JsSandboxIsolate(JsSandboxService.this, maxHeapSizeBytes); } @Override
diff --git a/android_webview/js_sandbox/service/js_sandbox_isolate.cc b/android_webview/js_sandbox/service/js_sandbox_isolate.cc index fff98664..61c02b0e 100644 --- a/android_webview/js_sandbox/service/js_sandbox_isolate.cc +++ b/android_webview/js_sandbox/service/js_sandbox_isolate.cc
@@ -24,6 +24,7 @@ #include "base/logging.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" +#include "base/notreached.h" #include "base/numerics/safe_math.h" #include "base/strings/string_piece.h" #include "base/synchronization/waitable_event.h" @@ -33,6 +34,7 @@ #include "base/task/thread_pool.h" #include "base/task/thread_pool/thread_pool_instance.h" #include "base/threading/thread_restrictions.h" +#include "base/time/time.h" #include "gin/arguments.h" #include "gin/array_buffer.h" #include "gin/function_template.h" @@ -43,6 +45,8 @@ #include "js_sandbox_isolate.h" #include "v8/include/v8-array-buffer.h" #include "v8/include/v8-function.h" +#include "v8/include/v8-inspector.h" +#include "v8/include/v8-isolate.h" #include "v8/include/v8-microtask-queue.h" #include "v8/include/v8-statistics.h" #include "v8/include/v8-template.h" @@ -113,6 +117,47 @@ return GetStackTrace(message, isolate); } +jint remapConsoleMessageErrorLevel(const v8::Isolate::MessageErrorLevel level) { + // Converted level should match the values specified in the + // org.chromium.android_webview.js_sandbox.common.IJsSandboxIsolateClient AIDL + // file (in AndroidX). + // + // These will probably remain identical to the underlying v8 enums/constants, + // but are mapped explicitly here to ensure we can maintain compatibility even + // if there are changes or additions. + switch (level) { + case v8::Isolate::MessageErrorLevel::kMessageLog: + return 1 << 0; + case v8::Isolate::MessageErrorLevel::kMessageDebug: + return 1 << 1; + case v8::Isolate::MessageErrorLevel::kMessageInfo: + return 1 << 2; + case v8::Isolate::MessageErrorLevel::kMessageError: + return 1 << 3; + case v8::Isolate::MessageErrorLevel::kMessageWarning: + return 1 << 4; + case v8::Isolate::MessageErrorLevel::kMessageAll: + NOTREACHED_NORETURN(); + } +} + +// Converts a V8 inspector (UTF-8 or UTF-16) StringView to a jstring. +base::android::ScopedJavaLocalRef<jstring> StringViewToJavaString( + JNIEnv* const env, + const v8_inspector::StringView& string_view) { + if (string_view.is8Bit()) { + return base::android::ConvertUTF8ToJavaString( + env, base::StringPiece( + reinterpret_cast<const char*>(string_view.characters8()), + string_view.length())); + } else { + return base::android::ConvertUTF16ToJavaString( + env, base::StringPiece16( + reinterpret_cast<const char16_t*>(string_view.characters16()), + string_view.length())); + } +} + void WasmAsyncResolvePromiseCallback(v8::Isolate* isolate, v8::Local<v8::Context> context, v8::Local<v8::Promise::Resolver> resolver, @@ -127,6 +172,17 @@ } } +class NoopInspectorChannel final : public v8_inspector::V8Inspector::Channel { + public: + ~NoopInspectorChannel() override = default; + void sendResponse( + int callId, + std::unique_ptr<v8_inspector::StringBuffer> message) override {} + void sendNotification( + std::unique_ptr<v8_inspector::StringBuffer> message) override {} + void flushProtocolNotifications() override {} +}; + } // namespace namespace android_webview { @@ -147,8 +203,69 @@ length = len; } -JsSandboxIsolate::JsSandboxIsolate(const size_t max_heap_size_bytes) - : isolate_max_heap_size_bytes_(max_heap_size_bytes), +// This class must only be constructed, destructed, and used from the isolate +// thread. +class JsSandboxIsolate::InspectorClient final + : public v8_inspector::V8InspectorClient { + public: + explicit InspectorClient(JsSandboxIsolate& isolate) : isolate_(isolate) {} + + ~InspectorClient() override = default; + + void consoleAPIMessage(const int context_group_id, + const v8::Isolate::MessageErrorLevel level, + const v8_inspector::StringView& message, + const v8_inspector::StringView& url, + const unsigned int line_number, + const unsigned int column_number, + v8_inspector::V8StackTrace* const trace) override { + if (!isolate_->console_enabled_) { + return; + } + + JNIEnv* env = base::android::AttachCurrentThread(); + const jint converted_level = remapConsoleMessageErrorLevel(level); + base::android::ScopedJavaLocalRef<jstring> java_string_message = + StringViewToJavaString(env, message); + // url is actually just the source (file/expression) identifier. + base::android::ScopedJavaLocalRef<jstring> java_string_source = + StringViewToJavaString(env, url); + base::android::ScopedJavaLocalRef<jstring> java_string_trace; + if (trace && !trace->isEmpty()) { + StringViewToJavaString(env, trace->toString()->string()); + } + + android_webview::Java_JsSandboxIsolate_consoleMessage( + env, isolate_->j_isolate_, static_cast<jint>(context_group_id), + converted_level, java_string_message, java_string_source, + base::saturated_cast<jint>(line_number), + base::saturated_cast<jint>(column_number), java_string_trace); + } + + void consoleClear(const int context_group_id) override { + if (!isolate_->console_enabled_) { + return; + } + JNIEnv* env = base::android::AttachCurrentThread(); + android_webview::Java_JsSandboxIsolate_consoleClear( + env, isolate_->j_isolate_, static_cast<jint>(context_group_id)); + } + + double currentTimeMS() override { + // Note: although this is not monotonically increasing time, this reflects + // the behaviour of Blink code. + return base::Time::Now().ToDoubleT() * 1000.0; + } + + private: + const base::raw_ref<JsSandboxIsolate> isolate_; +}; + +JsSandboxIsolate::JsSandboxIsolate( + const base::android::JavaParamRef<jobject>& j_isolate, + const size_t max_heap_size_bytes) + : j_isolate_(j_isolate), + isolate_max_heap_size_bytes_(max_heap_size_bytes), array_buffer_allocator_(std::make_unique<JsSandboxArrayBufferAllocator>( *gin::ArrayBufferAllocator::SharedInstance(), max_heap_size_bytes > 0 @@ -244,6 +361,17 @@ .second; } +// Called from Binder thread. +void JsSandboxIsolate::SetConsoleEnabled( + JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const jboolean enable) { + control_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&JsSandboxIsolate::SetConsoleEnabledOnControlThread, + base::Unretained(this), enable)); +} + // Called from control sequence. void JsSandboxIsolate::PostEvaluationToIsolateThread( const std::string code, @@ -722,6 +850,53 @@ isolate_holder_->isolate(), std::move(backing_store))); } +// Called from isolate thread. +void JsSandboxIsolate::EnableOrDisableInspectorAsNeeded() { + const bool needed = console_enabled_; + const bool already_enabled = bool{inspector_client_}; + + if (already_enabled && !needed) { + inspector_session_.reset(); + inspector_channel_.reset(); + inspector_.reset(); + inspector_client_.reset(); + } else if (!already_enabled && needed) { + v8::Isolate::Scope isolate_scope(isolate_holder_->isolate()); + v8::HandleScope handle_scope(isolate_holder_->isolate()); + v8::Context::Scope scope(context_holder_->context()); + + constexpr int context_group_id = 1; + inspector_client_ = std::make_unique<InspectorClient>(*this); + inspector_ = v8_inspector::V8Inspector::create(isolate_holder_->isolate(), + inspector_client_.get()); + inspector_channel_ = + static_cast<std::unique_ptr<v8_inspector::V8Inspector::Channel>>( + std::make_unique<NoopInspectorChannel>()); + inspector_session_ = + inspector_->connect(context_group_id, inspector_channel_.get(), + /*state=*/v8_inspector::StringView(), + v8_inspector::V8Inspector::kFullyTrusted, + v8_inspector::V8Inspector::kNotWaitingForDebugger); + inspector_->contextCreated(v8_inspector::V8ContextInfo( + context_holder_->context(), context_group_id, + /*humanReadableName=*/v8_inspector::StringView())); + } +} + +// Called from control sequence. +void JsSandboxIsolate::SetConsoleEnabledOnControlThread(const bool enable) { + cancelable_task_tracker_->PostTask( + isolate_task_runner_.get(), FROM_HERE, + base::BindOnce(&JsSandboxIsolate::SetConsoleEnabledOnIsolateThread, + base::Unretained(this), enable)); +} + +// Called from isolate thread. +void JsSandboxIsolate::SetConsoleEnabledOnIsolateThread(const bool enable) { + console_enabled_ = enable; + EnableOrDisableInspectorAsNeeded(); +} + static void JNI_JsSandboxIsolate_InitializeEnvironment(JNIEnv* env) { base::ThreadPoolInstance::CreateAndStartWithDefaultParams("JsSandboxIsolate"); #ifdef V8_USE_EXTERNAL_STARTUP_DATA @@ -733,10 +908,11 @@ static jlong JNI_JsSandboxIsolate_CreateNativeJsSandboxIsolateWrapper( JNIEnv* env, + const base::android::JavaParamRef<jobject>& j_sandbox_isolate, jlong max_heap_size_bytes) { CHECK_GE(max_heap_size_bytes, 0); - JsSandboxIsolate* processor = - new JsSandboxIsolate(base::saturated_cast<size_t>(max_heap_size_bytes)); + JsSandboxIsolate* processor = new JsSandboxIsolate( + j_sandbox_isolate, base::saturated_cast<size_t>(max_heap_size_bytes)); return reinterpret_cast<intptr_t>(processor); }
diff --git a/android_webview/js_sandbox/service/js_sandbox_isolate.h b/android_webview/js_sandbox/service/js_sandbox_isolate.h index f443e91a..c90ad64 100644 --- a/android_webview/js_sandbox/service/js_sandbox_isolate.h +++ b/android_webview/js_sandbox/service/js_sandbox_isolate.h
@@ -17,6 +17,7 @@ #include "base/synchronization/lock.h" #include "base/thread_annotations.h" #include "v8/include/v8-array-buffer.h" +#include "v8/include/v8-inspector.h" #include "v8/include/v8-promise.h" namespace base { @@ -43,7 +44,9 @@ class JsSandboxIsolate { public: - explicit JsSandboxIsolate(size_t max_heap_size_bytes = 0); + explicit JsSandboxIsolate( + const base::android::JavaParamRef<jobject>& j_isolate_, + size_t max_heap_size_bytes); ~JsSandboxIsolate(); jboolean EvaluateJavascript( @@ -64,10 +67,18 @@ const base::android::JavaParamRef<jstring>& jname, const jint fd, const jint length); + // May enable or disable inspection, as needed. + void SetConsoleEnabled(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + jboolean enable); private: + class InspectorClient; + void DeleteSelf(); void InitializeIsolateOnThread(); + // Will enabled or disable inspection depending on whether any dynamic + // features require it (for example, console logging). void EvaluateJavascriptOnThread( const std::string code, scoped_refptr<JsSandboxIsolateCallback> callback); @@ -121,6 +132,13 @@ [[noreturn]] void MemoryLimitExceeded(); [[noreturn]] void FreezeThread(); + void EnableOrDisableInspectorAsNeeded(); + void SetConsoleEnabledOnControlThread(bool enable); + void SetConsoleEnabledOnIsolateThread(bool enable); + + // Java-side JsSandboxIsolate object corresponding to this isolate. + const base::android::ScopedJavaGlobalRef<jobject> j_isolate_; + // V8 heap size limit. Must be non-negative. // // 0 indicates no explicit limit (but use the default V8 limits). @@ -157,6 +175,15 @@ // // This pointer must only be accessed from the isolate thread. JsSandboxIsolateCallback* current_callback_; + + bool console_enabled_; + + // Inspector objects should be destructed before anything they're inspecting, + // so they are later in the field list. + std::unique_ptr<v8_inspector::V8InspectorClient> inspector_client_; + std::unique_ptr<v8_inspector::V8Inspector> inspector_; + std::unique_ptr<v8_inspector::V8Inspector::Channel> inspector_channel_; + std::unique_ptr<v8_inspector::V8InspectorSession> inspector_session_; }; } // namespace android_webview
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index cb93e552..d018d467 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -607,6 +607,8 @@ "glanceables/glanceables_welcome_label.cc", "glanceables/glanceables_welcome_label.h", "glanceables/tasks/glanceables_tasks_client.h", + "glanceables/tasks/glanceables_tasks_types.cc", + "glanceables/tasks/glanceables_tasks_types.h", "host/ash_window_tree_host.cc", "host/ash_window_tree_host.h", "host/ash_window_tree_host_delegate.h",
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc index bee22e07..cf5badb 100644 --- a/ash/constants/ash_features.cc +++ b/ash/constants/ash_features.cc
@@ -317,6 +317,11 @@ "CaptureModeDemoTools", base::FEATURE_ENABLED_BY_DEFAULT); +// Enables the tour that walks new users through the Capture Mode feature. +BASE_FEATURE(kCaptureModeTour, + "CaptureModeTour", + base::FEATURE_DISABLED_BY_DEFAULT); + // If enabled, allow eSIM installation bypass the non-cellular internet // connectivity check. BASE_FEATURE(kCellularBypassESimInstallationConnectivityCheck, @@ -335,6 +340,13 @@ "CheckPasswordsAgainstCryptohomeHelper", base::FEATURE_DISABLED_BY_DEFAULT); +// When enabled alongside the keyboard auto-repeat setting, holding down Ctrl+V +// will cause the clipboard history menu to show. From there, the user can +// select a clipboard history item to replace the initially pasted content. +BASE_FEATURE(kClipboardHistoryLongpress, + "ClipboardHistoryLongpress", + base::FEATURE_DISABLED_BY_DEFAULT); + // If enabled, the clipboard nudge shown prefs will be reset at the start of // each new user session. BASE_FEATURE(kClipboardHistoryNudgeSessionReset, @@ -353,13 +365,6 @@ "ClipboardHistoryReorder", base::FEATURE_DISABLED_BY_DEFAULT); -// When enabled alongside the keyboard auto-repeat setting, holding down Ctrl+V -// will cause the clipboard history menu to show. From there, the user can -// select a clipboard history item to replace the initially pasted content. -BASE_FEATURE(kClipboardHistorySelector, - "ClipboardHistorySelector", - base::FEATURE_DISABLED_BY_DEFAULT); - // If enabled and account falls under the new deal, will be allowed to toggle // auto updates. BASE_FEATURE(kConsumerAutoUpdateToggleAllowed, @@ -1148,6 +1153,11 @@ "HoldingSpaceSuggestions", base::FEATURE_DISABLED_BY_DEFAULT); +// Enables the tour that walks new users through the Holding Space feature. +BASE_FEATURE(kHoldingSpaceTour, + "HoldingSpaceTour", + base::FEATURE_DISABLED_BY_DEFAULT); + // Enables a call-to-action label beside the home button. BASE_FEATURE(kHomeButtonWithText, "HomeButtonWithText", @@ -1629,7 +1639,7 @@ // screen. BASE_FEATURE(kPolicyProvidedTrustAnchorsAllowedAtLockScreen, "PolicyProvidedTrustAnchorsAllowedAtLockScreen", - base::FEATURE_DISABLED_BY_DEFAULT); + base::FEATURE_ENABLED_BY_DEFAULT); // Enables or disables the preference of using constant frame rate for camera // when streaming. @@ -1889,6 +1899,11 @@ "ShimlessRMADisableDarkMode", base::FEATURE_ENABLED_BY_DEFAULT); +// Enables or disables the diagnostic page in the Shimless RMA flow. +BASE_FEATURE(kShimlessRMADiagnosticPage, + "ShimlessRMADiagnosticPage", + base::FEATURE_DISABLED_BY_DEFAULT); + // Enables or disables a toggle to enable Bluetooth debug logs. BASE_FEATURE(kShowBluetoothDebugLogToggle, "ShowBluetoothDebugLogToggle", @@ -2432,6 +2447,10 @@ return base::FeatureList::IsEnabled(kCaptivePortalErrorPage); } +bool IsCaptureModeTourEnabled() { + return base::FeatureList::IsEnabled(kCaptureModeTour); +} + bool IsCheckPasswordsAgainstCryptohomeHelperEnabled() { return base::FeatureList::IsEnabled(kCheckPasswordsAgainstCryptohomeHelper); } @@ -2440,6 +2459,10 @@ return base::FeatureList::IsEnabled(kChromadAvailable); } +bool IsClipboardHistoryLongpressEnabled() { + return base::FeatureList::IsEnabled(kClipboardHistoryLongpress); +} + bool IsClipboardHistoryNudgeSessionResetEnabled() { return base::FeatureList::IsEnabled(kClipboardHistoryNudgeSessionReset); } @@ -2452,10 +2475,6 @@ return base::FeatureList::IsEnabled(kClipboardHistoryReorder); } -bool IsClipboardHistorySelectorEnabled() { - return base::FeatureList::IsEnabled(kClipboardHistorySelector); -} - bool IsCryptauthAttestationSyncingEnabled() { return base::FeatureList::IsEnabled(kCryptauthAttestationSyncing); } @@ -2710,6 +2729,10 @@ return base::FeatureList::IsEnabled(kHoldingSpaceSuggestions); } +bool IsHoldingSpaceTourEnabled() { + return base::FeatureList::IsEnabled(kHoldingSpaceTour); +} + bool IsHomeButtonWithTextEnabled() { return base::FeatureList::IsEnabled(kHomeButtonWithText); } @@ -3175,6 +3198,10 @@ return base::FeatureList::IsEnabled(kShimlessRMADisableDarkMode); } +bool IsShimlessRMADiagnosticPageEnabled() { + return base::FeatureList::IsEnabled(kShimlessRMADiagnosticPage); +} + bool IsSmdsDbusMigrationEnabled() { return base::FeatureList::IsEnabled(kSmdsDbusMigration); } @@ -3246,6 +3273,11 @@ return base::FeatureList::IsEnabled(kUseStorkSmdsServerAddress); } +bool IsUserEducationEnabled() { + return IsCaptureModeTourEnabled() || IsHoldingSpaceTourEnabled() || + IsWelcomeTourEnabled(); +} + bool IsVideoConferenceEnabled() { return base::FeatureList::IsEnabled(kVideoConference) && switches::IsCameraEffectsSupportedByHardware();
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h index 0311d44..621bc56 100644 --- a/ash/constants/ash_features.h +++ b/ash/constants/ash_features.h
@@ -93,6 +93,7 @@ BASE_DECLARE_FEATURE(kCameraPrivacySwitchNotifications); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCaptivePortalErrorPage); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCaptureModeDemoTools); +COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCaptureModeTour); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCellularBypassESimInstallationConnectivityCheck); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kCellularUseSecondEuicc); @@ -100,10 +101,11 @@ BASE_DECLARE_FEATURE(kCheckPasswordsAgainstCryptohomeHelper); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kChromadAvailable); COMPONENT_EXPORT(ASH_CONSTANTS) +BASE_DECLARE_FEATURE(kClipboardHistoryLongpress); +COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kClipboardHistoryNudgeSessionReset); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kClipboardHistoryRefresh); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kClipboardHistoryReorder); -COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kClipboardHistorySelector); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kConsumerAutoUpdateToggleAllowed); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kContextualNudges); @@ -350,6 +352,7 @@ BASE_DECLARE_FEATURE(kHoldingSpacePredictability); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHoldingSpaceRefresh); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHoldingSpaceSuggestions); +COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHoldingSpaceTour); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kHotspot); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kVirtualKeyboardNewHeader); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kImeDownloaderUpdate); @@ -541,6 +544,8 @@ COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kShimlessRMAFlow); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kShimlessRMAOsUpdate); COMPONENT_EXPORT(ASH_CONSTANTS) +BASE_DECLARE_FEATURE(kShimlessRMADiagnosticPage); +COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kShimlessRMADisableDarkMode); COMPONENT_EXPORT(ASH_CONSTANTS) BASE_DECLARE_FEATURE(kShowBluetoothDebugLogToggle); @@ -665,14 +670,15 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsBluetoothQualityReportEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCalendarJellyEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCaptivePortalErrorPageEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCaptureModeTourEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCheckPasswordsAgainstCryptohomeHelperEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsChromadAvailableEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsClipboardHistoryLongpressEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsClipboardHistoryNudgeSessionResetEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsClipboardHistoryRefreshEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsClipboardHistoryReorderEnabled(); -COMPONENT_EXPORT(ASH_CONSTANTS) bool IsClipboardHistorySelectorEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsConsumerAutoUpdateToggleAllowed(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCrosPrivacyHubEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsCrosPrivacyHubV0Enabled(); @@ -745,6 +751,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpacePredictabilityEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceRefreshEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceSuggestionsEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHoldingSpaceTourEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHomeButtonWithTextEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHostnameSettingEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsHotspotEnabled(); @@ -868,6 +875,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsShelfPalmRejectionSwipeOffsetEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsShelfStackedHotseatEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsSimLockPolicyEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsShimlessRMADiagnosticPageEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsShimlessRMAFlowEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsShimlessRMAOsUpdateEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsShimlessRMADarkModeDisabled(); @@ -891,6 +899,7 @@ COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUploadOfficeToCloudEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseLoginShelfWidgetEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUseStorkSmdsServerAddressEnabled(); +COMPONENT_EXPORT(ASH_CONSTANTS) bool IsUserEducationEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVideoConferenceEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVcBackgroundReplaceEnabled(); COMPONENT_EXPORT(ASH_CONSTANTS) bool IsVcControlsUiFakeEffectsEnabled();
diff --git a/ash/glanceables/tasks/glanceables_tasks_client.h b/ash/glanceables/tasks/glanceables_tasks_client.h index 023d59d..7aad735 100644 --- a/ash/glanceables/tasks/glanceables_tasks_client.h +++ b/ash/glanceables/tasks/glanceables_tasks_client.h
@@ -6,28 +6,34 @@ #define ASH_GLANCEABLES_TASKS_GLANCEABLES_TASKS_CLIENT_H_ #include <string> +#include <vector> #include "ash/ash_export.h" #include "base/functional/callback_forward.h" -#include "google_apis/tasks/tasks_api_requests.h" namespace ash { +struct GlanceablesTask; +struct GlanceablesTaskList; + // Interface for the tasks browser client. class ASH_EXPORT GlanceablesTasksClient { public: + using GetTaskListsCallback = base::OnceCallback<void( + const std::vector<GlanceablesTaskList>& task_lists)>; + using GetTasksCallback = + base::OnceCallback<void(const std::vector<GlanceablesTask>& tasks)>; + // Fetches all the authenticated user's task lists and invokes `callback` when // done. // Returned `base::OnceClosure` can cancel the api call. - virtual base::OnceClosure GetTaskLists( - google_apis::tasks::ListTaskListsRequest::Callback callback) = 0; + virtual base::OnceClosure GetTaskLists(GetTaskListsCallback callback) = 0; // Fetches all tasks in the specified task list (`task_list_id` must not be // empty) and invokes `callback` when done. // Returned `base::OnceClosure` can cancel the api call. - virtual base::OnceClosure GetTasks( - google_apis::tasks::ListTasksRequest::Callback callback, - const std::string& task_list_id) = 0; + virtual base::OnceClosure GetTasks(GetTasksCallback callback, + const std::string& task_list_id) = 0; protected: virtual ~GlanceablesTasksClient() = default;
diff --git a/ash/glanceables/tasks/glanceables_tasks_types.cc b/ash/glanceables/tasks/glanceables_tasks_types.cc new file mode 100644 index 0000000..59b38a5 --- /dev/null +++ b/ash/glanceables/tasks/glanceables_tasks_types.cc
@@ -0,0 +1,29 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/glanceables/tasks/glanceables_tasks_types.h" + +namespace ash { + +GlanceablesTaskList::GlanceablesTaskList(const std::string& id, + const std::string& title, + const base::Time& updated) + : id(id), title(title), updated(updated) {} + +GlanceablesTaskList::~GlanceablesTaskList() = default; + +// ---------------------------------------------------------------------------- +// GlanceablesTask: + +GlanceablesTask::GlanceablesTask(const std::string& id, + const std::string& title, + bool completed, + const std::vector<GlanceablesTask>& subtasks) + : id(id), title(title), completed(completed), subtasks(subtasks) {} + +GlanceablesTask::GlanceablesTask(const GlanceablesTask&) = default; + +GlanceablesTask::~GlanceablesTask() = default; + +} // namespace ash
diff --git a/ash/glanceables/tasks/glanceables_tasks_types.h b/ash/glanceables/tasks/glanceables_tasks_types.h new file mode 100644 index 0000000..3a2d1337 --- /dev/null +++ b/ash/glanceables/tasks/glanceables_tasks_types.h
@@ -0,0 +1,68 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ASH_GLANCEABLES_TASKS_GLANCEABLES_TASKS_TYPES_H_ +#define ASH_GLANCEABLES_TASKS_GLANCEABLES_TASKS_TYPES_H_ + +#include <string> +#include <vector> + +#include "ash/ash_export.h" +#include "base/time/time.h" + +namespace ash { + +// Lightweight TaskList definition to separate API and ash/ui-friendly types. +// Contains information that describes a single task list. All values are from +// the API resource +// https://developers.google.com/tasks/reference/rest/v1/tasklists. +struct ASH_EXPORT GlanceablesTaskList { + GlanceablesTaskList() = delete; + GlanceablesTaskList(const std::string& id, + const std::string& title, + const base::Time& updated); + ~GlanceablesTaskList(); + + // Task list identifier. + const std::string id; + + // Title of the task list. + const std::string title; + + // Last modification time of the task list. + const base::Time updated; +}; + +// Lightweight Task definition to separate API and ash/ui-friendly types. +// The most significant difference is that API tasks are flat (subtask-task +// relationship is expressed by parent id property), but here they are +// represented as a tree structure. All values are from the API resource +// https://developers.google.com/tasks/reference/rest/v1/tasks. +struct ASH_EXPORT GlanceablesTask { + GlanceablesTask() = delete; + GlanceablesTask(const std::string& id, + const std::string& title, + bool completed, + const std::vector<GlanceablesTask>& subtasks); + GlanceablesTask(const GlanceablesTask&); + ~GlanceablesTask(); + + // Task identifier. + const std::string id; + + // Title of the task. + const std::string title; + + // Indicates whether the task is completed (has "status" field equals to + // "completed" on the API side). + bool completed; + + // Subtasks of the task (pre-grouped tasks that have "parent" field equals to + // `id` on the API side). + const std::vector<GlanceablesTask> subtasks; +}; + +} // namespace ash + +#endif // ASH_GLANCEABLES_TASKS_GLANCEABLES_TASKS_TYPES_H_
diff --git a/ash/quick_pair/fast_pair_handshake/fast_pair_encryption_unittest.cc b/ash/quick_pair/fast_pair_handshake/fast_pair_encryption_unittest.cc index 5981dd58..500feea5 100644 --- a/ash/quick_pair/fast_pair_handshake/fast_pair_encryption_unittest.cc +++ b/ash/quick_pair/fast_pair_handshake/fast_pair_encryption_unittest.cc
@@ -122,21 +122,29 @@ EXPECT_NE(GenerateHmacSha256(secret_key, nonce, input), expected); } -TEST_F(FastPairEncryptionTest, GenerateHmacSha256_EmptyData) { - const std::vector<uint8_t> input = {}; +TEST_F(FastPairEncryptionTest, GenerateHmacSha256_EmptyParamCombos_NoCrash) { + const std::vector<uint8_t> input = {0xEE, 0x4A, 0x24, 0x83, 0x73, 0x80, 0x52, + 0xE4, 0x4E, 0x9B, 0x2A, 0x14, 0x5E, 0x5D, + 0xDF, 0xAA, 0x44, 0xB9, 0xE5, 0x53, 0x6A, + 0xF4, 0x38, 0xE1, 0xE5, 0xC6}; - const std::array<uint8_t, kNonceSizeBytes> nonce = {}; + const std::array<uint8_t, kNonceSizeBytes> nonce = {0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07}; const std::array<uint8_t, kSecretKeySizeBytes> secret_key = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; - - const std::array<uint8_t, kHmacSizeBytes> expected = { - 0xBB, 0x07, 0xA3, 0xDE, 0x98, 0xC4, 0x97, 0x9C, 0x5F, 0x52, 0x19, - 0x39, 0x9F, 0xCB, 0xDA, 0xEB, 0xA3, 0x7E, 0xD7, 0xFA, 0x84, 0xAA, - 0x28, 0x2A, 0x76, 0xCF, 0xF3, 0xB6, 0x30, 0x36, 0x7E, 0x10}; - - EXPECT_EQ(GenerateHmacSha256(secret_key, nonce, input), expected); + std::vector<uint8_t> empty_input; + std::array<uint8_t, kNonceSizeBytes> empty_nonce; + std::array<uint8_t, kSecretKeySizeBytes> empty_secret_key; + for (size_t i = 0; i < 2; i++) { + for (size_t j = 0; j < 2; j++) { + for (size_t k = 0; k < 2; k++) { + GenerateHmacSha256(i ? secret_key : empty_secret_key, + j ? nonce : empty_nonce, k ? input : empty_input); + } + } + } } TEST_F(FastPairEncryptionTest, GenerateHmacSha256_OneByteData) { @@ -217,6 +225,29 @@ EXPECT_EQ(EncryptAdditionalData(secret_key, nonce, input), expected); } +TEST_F(FastPairEncryptionTest, EncryptAdditionalData_EmptyParamCombos_NoCrash) { + std::vector<uint8_t> input = {0x53, 0x6F, 0x6D, 0x65, 0x6F, 0x6E, 0x65, + 0x27, 0x73, 0x20, 0x47, 0x6F, 0x6F, 0x67, + 0x6C, 0x65, 0x20, 0x48, 0x65, 0x61, 0x64, + 0x70, 0x68, 0x6F, 0x6E, 0x65}; + std::array<uint8_t, kSecretKeySizeBytes> secret_key = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; + std::array<uint8_t, kNonceSizeBytes> nonce = {0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07}; + std::vector<uint8_t> empty_input; + std::array<uint8_t, kNonceSizeBytes> empty_nonce; + std::array<uint8_t, kSecretKeySizeBytes> empty_secret_key; + for (size_t i = 0; i < 2; i++) { + for (size_t j = 0; j < 2; j++) { + for (size_t k = 0; k < 2; k++) { + EncryptAdditionalData(i ? secret_key : empty_secret_key, + j ? nonce : empty_nonce, k ? input : empty_input); + } + } + } +} + TEST_F(FastPairEncryptionTest, EncryptAdditionalData_OneByteData) { const std::vector<uint8_t> input = {0x00};
diff --git a/ash/shelf/drag_handle.cc b/ash/shelf/drag_handle.cc index 46282a9..b8433fe 100644 --- a/ash/shelf/drag_handle.cc +++ b/ash/shelf/drag_handle.cc
@@ -167,7 +167,8 @@ hide_drag_handle_nudge_timer_.Start( FROM_HERE, nudge_duration, base::BindOnce(&DragHandle::HideDragHandleNudge, base::Unretained(this), - contextual_tooltip::DismissNudgeReason::kTimeout)); + contextual_tooltip::DismissNudgeReason::kTimeout, + /*animate=*/true)); } contextual_tooltip::HandleNudgeShown( pref, contextual_tooltip::TooltipType::kInAppToHome); @@ -192,7 +193,8 @@ } void DragHandle::HideDragHandleNudge( - contextual_tooltip::DismissNudgeReason reason) { + contextual_tooltip::DismissNudgeReason reason, + bool animate) { StopDragHandleNudgeShowTimer(); if (!gesture_nudge_target_visibility()) return; @@ -206,8 +208,9 @@ contextual_tooltip::TooltipType::kInAppToHome); } - HideDragHandleNudgeHelper(/*hidden_by_tap=*/reason == - contextual_tooltip::DismissNudgeReason::kTap); + HideDragHandleNudgeHelper( + /*hidden_by_tap=*/reason == contextual_tooltip::DismissNudgeReason::kTap, + animate); gesture_nudge_target_visibility_ = false; } @@ -230,7 +233,8 @@ hide_drag_handle_nudge_timer_.Stop(); } else { HideDragHandleNudge( - contextual_tooltip::DismissNudgeReason::kPerformedGesture); + contextual_tooltip::DismissNudgeReason::kPerformedGesture, + /*animate=*/true); } } @@ -336,7 +340,8 @@ SplitViewController::State state) { if (SplitViewController::Get(shelf_->shelf_widget()->GetNativeWindow()) ->InSplitViewMode()) { - HideDragHandleNudge(contextual_tooltip::DismissNudgeReason::kOther); + HideDragHandleNudge(contextual_tooltip::DismissNudgeReason::kOther, + /*animate=*/true); } } @@ -431,7 +436,15 @@ } } -void DragHandle::HideDragHandleNudgeHelper(bool hidden_by_tap) { +void DragHandle::HideDragHandleNudgeHelper(bool hidden_by_tap, bool animate) { + if (!animate) { + ScheduleDragHandleTranslationAnimation( + 0, base::TimeDelta(), gfx::Tween::ZERO, + ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + drag_handle_nudge_->GetWidget()->CloseWithReason( + views::Widget::ClosedReason::kUnspecified); + return; + } ScheduleDragHandleTranslationAnimation( 0, hidden_by_tap ? kInAppToHomeHideOnTapAnimationDuration @@ -495,7 +508,8 @@ void DragHandle::HandleTapOnNudge() { if (!drag_handle_nudge_) return; - HideDragHandleNudge(contextual_tooltip::DismissNudgeReason::kTap); + HideDragHandleNudge(contextual_tooltip::DismissNudgeReason::kTap, + /*animate=*/true); } void DragHandle::StopDragHandleNudgeShowTimer() {
diff --git a/ash/shelf/drag_handle.h b/ash/shelf/drag_handle.h index fd97c01..37c43bd 100644 --- a/ash/shelf/drag_handle.h +++ b/ash/shelf/drag_handle.h
@@ -60,7 +60,8 @@ // Immediately begins the animation to return the drag handle back to its // original position and hide the tooltip. - void HideDragHandleNudge(contextual_tooltip::DismissNudgeReason reason); + void HideDragHandleNudge(contextual_tooltip::DismissNudgeReason reason, + bool animate); // Called when the window drag from shelf starts or ends. The drag handle // contextual nudge will remain visible while the gesture is in progress. @@ -130,7 +131,7 @@ // Helper function to hide the drag handle nudge. Called by // |hide_drag_handle_nudge_timer_|. - void HideDragHandleNudgeHelper(bool hidden_by_tap); + void HideDragHandleNudgeHelper(bool hidden_by_tap, bool animate); // Helper function to animate the drag handle for the drag handle gesture // contextual nudge.
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc index faa1377..967a225 100644 --- a/ash/shelf/shelf_widget.cc +++ b/ash/shelf/shelf_widget.cc
@@ -739,7 +739,7 @@ void ShelfWidget::HideDragHandleNudge( contextual_tooltip::DismissNudgeReason context) { - delegate_view_->drag_handle()->HideDragHandleNudge(context); + delegate_view_->drag_handle()->HideDragHandleNudge(context, /*animate=*/true); } void ShelfWidget::SetLoginShelfButtonOpacity(float target_opacity) {
diff --git a/ash/shell.cc b/ash/shell.cc index 5c95da6..cf3f858 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -1625,7 +1625,7 @@ std::make_unique<federated::FederatedServiceControllerImpl>(); } - if (features::IsWelcomeTourEnabled()) { + if (features::IsUserEducationEnabled()) { user_education_controller_ = std::make_unique<UserEducationController>( shell_delegate_->CreateUserEducationDelegate()); }
diff --git a/ash/system/accessibility/accessibility_detailed_view.cc b/ash/system/accessibility/accessibility_detailed_view.cc index a696ead..9702716 100644 --- a/ash/system/accessibility/accessibility_detailed_view.cc +++ b/ash/system/accessibility/accessibility_detailed_view.cc
@@ -20,6 +20,7 @@ #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_id.h" #include "ash/style/rounded_container.h" +#include "ash/style/switch.h" #include "ash/system/machine_learning/user_settings_event_logger.h" #include "ash/system/model/system_tray_model.h" #include "ash/system/tray/hover_highlight_view.h" @@ -104,9 +105,15 @@ if (!item) return; views::View* right_view = item->right_view(); - // The right view is either an enterprise icon or a tray toggle button. - if (views::IsViewClass<TrayToggleButton>(right_view)) { - TrayToggleButton* button = static_cast<TrayToggleButton*>(right_view); + // The right view is either an enterprise icon or a `TrayToggleButton`. + // For QsRevamp: the right view is either an enterprise icon or a `Switch`. + if (!features::IsQsRevampEnabled()) { + if (views::IsViewClass<TrayToggleButton>(right_view)) { + TrayToggleButton* button = static_cast<TrayToggleButton*>(right_view); + button->AnimateIsOn(toggled); + } + } else if (views::IsViewClass<Switch>(right_view)) { + Switch* button = static_cast<Switch*>(right_view); button->AnimateIsOn(toggled); } // The entire row is treated as one element for accessibility. @@ -656,10 +663,15 @@ enterprise_managed_icon.Size().width()); } else { // Create a non-clickable non-focusable toggle button on the right. - auto toggle = std::make_unique<TrayToggleButton>( - views::Button::PressedCallback(), - /*accessible_name_id=*/absl::nullopt, - /*use_empty_border=*/features::IsQsRevampEnabled()); + std::unique_ptr<views::ToggleButton> toggle; + if (!features::IsQsRevampEnabled()) { + toggle = std::make_unique<TrayToggleButton>( + views::Button::PressedCallback(), + /*accessible_name_id=*/absl::nullopt, + /*use_empty_border=*/features::IsQsRevampEnabled()); + } else { + toggle = std::make_unique<Switch>(); + } toggle->SetIsOn(checked); toggle->SetCanProcessEventsWithinSubtree(false); toggle->SetFocusBehavior(views::View::FocusBehavior::NEVER);
diff --git a/ash/system/accessibility/accessibility_detailed_view_unittest.cc b/ash/system/accessibility/accessibility_detailed_view_unittest.cc index 7f8d848..4a06a7b 100644 --- a/ash/system/accessibility/accessibility_detailed_view_unittest.cc +++ b/ash/system/accessibility/accessibility_detailed_view_unittest.cc
@@ -14,9 +14,9 @@ #include "ash/session/session_controller_impl.h" #include "ash/shell.h" #include "ash/style/rounded_container.h" +#include "ash/style/switch.h" #include "ash/system/tray/fake_detailed_view_delegate.h" #include "ash/system/tray/hover_highlight_view.h" -#include "ash/system/tray/tray_toggle_button.h" #include "ash/test/ash_test_base.h" #include "base/test/scoped_feature_list.h" #include "components/live_caption/pref_names.h" @@ -126,14 +126,13 @@ return node_data.GetCheckedState() == ax::mojom::CheckedState::kTrue; } -// Returns true if `item` has a toggle button on the right and the button is -// toggled. -bool IsToggleButtonToggled(HoverHighlightView* item) { +// Returns true if `item` has a `Switch` on the right and the button is toggled. +bool IsSwitchToggled(HoverHighlightView* item) { views::View* right_view = item->right_view(); - if (!views::IsViewClass<TrayToggleButton>(right_view)) { + if (!views::IsViewClass<Switch>(right_view)) { return false; } - return static_cast<TrayToggleButton*>(right_view)->GetIsOn(); + return static_cast<Switch*>(right_view)->GetIsOn(); } } // namespace @@ -671,11 +670,11 @@ EnableSpokenFeedback(true); CreateDetailedMenu(); ASSERT_TRUE(spoken_feedback_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(spoken_feedback_top_view())); + EXPECT_TRUE(IsSwitchToggled(spoken_feedback_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(spoken_feedback_top_view())); ClickView(spoken_feedback_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(spoken_feedback_top_view())); + EXPECT_FALSE(IsSwitchToggled(spoken_feedback_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(spoken_feedback_top_view())); EXPECT_FALSE(controller()->spoken_feedback().enabled()); } @@ -684,11 +683,11 @@ EnableSelectToSpeak(true); CreateDetailedMenu(); ASSERT_TRUE(select_to_speak_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(select_to_speak_top_view())); + EXPECT_TRUE(IsSwitchToggled(select_to_speak_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(select_to_speak_top_view())); ClickView(select_to_speak_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(select_to_speak_top_view())); + EXPECT_FALSE(IsSwitchToggled(select_to_speak_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(select_to_speak_top_view())); EXPECT_FALSE(controller()->select_to_speak().enabled()); } @@ -697,11 +696,11 @@ EnableDictation(true); CreateDetailedMenu(); ASSERT_TRUE(dictation_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(dictation_top_view())); + EXPECT_TRUE(IsSwitchToggled(dictation_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(dictation_top_view())); ClickView(dictation_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(dictation_top_view())); + EXPECT_FALSE(IsSwitchToggled(dictation_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(dictation_top_view())); EXPECT_FALSE(controller()->dictation().enabled()); } @@ -710,11 +709,11 @@ EnableHighContrast(true); CreateDetailedMenu(); ASSERT_TRUE(high_contrast_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(high_contrast_top_view())); + EXPECT_TRUE(IsSwitchToggled(high_contrast_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(high_contrast_top_view())); ClickView(high_contrast_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(high_contrast_top_view())); + EXPECT_FALSE(IsSwitchToggled(high_contrast_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(high_contrast_top_view())); EXPECT_FALSE(controller()->high_contrast().enabled()); } @@ -723,7 +722,7 @@ Shell::Get()->accessibility_delegate()->SetMagnifierEnabled(true); CreateDetailedMenu(); ASSERT_TRUE(screen_magnifier_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(screen_magnifier_top_view())); + EXPECT_TRUE(IsSwitchToggled(screen_magnifier_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(screen_magnifier_top_view())); ClickView(screen_magnifier_top_view()); @@ -731,7 +730,7 @@ // it manually. controller()->NotifyAccessibilityStatusChanged(); - EXPECT_FALSE(IsToggleButtonToggled(screen_magnifier_top_view())); + EXPECT_FALSE(IsSwitchToggled(screen_magnifier_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(screen_magnifier_top_view())); EXPECT_FALSE(Shell::Get()->accessibility_delegate()->IsMagnifierEnabled()); } @@ -740,11 +739,11 @@ SetDockedMagnifierEnabled(true); CreateDetailedMenu(); ASSERT_TRUE(docked_magnifier_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(docked_magnifier_top_view())); + EXPECT_TRUE(IsSwitchToggled(docked_magnifier_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(docked_magnifier_top_view())); ClickView(docked_magnifier_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(docked_magnifier_top_view())); + EXPECT_FALSE(IsSwitchToggled(docked_magnifier_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(docked_magnifier_top_view())); EXPECT_FALSE(Shell::Get()->docked_magnifier_controller()->GetEnabled()); } @@ -753,11 +752,11 @@ EnableLargeCursor(true); CreateDetailedMenu(); ASSERT_TRUE(large_cursor_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(large_cursor_top_view())); + EXPECT_TRUE(IsSwitchToggled(large_cursor_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(large_cursor_top_view())); ClickView(large_cursor_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(large_cursor_top_view())); + EXPECT_FALSE(IsSwitchToggled(large_cursor_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(large_cursor_top_view())); EXPECT_FALSE(controller()->large_cursor().enabled()); } @@ -766,11 +765,11 @@ EnableLiveCaption(true); CreateDetailedMenu(); ASSERT_TRUE(live_caption_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(live_caption_top_view())); + EXPECT_TRUE(IsSwitchToggled(live_caption_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(live_caption_top_view())); ClickView(live_caption_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(live_caption_top_view())); + EXPECT_FALSE(IsSwitchToggled(live_caption_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(live_caption_top_view())); EXPECT_FALSE(controller()->live_caption().enabled()); } @@ -779,11 +778,11 @@ EnableAutoclick(true); CreateDetailedMenu(); ASSERT_TRUE(autoclick_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(autoclick_top_view())); + EXPECT_TRUE(IsSwitchToggled(autoclick_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(autoclick_top_view())); ClickView(autoclick_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(autoclick_top_view())); + EXPECT_FALSE(IsSwitchToggled(autoclick_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(autoclick_top_view())); EXPECT_FALSE(controller()->autoclick().enabled()); } @@ -792,11 +791,11 @@ EnableVirtualKeyboard(true); CreateDetailedMenu(); ASSERT_TRUE(virtual_keyboard_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(virtual_keyboard_top_view())); + EXPECT_TRUE(IsSwitchToggled(virtual_keyboard_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(virtual_keyboard_top_view())); ClickView(virtual_keyboard_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(virtual_keyboard_top_view())); + EXPECT_FALSE(IsSwitchToggled(virtual_keyboard_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(virtual_keyboard_top_view())); EXPECT_FALSE(controller()->virtual_keyboard().enabled()); } @@ -805,11 +804,11 @@ EnableMonoAudio(true); CreateDetailedMenu(); ASSERT_TRUE(mono_audio_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(mono_audio_top_view())); + EXPECT_TRUE(IsSwitchToggled(mono_audio_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(mono_audio_top_view())); ClickView(mono_audio_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(mono_audio_top_view())); + EXPECT_FALSE(IsSwitchToggled(mono_audio_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(mono_audio_top_view())); EXPECT_FALSE(controller()->mono_audio().enabled()); } @@ -818,11 +817,11 @@ SetCaretHighlightEnabled(true); CreateDetailedMenu(); ASSERT_TRUE(caret_highlight_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(caret_highlight_top_view())); + EXPECT_TRUE(IsSwitchToggled(caret_highlight_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(caret_highlight_top_view())); ClickView(caret_highlight_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(caret_highlight_top_view())); + EXPECT_FALSE(IsSwitchToggled(caret_highlight_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(caret_highlight_top_view())); EXPECT_FALSE(controller()->caret_highlight().enabled()); } @@ -831,11 +830,11 @@ SetCursorHighlightEnabled(true); CreateDetailedMenu(); ASSERT_TRUE(highlight_mouse_cursor_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(highlight_mouse_cursor_top_view())); + EXPECT_TRUE(IsSwitchToggled(highlight_mouse_cursor_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(highlight_mouse_cursor_top_view())); ClickView(highlight_mouse_cursor_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(highlight_mouse_cursor_top_view())); + EXPECT_FALSE(IsSwitchToggled(highlight_mouse_cursor_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(highlight_mouse_cursor_top_view())); EXPECT_FALSE(controller()->cursor_highlight().enabled()); } @@ -844,11 +843,11 @@ SetFocusHighlightEnabled(true); CreateDetailedMenu(); ASSERT_TRUE(highlight_keyboard_focus_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(highlight_keyboard_focus_top_view())); + EXPECT_TRUE(IsSwitchToggled(highlight_keyboard_focus_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(highlight_keyboard_focus_top_view())); ClickView(highlight_keyboard_focus_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(highlight_keyboard_focus_top_view())); + EXPECT_FALSE(IsSwitchToggled(highlight_keyboard_focus_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(highlight_keyboard_focus_top_view())); EXPECT_FALSE(controller()->focus_highlight().enabled()); } @@ -857,11 +856,11 @@ EnableStickyKeys(true); CreateDetailedMenu(); ASSERT_TRUE(sticky_keys_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(sticky_keys_top_view())); + EXPECT_TRUE(IsSwitchToggled(sticky_keys_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(sticky_keys_top_view())); ClickView(sticky_keys_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(sticky_keys_top_view())); + EXPECT_FALSE(IsSwitchToggled(sticky_keys_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(sticky_keys_top_view())); EXPECT_FALSE(controller()->sticky_keys().enabled()); } @@ -874,11 +873,11 @@ EnableSwitchAccess(true); CreateDetailedMenu(); ASSERT_TRUE(switch_access_top_view()); - EXPECT_TRUE(IsToggleButtonToggled(switch_access_top_view())); + EXPECT_TRUE(IsSwitchToggled(switch_access_top_view())); EXPECT_TRUE(IsCheckedForAccessibility(switch_access_top_view())); ClickView(switch_access_top_view()); - EXPECT_FALSE(IsToggleButtonToggled(switch_access_top_view())); + EXPECT_FALSE(IsSwitchToggled(switch_access_top_view())); EXPECT_FALSE(IsCheckedForAccessibility(switch_access_top_view())); EXPECT_FALSE(controller()->switch_access().enabled()); }
diff --git a/ash/system/audio/audio_detailed_view.cc b/ash/system/audio/audio_detailed_view.cc index 157ff8c5..1c5ef1a 100644 --- a/ash/system/audio/audio_detailed_view.cc +++ b/ash/system/audio/audio_detailed_view.cc
@@ -340,11 +340,10 @@ l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LIVE_CAPTION)); // Creates a toggle button on the right. - auto toggle = std::make_unique<TrayToggleButton>( - base::BindRepeating(&AudioDetailedView::ToggleLiveCaptionState, - weak_factory_.GetWeakPtr()), - IDS_ASH_STATUS_TRAY_LIVE_CAPTION, - /*use_empty_border=*/true); + auto toggle = std::make_unique<Switch>(base::BindRepeating( + &AudioDetailedView::ToggleLiveCaptionState, weak_factory_.GetWeakPtr())); + SetAccessibleName( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_LIVE_CAPTION)); toggle->SetIsOn(live_caption_enabled); std::u16string toggle_tooltip = live_caption_enabled @@ -435,10 +434,7 @@ // Create a non-clickable non-focusable toggle button on the right. The events // and focus behavior should be handled by `noise_cancellation_view_` instead. - auto toggle = - std::make_unique<TrayToggleButton>(views::Button::PressedCallback(), - /*accessible_name_id=*/absl::nullopt, - /*use_empty_border=*/true); + auto toggle = std::make_unique<Switch>(); toggle->SetIsOn(noise_cancellation_state); toggle->SetCanProcessEventsWithinSubtree(false); toggle->SetFocusBehavior(views::View::FocusBehavior::NEVER);
diff --git a/ash/system/audio/audio_detailed_view.h b/ash/system/audio/audio_detailed_view.h index 49f2f5e..05ec61a 100644 --- a/ash/system/audio/audio_detailed_view.h +++ b/ash/system/audio/audio_detailed_view.h
@@ -11,12 +11,12 @@ #include "ash/accessibility/accessibility_observer.h" #include "ash/ash_export.h" +#include "ash/style/switch.h" #include "ash/system/tray/hover_highlight_view.h" #include "ash/system/tray/tray_detailed_view.h" #include "chromeos/ash/components/audio/audio_device.h" #include "components/soda/soda_installer.h" #include "ui/views/controls/button/button.h" -#include "ui/views/controls/button/toggle_button.h" #include "ui/views/view.h" namespace gfx { @@ -134,10 +134,10 @@ // Owned by the views hierarchy. HoverHighlightView* live_caption_view_ = nullptr; views::ImageView* live_caption_icon_ = nullptr; - views::ToggleButton* live_caption_button_ = nullptr; + Switch* live_caption_button_ = nullptr; HoverHighlightView* noise_cancellation_view_ = nullptr; views::ImageView* noise_cancellation_icon_ = nullptr; - views::ToggleButton* noise_cancellation_button_ = nullptr; + Switch* noise_cancellation_button_ = nullptr; views::Button* settings_button_ = nullptr; base::WeakPtrFactory<AudioDetailedView> weak_factory_{this};
diff --git a/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc b/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc index 3022546..37a6e8d 100644 --- a/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc +++ b/ash/system/audio/unified_audio_detailed_view_controller_unittest.cc
@@ -8,6 +8,7 @@ #include "ash/constants/ash_features.h" #include "ash/session/session_controller_impl.h" #include "ash/shell.h" +#include "ash/style/switch.h" #include "ash/system/audio/audio_detailed_view.h" #include "ash/system/audio/mic_gain_slider_controller.h" #include "ash/system/audio/mic_gain_slider_view.h" @@ -440,14 +441,7 @@ // view first. GetAudioDetailedView(); EXPECT_EQ(1u, toggles_map_.size()); - - if (!IsQsRevampEnabled()) { - views::ToggleButton* toggle = - (views::ToggleButton*)toggles_map_[internal_mic.id]->children()[1]; - EXPECT_TRUE(toggle->GetIsOn()); - } else { - EXPECT_TRUE(noise_cancellation_button()); - } + noise_cancellation_button()->GetIsOn(); } TEST_P(UnifiedAudioDetailedViewControllerTest, @@ -468,15 +462,15 @@ GetAudioDetailedView(); EXPECT_EQ(1u, toggles_map_.size()); - if (!IsQsRevampEnabled()) { - views::ToggleButton* toggle = - (views::ToggleButton*)toggles_map_[internal_mic.id]->children()[1]; - auto widget = CreateFramelessTestWidget(); - widget->SetContentsView(toggle); + views::ToggleButton* toggle = noise_cancellation_button(); + auto widget = CreateFramelessTestWidget(); + widget->SetContentsView(toggle); - // The toggle loaded the pref correctly. - EXPECT_FALSE(toggle->GetIsOn()); - EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState()); + // The toggle loaded the pref correctly. + EXPECT_FALSE(toggle->GetIsOn()); + EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState()); + + if (!IsQsRevampEnabled()) { ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::PointF(), gfx::PointF(), ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_NONE); @@ -490,13 +484,6 @@ views::test::ButtonTestApi(toggle).NotifyClick(press); EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState()); } else { - auto widget = CreateFramelessTestWidget(); - widget->SetContentsView(noise_cancellation_button()); - - // The toggle loaded the pref correctly. - EXPECT_FALSE(noise_cancellation_button()->GetIsOn()); - EXPECT_FALSE(audio_pref_handler_->GetNoiseCancellationState()); - // For QsRevamp, the entire row of `noise_cancellation_view_` is clickable. ToggleNoiseCancellation(); EXPECT_TRUE(audio_pref_handler_->GetNoiseCancellationState());
diff --git a/ash/system/bluetooth/bluetooth_detailed_view_impl.cc b/ash/system/bluetooth/bluetooth_detailed_view_impl.cc index 79c8c191..fe93164 100644 --- a/ash/system/bluetooth/bluetooth_detailed_view_impl.cc +++ b/ash/system/bluetooth/bluetooth_detailed_view_impl.cc
@@ -96,8 +96,9 @@ IDS_ASH_STATUS_TRAY_BLUETOOTH_TOGGLE_TOOLTIP, toggle_tooltip)); // Ensure the toggle button is in sync with the current Bluetooth state. - if (toggle_button_->GetIsOn() != enabled) + if (toggle_button_->GetIsOn() != enabled) { toggle_button_->SetIsOn(enabled); + } InvalidateLayout(); } @@ -183,11 +184,9 @@ toggle_row_->AddViewAndLabel(std::move(icon), u""); toggle_row_->text_label()->SetEnabledColorId(cros_tokens::kCrosSysOnSurface); - auto toggle = std::make_unique<TrayToggleButton>( - base::BindRepeating(&BluetoothDetailedViewImpl::OnToggleClicked, - weak_factory_.GetWeakPtr()), - IDS_ASH_STATUS_TRAY_BLUETOOTH, - /*use_empty_border=*/true); + auto toggle = std::make_unique<Switch>(base::BindRepeating( + &BluetoothDetailedViewImpl::OnToggleClicked, weak_factory_.GetWeakPtr())); + SetAccessibleName(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH)); toggle_button_ = toggle.get(); toggle_row_->AddRightView(toggle.release());
diff --git a/ash/system/bluetooth/bluetooth_detailed_view_impl.h b/ash/system/bluetooth/bluetooth_detailed_view_impl.h index be087ea..4916b620 100644 --- a/ash/system/bluetooth/bluetooth_detailed_view_impl.h +++ b/ash/system/bluetooth/bluetooth_detailed_view_impl.h
@@ -6,6 +6,7 @@ #define ASH_SYSTEM_BLUETOOTH_BLUETOOTH_DETAILED_VIEW_IMPL_H_ #include "ash/ash_export.h" +#include "ash/style/switch.h" #include "ash/system/bluetooth/bluetooth_detailed_view.h" #include "ash/system/tray/tray_detailed_view.h" #include "base/memory/weak_ptr.h" @@ -14,7 +15,6 @@ namespace views { class Button; class ImageView; -class ToggleButton; } // namespace views namespace ash { @@ -73,7 +73,7 @@ RoundedContainer* top_container_ = nullptr; HoverHighlightView* toggle_row_ = nullptr; views::ImageView* toggle_icon_ = nullptr; - views::ToggleButton* toggle_button_ = nullptr; + Switch* toggle_button_ = nullptr; RoundedContainer* main_container_ = nullptr; HoverHighlightView* pair_new_device_view_ = nullptr; views::ImageView* pair_new_device_icon_ = nullptr;
diff --git a/ash/system/bluetooth/bluetooth_detailed_view_impl_unittest.cc b/ash/system/bluetooth/bluetooth_detailed_view_impl_unittest.cc index c25fc11..f5ee01a 100644 --- a/ash/system/bluetooth/bluetooth_detailed_view_impl_unittest.cc +++ b/ash/system/bluetooth/bluetooth_detailed_view_impl_unittest.cc
@@ -8,12 +8,12 @@ #include "ash/public/cpp/test/test_system_tray_client.h" #include "ash/style/rounded_container.h" +#include "ash/style/switch.h" #include "ash/system/bluetooth/bluetooth_device_list_item_view.h" #include "ash/system/tray/detailed_view_delegate.h" #include "ash/system/tray/hover_highlight_view.h" #include "ash/test/ash_test_base.h" #include "mojo/public/cpp/bindings/clone_traits.h" -#include "ui/views/controls/button/toggle_button.h" #include "ui/views/controls/label.h" #include "ui/views/test/views_test_utils.h" #include "ui/views/widget/widget.h" @@ -98,9 +98,7 @@ return bluetooth_detailed_view_->toggle_row_; } - views::ToggleButton* GetToggleButton() { - return bluetooth_detailed_view_->toggle_button_; - } + Switch* GetToggleButton() { return bluetooth_detailed_view_->toggle_button_; } RoundedContainer* GetMainContainer() { return bluetooth_detailed_view_->main_container_; @@ -137,7 +135,7 @@ TEST_F(BluetoothDetailedViewImplTest, UpdateBluetoothEnabledStateChangesUIState) { HoverHighlightView* toggle_row = GetToggleRow(); - views::ToggleButton* toggle_button = GetToggleButton(); + Switch* toggle_button = GetToggleButton(); RoundedContainer* main_container = GetMainContainer(); bluetooth_detailed_view_->UpdateBluetoothEnabledState(true); @@ -167,7 +165,7 @@ } TEST_F(BluetoothDetailedViewImplTest, PressingToggleButtonNotifiesDelegate) { - views::ToggleButton* toggle_button = GetToggleButton(); + Switch* toggle_button = GetToggleButton(); EXPECT_FALSE(toggle_button->GetIsOn()); EXPECT_FALSE(bluetooth_detailed_view_delegate_.last_toggle_state_);
diff --git a/ash/system/holding_space/holding_space_item_chip_view.cc b/ash/system/holding_space/holding_space_item_chip_view.cc index 5b9d0f0..41c08b98 100644 --- a/ash/system/holding_space/holding_space_item_chip_view.cc +++ b/ash/system/holding_space/holding_space_item_chip_view.cc
@@ -330,7 +330,18 @@ .SetID(kHoldingSpaceItemSecondaryChipLabelId) .SetStyle(TypographyToken::kCrosLabel1) .SetElideBehavior(gfx::FADE_TAIL) - .SetCallback(paint_label_mask_callback))) + .SetCallback(paint_label_mask_callback)) + .AfterBuild(base::BindOnce( + [](HoldingSpaceItemChipView* self, + views::BoxLayoutView* box_layout_view) { + // Synchronize line heights between primary and + // secondary labels so that text will be vertically + // centered when both are shown despite differences + // in font sizes. + self->secondary_label_->SetLineHeight( + self->primary_label_->GetLineHeight()); + }, + base::Unretained(this)))) .AddChild(views::Builder<views::BoxLayoutView>() .SetOrientation(Orientation::kHorizontal) .SetMainAxisAlignment(MainAxisAlignment::kEnd)
diff --git a/ash/system/ime_menu/ime_list_view.cc b/ash/system/ime_menu/ime_list_view.cc index b999639..e620ed7 100644 --- a/ash/system/ime_menu/ime_list_view.cc +++ b/ash/system/ime_menu/ime_list_view.cc
@@ -19,6 +19,7 @@ #include "ash/style/ash_color_id.h" #include "ash/style/ash_color_provider.h" #include "ash/style/rounded_container.h" +#include "ash/style/switch.h" #include "ash/system/tray/actionable_view.h" #include "ash/system/tray/system_menu_button.h" #include "ash/system/tray/tray_detailed_view.h" @@ -165,6 +166,7 @@ ~KeyboardStatusRow() override = default; views::ToggleButton* toggle() const { return toggle_; } + Switch* qs_toggle() const { return qs_toggle_; } void Init(views::Button::PressedCallback callback) { const bool is_qs_revamp = features::IsQsRevampEnabled(); @@ -196,16 +198,29 @@ tri_view->AddView(TriView::Container::CENTER, label); // The on-screen keyboard toggle button. - toggle_ = new TrayToggleButton( - std::move(callback), IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD, - /*use_empty_border=*/is_qs_revamp); - toggle_->SetIsOn(keyboard::IsKeyboardEnabled()); - tri_view->AddView(TriView::Container::END, toggle_); + if (!is_qs_revamp) { + toggle_ = new TrayToggleButton( + std::move(callback), + IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD, + /*use_empty_border=*/is_qs_revamp); + toggle_->SetIsOn(keyboard::IsKeyboardEnabled()); + tri_view->AddView(TriView::Container::END, toggle_); + } else { + auto qs_toggle = std::make_unique<Switch>(std::move(callback)); + qs_toggle->SetAccessibleName(l10n_util::GetStringUTF16( + IDS_ASH_STATUS_TRAY_ACCESSIBILITY_VIRTUAL_KEYBOARD)); + qs_toggle->SetIsOn(keyboard::IsKeyboardEnabled()); + qs_toggle_ = qs_toggle.release(); + tri_view->AddView(TriView::Container::END, qs_toggle_); + } } private: - // ToggleButton to toggle keyboard on or off. + // `ToggleButton` to toggle keyboard on or off. views::ToggleButton* toggle_ = nullptr; + + // For QsRevamp: `KnobSwitch` to toggle keyboard on or off. + Switch* qs_toggle_ = nullptr; }; BEGIN_METADATA(KeyboardStatusRow, views::View) @@ -405,6 +420,9 @@ views::View* ImeListViewTestApi::GetToggleView() const { if (!ime_list_view_->keyboard_status_row_) return nullptr; + if (features::IsQsRevampEnabled()) { + return ime_list_view_->keyboard_status_row_->qs_toggle(); + } return ime_list_view_->keyboard_status_row_->toggle(); }
diff --git a/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_impl.cc b/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_impl.cc index 4510584..3c40d9ed 100644 --- a/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_impl.cc +++ b/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_impl.cc
@@ -17,6 +17,18 @@ namespace ash { namespace { +// Whether or not settings taken during the transition period should be +// persisted to the prefs. Values should only ever be true if the original +// setting was a user-configured value. +struct ForceMouseSettingPersistence { + bool swap_right = false; + bool sensitivity = false; + bool reverse_scrolling = false; + bool acceleration_enabled = false; + bool scroll_acceleration = false; + bool scroll_sensitivity = false; +}; + mojom::MouseSettingsPtr GetDefaultMouseSettings() { mojom::MouseSettingsPtr settings = mojom::MouseSettings::New(); settings->swap_right = kDefaultSwapRight; @@ -30,94 +42,61 @@ // GetMouseSettingsFromPrefs returns a mouse settings based on user prefs // to be used as settings for new mouses. -mojom::MouseSettingsPtr GetMouseSettingsFromPrefs(PrefService* prefs) { +mojom::MouseSettingsPtr GetMouseSettingsFromPrefs( + PrefService* prefs, + ForceMouseSettingPersistence& force_persistence) { mojom::MouseSettingsPtr settings = mojom::MouseSettings::New(); - settings->swap_right = prefs->GetBoolean(prefs::kPrimaryMouseButtonRight); - settings->sensitivity = prefs->GetInteger(prefs::kMouseSensitivity); - settings->reverse_scrolling = prefs->GetBoolean(prefs::kMouseReverseScroll); - settings->acceleration_enabled = prefs->GetBoolean(prefs::kMouseAcceleration); - settings->scroll_sensitivity = - prefs->GetInteger(prefs::kMouseScrollSensitivity); + + const auto* swap_right_preference = + prefs->GetUserPrefValue(prefs::kPrimaryMouseButtonRight); + settings->swap_right = swap_right_preference + ? swap_right_preference->GetBool() + : kDefaultSwapRight; + force_persistence.swap_right = swap_right_preference != nullptr; + + const auto* sensitivity_preference = + prefs->GetUserPrefValue(prefs::kMouseSensitivity); + settings->sensitivity = sensitivity_preference + ? sensitivity_preference->GetInt() + : kDefaultSensitivity; + force_persistence.sensitivity = sensitivity_preference != nullptr; + + const auto* reverse_scrolling_preference = + prefs->GetUserPrefValue(prefs::kMouseReverseScroll); + settings->reverse_scrolling = reverse_scrolling_preference + ? reverse_scrolling_preference->GetBool() + : kDefaultReverseScrolling; + force_persistence.reverse_scrolling = reverse_scrolling_preference != nullptr; + + const auto* acceleration_enabled_preference = + prefs->GetUserPrefValue(prefs::kMouseAcceleration); + settings->acceleration_enabled = + acceleration_enabled_preference + ? acceleration_enabled_preference->GetBool() + : kDefaultAccelerationEnabled; + force_persistence.acceleration_enabled = + acceleration_enabled_preference != nullptr; + + const auto* scroll_acceleration_preference = + prefs->GetUserPrefValue(prefs::kMouseScrollAcceleration); settings->scroll_acceleration = - prefs->GetBoolean(prefs::kMouseScrollAcceleration); + scroll_acceleration_preference ? scroll_acceleration_preference->GetBool() + : kDefaultSensitivity; + force_persistence.scroll_acceleration = + scroll_acceleration_preference != nullptr; + + const auto* scroll_sensitivity_preference = + prefs->GetUserPrefValue(prefs::kMouseScrollSensitivity); + settings->scroll_sensitivity = scroll_sensitivity_preference + ? scroll_sensitivity_preference->GetInt() + : kDefaultScrollAcceleration; + force_persistence.scroll_sensitivity = + scroll_sensitivity_preference != nullptr; + return settings; } -} // namespace - -MousePrefHandlerImpl::MousePrefHandlerImpl() = default; -MousePrefHandlerImpl::~MousePrefHandlerImpl() = default; - -void MousePrefHandlerImpl::InitializeMouseSettings(PrefService* pref_service, - mojom::Mouse* mouse) { - if (!pref_service) { - mouse->settings = GetDefaultMouseSettings(); - return; - } - - const auto& devices_dict = - pref_service->GetDict(prefs::kMouseDeviceSettingsDictPref); - const auto* settings_dict = devices_dict.FindDict(mouse->device_key); - if (!settings_dict) { - mouse->settings = GetNewMouseSettings(pref_service, *mouse); - } else { - mouse->settings = - RetrieveMouseSettings(pref_service, *mouse, *settings_dict); - } - DCHECK(mouse->settings); - - UpdateMouseSettings(pref_service, *mouse); -} - -void MousePrefHandlerImpl::UpdateMouseSettings(PrefService* pref_service, - const mojom::Mouse& mouse) { - DCHECK(mouse.settings); - const mojom::MouseSettings& settings = *mouse.settings; - // Populate `settings_dict` with all settings in `settings`. - base::Value::Dict settings_dict; - settings_dict.Set(prefs::kMouseSettingSwapRight, settings.swap_right); - settings_dict.Set(prefs::kMouseSettingSensitivity, settings.sensitivity); - settings_dict.Set(prefs::kMouseSettingReverseScrolling, - settings.reverse_scrolling); - settings_dict.Set(prefs::kMouseSettingAccelerationEnabled, - settings.acceleration_enabled); - settings_dict.Set(prefs::kMouseSettingScrollSensitivity, - settings.scroll_sensitivity); - settings_dict.Set(prefs::kMouseSettingScrollAcceleration, - settings.scroll_acceleration); - - // Retrieve old settings and merge with the new ones. - base::Value::Dict devices_dict = - pref_service->GetDict(prefs::kMouseDeviceSettingsDictPref).Clone(); - - // If an old settings dict already exists for the device, merge the updated - // settings into the old settings. Otherwise, insert the dict at - // `mouse.device_key`. - base::Value::Dict* old_settings_dict = - devices_dict.FindDict(mouse.device_key); - if (old_settings_dict) { - old_settings_dict->Merge(std::move(settings_dict)); - } else { - devices_dict.Set(mouse.device_key, std::move(settings_dict)); - } - - pref_service->SetDict(std::string(prefs::kMouseDeviceSettingsDictPref), - std::move(devices_dict)); -} - -mojom::MouseSettingsPtr MousePrefHandlerImpl::GetNewMouseSettings( - PrefService* prefs, - const mojom::Mouse& mouse) { - // TODO(michaelcheco): Remove once transitioned to per-device settings. - if (Shell::Get()->input_device_tracker()->WasDevicePreviouslyConnected( - InputDeviceTracker::InputDeviceCategory::kMouse, mouse.device_key)) { - return GetMouseSettingsFromPrefs(prefs); - } - - return GetDefaultMouseSettings(); -} - -mojom::MouseSettingsPtr MousePrefHandlerImpl::RetrieveMouseSettings( +mojom::MouseSettingsPtr RetrieveMouseSettings( PrefService* pref_service, const mojom::Mouse& mouse, const base::Value::Dict& settings_dict) { @@ -141,4 +120,132 @@ return settings; } +bool ExistingSettingsHasValue(base::StringPiece setting_key, + const base::Value::Dict* existing_settings_dict) { + if (!existing_settings_dict) { + return false; + } + + return existing_settings_dict->Find(setting_key) != nullptr; +} + +void UpdateMouseSettingsImpl( + PrefService* pref_service, + const mojom::Mouse& mouse, + const ForceMouseSettingPersistence& force_persistence) { + DCHECK(mouse.settings); + base::Value::Dict devices_dict = + pref_service->GetDict(prefs::kMouseDeviceSettingsDictPref).Clone(); + base::Value::Dict* existing_settings_dict = + devices_dict.FindDict(mouse.device_key); + const mojom::MouseSettings& settings = *mouse.settings; + + // Populate `settings_dict` with all settings in `settings`. + base::Value::Dict settings_dict; + + // Settings should only be persisted if one or more of the following is true: + // - Setting was previously persisted to storage + // - `force_persistence` requires the setting to be persisted, this means this + // device is being transitioned from the old global settings to per-device + // settings and the user specified the specific value for this setting. + // - Setting is different than the default, which means the user manually + // changed the value. + + if (ExistingSettingsHasValue(prefs::kMouseSettingSwapRight, + existing_settings_dict) || + force_persistence.swap_right || + settings.swap_right != kDefaultSwapRight) { + settings_dict.Set(prefs::kMouseSettingSwapRight, settings.swap_right); + } + + if (ExistingSettingsHasValue(prefs::kMouseSettingSensitivity, + existing_settings_dict) || + force_persistence.sensitivity || + settings.sensitivity != kDefaultSensitivity) { + settings_dict.Set(prefs::kMouseSettingSensitivity, settings.sensitivity); + } + + if (ExistingSettingsHasValue(prefs::kMouseSettingReverseScrolling, + existing_settings_dict) || + force_persistence.reverse_scrolling || + settings.reverse_scrolling != kDefaultReverseScrolling) { + settings_dict.Set(prefs::kMouseSettingReverseScrolling, + settings.reverse_scrolling); + } + + if (ExistingSettingsHasValue(prefs::kMouseSettingAccelerationEnabled, + existing_settings_dict) || + force_persistence.acceleration_enabled || + settings.acceleration_enabled != kDefaultAccelerationEnabled) { + settings_dict.Set(prefs::kMouseSettingAccelerationEnabled, + settings.acceleration_enabled); + } + + if (ExistingSettingsHasValue(prefs::kMouseSettingScrollSensitivity, + existing_settings_dict) || + force_persistence.scroll_sensitivity || + settings.scroll_sensitivity != kDefaultSensitivity) { + settings_dict.Set(prefs::kMouseSettingScrollSensitivity, + settings.scroll_sensitivity); + } + + if (ExistingSettingsHasValue(prefs::kMouseSettingScrollAcceleration, + existing_settings_dict) || + force_persistence.scroll_acceleration || + settings.scroll_acceleration != kDefaultScrollAcceleration) { + settings_dict.Set(prefs::kMouseSettingScrollAcceleration, + settings.scroll_acceleration); + } + + // If an old settings dict already exists for the device, merge the updated + // settings into the old settings. Otherwise, insert the dict at + // `mouse.device_key`. + if (existing_settings_dict) { + existing_settings_dict->Merge(std::move(settings_dict)); + } else { + devices_dict.Set(mouse.device_key, std::move(settings_dict)); + } + + pref_service->SetDict(std::string(prefs::kMouseDeviceSettingsDictPref), + std::move(devices_dict)); +} + +} // namespace + +MousePrefHandlerImpl::MousePrefHandlerImpl() = default; +MousePrefHandlerImpl::~MousePrefHandlerImpl() = default; + +void MousePrefHandlerImpl::InitializeMouseSettings(PrefService* pref_service, + mojom::Mouse* mouse) { + if (!pref_service) { + mouse->settings = GetDefaultMouseSettings(); + return; + } + + const auto& devices_dict = + pref_service->GetDict(prefs::kMouseDeviceSettingsDictPref); + const auto* settings_dict = devices_dict.FindDict(mouse->device_key); + ForceMouseSettingPersistence force_persistence; + + if (settings_dict) { + mouse->settings = + RetrieveMouseSettings(pref_service, *mouse, *settings_dict); + } else if (Shell::Get()->input_device_tracker()->WasDevicePreviouslyConnected( + InputDeviceTracker::InputDeviceCategory::kMouse, + mouse->device_key)) { + mouse->settings = + GetMouseSettingsFromPrefs(pref_service, force_persistence); + } else { + mouse->settings = GetDefaultMouseSettings(); + } + DCHECK(mouse->settings); + + UpdateMouseSettingsImpl(pref_service, *mouse, force_persistence); +} + +void MousePrefHandlerImpl::UpdateMouseSettings(PrefService* pref_service, + const mojom::Mouse& mouse) { + UpdateMouseSettingsImpl(pref_service, mouse, /*force_persistence=*/{}); +} + } // namespace ash
diff --git a/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_impl.h b/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_impl.h index 68d8a4a..bc6dca5 100644 --- a/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_impl.h +++ b/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_impl.h
@@ -25,14 +25,6 @@ mojom::Mouse* mouse) override; void UpdateMouseSettings(PrefService* pref_service, const mojom::Mouse& mouse) override; - - private: - mojom::MouseSettingsPtr GetNewMouseSettings(PrefService* prefs, - const mojom::Mouse& Mouse); - mojom::MouseSettingsPtr RetrieveMouseSettings( - PrefService* prefs, - const mojom::Mouse& mouse, - const base::Value::Dict& settings_dict); }; } // namespace ash
diff --git a/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_unittest.cc b/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_unittest.cc index c3c6c16..30dff821 100644 --- a/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_unittest.cc +++ b/ash/system/input_device_settings/pref_handlers/mouse_pref_handler_unittest.cc
@@ -38,6 +38,14 @@ /*scroll_sensitivity=*/kDefaultSensitivity, /*scroll_acceleration=*/kDefaultScrollAcceleration); +const mojom::MouseSettings kMouseSettingsNotDefault( + /*swap_right=*/!kDefaultSwapRight, + /*sensitivity=*/1, + /*reverse_scrolling=*/!kDefaultReverseScrolling, + /*acceleration_enabled=*/!kDefaultAccelerationEnabled, + /*scroll_sensitivity=*/1, + /*scroll_acceleration=*/!kDefaultScrollAcceleration); + const mojom::MouseSettings kMouseSettings1( /*swap_right=*/false, /*sensitivity=*/1, @@ -82,17 +90,30 @@ // We are using these test constants as a a way to differentiate values // retrieved from prefs or default mouse settings. pref_service_->registry()->RegisterBooleanPref( - prefs::kPrimaryMouseButtonRight, kTestSwapRight); + prefs::kPrimaryMouseButtonRight, kDefaultSwapRight); pref_service_->registry()->RegisterIntegerPref(prefs::kMouseSensitivity, - kTestSensitivity); + kDefaultSensitivity); pref_service_->registry()->RegisterBooleanPref(prefs::kMouseReverseScroll, - kTestReverseScrolling); + kDefaultReverseScrolling); pref_service_->registry()->RegisterBooleanPref(prefs::kMouseAcceleration, - kTestAccelerationEnabled); + kDefaultAccelerationEnabled); pref_service_->registry()->RegisterIntegerPref( - prefs::kMouseScrollSensitivity, kTestScrollSensitivity); + prefs::kMouseScrollSensitivity, kDefaultSensitivity); pref_service_->registry()->RegisterBooleanPref( - prefs::kMouseScrollAcceleration, kTestScrollAcceleration); + prefs::kMouseScrollAcceleration, kDefaultScrollAcceleration); + + pref_service_->SetUserPref(prefs::kPrimaryMouseButtonRight, + base::Value(kTestSwapRight)); + pref_service_->SetUserPref(prefs::kMouseSensitivity, + base::Value(kTestSensitivity)); + pref_service_->SetUserPref(prefs::kMouseReverseScroll, + base::Value(kTestReverseScrolling)); + pref_service_->SetUserPref(prefs::kMouseAcceleration, + base::Value(kTestAccelerationEnabled)); + pref_service_->SetUserPref(prefs::kMouseScrollSensitivity, + base::Value(kTestScrollSensitivity)); + pref_service_->SetUserPref(prefs::kMouseScrollAcceleration, + base::Value(kTestScrollAcceleration)); } void CheckMouseSettingsAndDictAreEqual( @@ -100,33 +121,51 @@ const base::Value::Dict& settings_dict) { const auto swap_right = settings_dict.FindBool(prefs::kMouseSettingSwapRight); - ASSERT_TRUE(swap_right.has_value()); - EXPECT_EQ(settings.swap_right, swap_right); + if (swap_right.has_value()) { + EXPECT_EQ(settings.swap_right, swap_right); + } else { + EXPECT_EQ(settings.swap_right, kDefaultSwapRight); + } const auto sensitivity = settings_dict.FindInt(prefs::kMouseSettingSensitivity); - ASSERT_TRUE(sensitivity.has_value()); - EXPECT_EQ(settings.sensitivity, sensitivity); + if (sensitivity.has_value()) { + EXPECT_EQ(settings.sensitivity, sensitivity); + } else { + EXPECT_EQ(settings.sensitivity, kDefaultSensitivity); + } const auto reverse_scrolling = settings_dict.FindBool(prefs::kMouseSettingReverseScrolling); - ASSERT_TRUE(reverse_scrolling.has_value()); - EXPECT_EQ(settings.reverse_scrolling, reverse_scrolling); + if (reverse_scrolling.has_value()) { + EXPECT_EQ(settings.reverse_scrolling, reverse_scrolling); + } else { + EXPECT_EQ(settings.reverse_scrolling, kDefaultReverseScrolling); + } const auto acceleration_enabled = settings_dict.FindBool(prefs::kMouseSettingAccelerationEnabled); - ASSERT_TRUE(acceleration_enabled.has_value()); - EXPECT_EQ(settings.acceleration_enabled, acceleration_enabled); + if (acceleration_enabled.has_value()) { + EXPECT_EQ(settings.acceleration_enabled, acceleration_enabled); + } else { + EXPECT_EQ(settings.acceleration_enabled, kDefaultAccelerationEnabled); + } const auto scroll_sensitivity = settings_dict.FindInt(prefs::kMouseSettingScrollSensitivity); - ASSERT_TRUE(scroll_sensitivity.has_value()); - EXPECT_EQ(settings.scroll_sensitivity, scroll_sensitivity); + if (scroll_sensitivity.has_value()) { + EXPECT_EQ(settings.scroll_sensitivity, scroll_sensitivity); + } else { + EXPECT_EQ(settings.scroll_sensitivity, kDefaultSensitivity); + } const auto scroll_acceleration = settings_dict.FindBool(prefs::kMouseSettingScrollAcceleration); - ASSERT_TRUE(scroll_acceleration.has_value()); - EXPECT_EQ(settings.scroll_acceleration, scroll_acceleration); + if (scroll_acceleration.has_value()) { + EXPECT_EQ(settings.scroll_acceleration, scroll_acceleration); + } else { + EXPECT_EQ(settings.scroll_acceleration, kDefaultScrollAcceleration); + } } void CallUpdateMouseSettings(const std::string& device_key, @@ -147,6 +186,16 @@ return std::move(mouse->settings); } + const base::Value::Dict* GetSettingsDict(const std::string& device_key) { + const auto& devices_dict = + pref_service_->GetDict(prefs::kMouseDeviceSettingsDictPref); + EXPECT_EQ(1u, devices_dict.size()); + const auto* settings_dict = devices_dict.FindDict(device_key); + EXPECT_NE(nullptr, settings_dict); + + return settings_dict; + } + protected: std::unique_ptr<MousePrefHandlerImpl> pref_handler_; std::unique_ptr<TestingPrefServiceSimple> pref_service_; @@ -294,6 +343,71 @@ ASSERT_EQ(settings->scroll_acceleration, kTestScrollAcceleration); } +TEST_F(MousePrefHandlerTest, TransitionPeriodSettingsPersistedWhenUserChosen) { + mojom::Mouse mouse; + mouse.device_key = kMouseKey1; + Shell::Get()->input_device_tracker()->OnMouseConnected(mouse); + + pref_service_->SetUserPref(prefs::kPrimaryMouseButtonRight, + base::Value(kDefaultSwapRight)); + pref_service_->SetUserPref(prefs::kMouseSensitivity, + base::Value(kDefaultSensitivity)); + pref_service_->SetUserPref(prefs::kMouseReverseScroll, + base::Value(kDefaultReverseScrolling)); + pref_service_->SetUserPref(prefs::kMouseAcceleration, + base::Value(kDefaultAccelerationEnabled)); + pref_service_->SetUserPref(prefs::kMouseScrollSensitivity, + base::Value(kDefaultSensitivity)); + pref_service_->SetUserPref(prefs::kMouseScrollAcceleration, + base::Value(kDefaultScrollAcceleration)); + mojom::MouseSettingsPtr settings = + CallInitializeMouseSettings(mouse.device_key); + EXPECT_EQ(kMouseSettingsDefault, *settings); + + const auto* settings_dict = GetSettingsDict(kMouseKey1); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingSwapRight)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingReverseScrolling)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingAccelerationEnabled)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingScrollSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingScrollAcceleration)); + CheckMouseSettingsAndDictAreEqual(kMouseSettingsDefault, *settings_dict); +} + +TEST_F(MousePrefHandlerTest, DefaultNotPersistedUntilUpdated) { + CallUpdateMouseSettings(kMouseKey1, kMouseSettingsDefault); + + const auto* settings_dict = GetSettingsDict(kMouseKey1); + EXPECT_FALSE(settings_dict->contains(prefs::kMouseSettingSwapRight)); + EXPECT_FALSE(settings_dict->contains(prefs::kMouseSettingSensitivity)); + EXPECT_FALSE(settings_dict->contains(prefs::kMouseSettingReverseScrolling)); + EXPECT_FALSE( + settings_dict->contains(prefs::kMouseSettingAccelerationEnabled)); + EXPECT_FALSE(settings_dict->contains(prefs::kMouseSettingScrollSensitivity)); + EXPECT_FALSE(settings_dict->contains(prefs::kMouseSettingScrollAcceleration)); + CheckMouseSettingsAndDictAreEqual(kMouseSettingsDefault, *settings_dict); + + CallUpdateMouseSettings(kMouseKey1, kMouseSettingsNotDefault); + settings_dict = GetSettingsDict(kMouseKey1); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingSwapRight)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingReverseScrolling)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingAccelerationEnabled)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingScrollSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingScrollAcceleration)); + CheckMouseSettingsAndDictAreEqual(kMouseSettingsNotDefault, *settings_dict); + + CallUpdateMouseSettings(kMouseKey1, kMouseSettingsDefault); + settings_dict = GetSettingsDict(kMouseKey1); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingSwapRight)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingReverseScrolling)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingAccelerationEnabled)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingScrollSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kMouseSettingScrollAcceleration)); + CheckMouseSettingsAndDictAreEqual(kMouseSettingsDefault, *settings_dict); +} + class MouseSettingsPrefConversionTest : public MousePrefHandlerTest, public testing::WithParamInterface< @@ -327,12 +441,7 @@ TEST_P(MouseSettingsPrefConversionTest, CheckConversion) { CallUpdateMouseSettings(device_key_, settings_); - const auto& devices_dict = - pref_service_->GetDict(prefs::kMouseDeviceSettingsDictPref); - ASSERT_EQ(1u, devices_dict.size()); - auto* settings_dict = devices_dict.FindDict(device_key_); - ASSERT_NE(nullptr, settings_dict); - + const auto* settings_dict = GetSettingsDict(device_key_); CheckMouseSettingsAndDictAreEqual(settings_, *settings_dict); }
diff --git a/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_impl.cc b/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_impl.cc index 9c0a015..d48e9e38 100644 --- a/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_impl.cc +++ b/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_impl.cc
@@ -16,6 +16,22 @@ namespace ash { namespace { + +// Whether or not settings taken during the transition period should be +// persisted to the prefs. Values should only ever be true if the original +// setting was a user-configured value. +struct ForceTouchpadSettingPersistence { + bool sensitivity = false; + bool reverse_scrolling = false; + bool acceleration_enabled = false; + bool tap_to_click_enabled = false; + bool tap_dragging_enabled = false; + bool scroll_sensitivity = false; + bool scroll_acceleration = false; + bool haptic_sensitivity = false; + bool haptic_enabled = false; +}; + mojom::TouchpadSettingsPtr GetDefaultTouchpadSettings() { mojom::TouchpadSettingsPtr settings = mojom::TouchpadSettings::New(); settings->sensitivity = kDefaultSensitivity; @@ -33,114 +49,96 @@ // GetTouchpadSettingsFromPrefs returns a touchpad settings based on user prefs // to be used as settings for new touchpads. -mojom::TouchpadSettingsPtr GetTouchpadSettingsFromPrefs(PrefService* prefs) { +mojom::TouchpadSettingsPtr GetTouchpadSettingsFromPrefs( + PrefService* prefs, + ForceTouchpadSettingPersistence& force_persistence) { mojom::TouchpadSettingsPtr settings = mojom::TouchpadSettings::New(); - settings->sensitivity = prefs->GetInteger(prefs::kTouchpadSensitivity); - settings->reverse_scrolling = prefs->GetBoolean(prefs::kNaturalScroll); + + const auto* sensitivity_preference = + prefs->GetUserPrefValue(prefs::kTouchpadSensitivity); + settings->sensitivity = sensitivity_preference + ? sensitivity_preference->GetInt() + : kDefaultSensitivity; + force_persistence.sensitivity = sensitivity_preference != nullptr; + + const auto* reverse_scrolling_preference = + prefs->GetUserPrefValue(prefs::kNaturalScroll); + settings->reverse_scrolling = reverse_scrolling_preference + ? reverse_scrolling_preference->GetBool() + : kDefaultReverseScrolling; + force_persistence.reverse_scrolling = reverse_scrolling_preference != nullptr; + + const auto* acceleration_enabled_preference = + prefs->GetUserPrefValue(prefs::kTouchpadAcceleration); settings->acceleration_enabled = - prefs->GetBoolean(prefs::kTouchpadAcceleration); - settings->tap_to_click_enabled = prefs->GetBoolean(prefs::kTapToClickEnabled); + acceleration_enabled_preference + ? acceleration_enabled_preference->GetBool() + : kDefaultAccelerationEnabled; + force_persistence.acceleration_enabled = + acceleration_enabled_preference != nullptr; + + const auto* tap_to_click_enabled_preference = + prefs->GetUserPrefValue(prefs::kTapToClickEnabled); + settings->tap_to_click_enabled = + tap_to_click_enabled_preference + ? tap_to_click_enabled_preference->GetBool() + : kDefaultTapToClickEnabled; + force_persistence.tap_to_click_enabled = + tap_to_click_enabled_preference != nullptr; + + // Three finger click does not update `force_persistence` as it will soon be + // removed. + const auto* three_finger_click_enabled_preference = + prefs->GetUserPrefValue(prefs::kEnableTouchpadThreeFingerClick); settings->three_finger_click_enabled = - prefs->GetBoolean(prefs::kEnableTouchpadThreeFingerClick); + three_finger_click_enabled_preference + ? three_finger_click_enabled_preference->GetBool() + : kDefaultThreeFingerClickEnabled; + + const auto* tap_dragging_enabled_preference = + prefs->GetUserPrefValue(prefs::kTapDraggingEnabled); settings->tap_dragging_enabled = - prefs->GetBoolean(prefs::kTapDraggingEnabled); - settings->scroll_sensitivity = - prefs->GetInteger(prefs::kTouchpadScrollSensitivity); + tap_dragging_enabled_preference + ? tap_dragging_enabled_preference->GetBool() + : kDefaultTapDraggingEnabled; + force_persistence.tap_dragging_enabled = + tap_dragging_enabled_preference != nullptr; + + const auto* scroll_sensitivity_preference = + prefs->GetUserPrefValue(prefs::kTouchpadScrollSensitivity); + settings->scroll_sensitivity = scroll_sensitivity_preference + ? scroll_sensitivity_preference->GetInt() + : kDefaultSensitivity; + force_persistence.scroll_sensitivity = + scroll_sensitivity_preference != nullptr; + + const auto* scroll_acceleration_preference = + prefs->GetUserPrefValue(prefs::kTouchpadScrollAcceleration); settings->scroll_acceleration = - prefs->GetBoolean(prefs::kTouchpadScrollAcceleration); - settings->haptic_sensitivity = - prefs->GetInteger(prefs::kTouchpadHapticClickSensitivity); - settings->haptic_enabled = prefs->GetBoolean(prefs::kTouchpadHapticFeedback); + scroll_acceleration_preference ? scroll_acceleration_preference->GetBool() + : kDefaultScrollAcceleration; + force_persistence.scroll_acceleration = + scroll_acceleration_preference != nullptr; + + const auto* haptic_sensitivity_preference = + prefs->GetUserPrefValue(prefs::kTouchpadHapticClickSensitivity); + settings->haptic_sensitivity = haptic_sensitivity_preference + ? haptic_sensitivity_preference->GetInt() + : kDefaultHapticSensitivity; + force_persistence.haptic_sensitivity = + haptic_sensitivity_preference != nullptr; + + const auto* haptic_enabled_preference = + prefs->GetUserPrefValue(prefs::kTouchpadHapticFeedback); + settings->haptic_enabled = haptic_enabled_preference + ? haptic_enabled_preference->GetBool() + : kDefaultHapticFeedbackEnabled; + force_persistence.haptic_enabled = haptic_enabled_preference != nullptr; + return settings; } -} // namespace - -TouchpadPrefHandlerImpl::TouchpadPrefHandlerImpl() = default; -TouchpadPrefHandlerImpl::~TouchpadPrefHandlerImpl() = default; - -void TouchpadPrefHandlerImpl::InitializeTouchpadSettings( - PrefService* pref_service, - mojom::Touchpad* touchpad) { - if (!pref_service) { - touchpad->settings = GetDefaultTouchpadSettings(); - return; - } - - const auto& devices_dict = - pref_service->GetDict(prefs::kTouchpadDeviceSettingsDictPref); - const auto* settings_dict = devices_dict.FindDict(touchpad->device_key); - if (!settings_dict) { - touchpad->settings = GetNewTouchpadSettings(pref_service, *touchpad); - } else { - touchpad->settings = - RetrieveTouchpadSettings(pref_service, *touchpad, *settings_dict); - } - DCHECK(touchpad->settings); - - UpdateTouchpadSettings(pref_service, *touchpad); -} - -void TouchpadPrefHandlerImpl::UpdateTouchpadSettings( - PrefService* pref_service, - const mojom::Touchpad& touchpad) { - DCHECK(touchpad.settings); - const mojom::TouchpadSettings& settings = *touchpad.settings; - // Populate `settings_dict` with all settings in `settings`. - base::Value::Dict settings_dict; - settings_dict.Set(prefs::kTouchpadSettingSensitivity, settings.sensitivity); - settings_dict.Set(prefs::kTouchpadSettingReverseScrolling, - settings.reverse_scrolling); - settings_dict.Set(prefs::kTouchpadSettingAccelerationEnabled, - settings.acceleration_enabled); - settings_dict.Set(prefs::kTouchpadSettingScrollSensitivity, - settings.scroll_sensitivity); - settings_dict.Set(prefs::kTouchpadSettingScrollAcceleration, - settings.scroll_acceleration); - settings_dict.Set(prefs::kTouchpadSettingTapToClickEnabled, - settings.tap_to_click_enabled); - settings_dict.Set(prefs::kTouchpadSettingThreeFingerClickEnabled, - settings.three_finger_click_enabled); - settings_dict.Set(prefs::kTouchpadSettingTapDraggingEnabled, - settings.tap_dragging_enabled); - settings_dict.Set(prefs::kTouchpadSettingHapticSensitivity, - settings.haptic_sensitivity); - settings_dict.Set(prefs::kTouchpadSettingHapticEnabled, - settings.haptic_enabled); - - // Retrieve old settings and merge with the new ones. - base::Value::Dict devices_dict = - pref_service->GetDict(prefs::kTouchpadDeviceSettingsDictPref).Clone(); - - // If an old settings dict already exists for the device, merge the updated - // settings into the old settings. Otherwise, insert the dict at - // `touchpad.device_key`. - base::Value::Dict* old_settings_dict = - devices_dict.FindDict(touchpad.device_key); - if (old_settings_dict) { - old_settings_dict->Merge(std::move(settings_dict)); - } else { - devices_dict.Set(touchpad.device_key, std::move(settings_dict)); - } - - pref_service->SetDict(std::string(prefs::kTouchpadDeviceSettingsDictPref), - std::move(devices_dict)); -} - -mojom::TouchpadSettingsPtr TouchpadPrefHandlerImpl::GetNewTouchpadSettings( - PrefService* prefs, - const mojom::Touchpad& touchpad) { - // TODO(michaelcheco): Remove once transitioned to per-device settings. - if (Shell::Get()->input_device_tracker()->WasDevicePreviouslyConnected( - InputDeviceTracker::InputDeviceCategory::kTouchpad, - touchpad.device_key)) { - return GetTouchpadSettingsFromPrefs(prefs); - } - - return GetDefaultTouchpadSettings(); -} - -mojom::TouchpadSettingsPtr TouchpadPrefHandlerImpl::RetrieveTouchpadSettings( +mojom::TouchpadSettingsPtr RetrieveTouchpadSettings( PrefService* pref_service, const mojom::Touchpad& touchpad, const base::Value::Dict& settings_dict) { @@ -178,4 +176,166 @@ return settings; } +bool ExistingSettingsHasValue(base::StringPiece setting_key, + const base::Value::Dict* existing_settings_dict) { + if (!existing_settings_dict) { + return false; + } + + return existing_settings_dict->Find(setting_key) != nullptr; +} + +void UpdateTouchpadSettingsImpl( + PrefService* pref_service, + const mojom::Touchpad& touchpad, + const ForceTouchpadSettingPersistence& force_persistence) { + DCHECK(touchpad.settings); + base::Value::Dict devices_dict = + pref_service->GetDict(prefs::kTouchpadDeviceSettingsDictPref).Clone(); + base::Value::Dict* existing_settings_dict = + devices_dict.FindDict(touchpad.device_key); + const mojom::TouchpadSettings& settings = *touchpad.settings; + + // Populate `settings_dict` with all settings in `settings`. + base::Value::Dict settings_dict; + + // Settings should only be persisted if one or more of the following is true: + // - Setting was previously persisted to storage + // - `force_persistence` requires the setting to be persisted, this means this + // device is being transitioned from the old global settings to per-device + // settings and the user specified the specific value for this setting. + // - Setting is different than the default, which means the user manually + // changed the value. + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingSensitivity, + existing_settings_dict) || + force_persistence.sensitivity || + settings.sensitivity != kDefaultSensitivity) { + settings_dict.Set(prefs::kTouchpadSettingSensitivity, settings.sensitivity); + } + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingReverseScrolling, + existing_settings_dict) || + force_persistence.reverse_scrolling || + settings.reverse_scrolling != kDefaultReverseScrolling) { + settings_dict.Set(prefs::kTouchpadSettingReverseScrolling, + settings.reverse_scrolling); + } + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingAccelerationEnabled, + existing_settings_dict) || + force_persistence.acceleration_enabled || + settings.acceleration_enabled != kDefaultAccelerationEnabled) { + settings_dict.Set(prefs::kTouchpadSettingAccelerationEnabled, + settings.acceleration_enabled); + } + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingScrollSensitivity, + existing_settings_dict) || + force_persistence.scroll_sensitivity || + settings.scroll_sensitivity != kDefaultSensitivity) { + settings_dict.Set(prefs::kTouchpadSettingScrollSensitivity, + settings.scroll_sensitivity); + } + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingScrollAcceleration, + existing_settings_dict) || + force_persistence.scroll_acceleration || + settings.scroll_acceleration != kDefaultScrollAcceleration) { + settings_dict.Set(prefs::kTouchpadSettingScrollAcceleration, + settings.scroll_acceleration); + } + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingTapToClickEnabled, + existing_settings_dict) || + force_persistence.tap_to_click_enabled || + settings.tap_to_click_enabled != kDefaultTapToClickEnabled) { + settings_dict.Set(prefs::kTouchpadSettingTapToClickEnabled, + settings.tap_to_click_enabled); + } + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingThreeFingerClickEnabled, + existing_settings_dict) || + settings.three_finger_click_enabled != kDefaultThreeFingerClickEnabled) { + settings_dict.Set(prefs::kTouchpadSettingThreeFingerClickEnabled, + settings.three_finger_click_enabled); + } + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingTapDraggingEnabled, + existing_settings_dict) || + force_persistence.tap_dragging_enabled || + settings.tap_dragging_enabled != kDefaultTapDraggingEnabled) { + settings_dict.Set(prefs::kTouchpadSettingTapDraggingEnabled, + settings.tap_dragging_enabled); + } + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingHapticSensitivity, + existing_settings_dict) || + force_persistence.haptic_sensitivity || + settings.haptic_sensitivity != kDefaultSensitivity) { + settings_dict.Set(prefs::kTouchpadSettingHapticSensitivity, + settings.haptic_sensitivity); + } + + if (ExistingSettingsHasValue(prefs::kTouchpadSettingHapticEnabled, + existing_settings_dict) || + force_persistence.haptic_enabled || + settings.haptic_enabled != kDefaultHapticFeedbackEnabled) { + settings_dict.Set(prefs::kTouchpadSettingHapticEnabled, + settings.haptic_enabled); + } + + // If an old settings dict already exists for the device, merge the updated + // settings into the old settings. Otherwise, insert the dict at + // `touchpad.device_key`. + if (existing_settings_dict) { + existing_settings_dict->Merge(std::move(settings_dict)); + } else { + devices_dict.Set(touchpad.device_key, std::move(settings_dict)); + } + + pref_service->SetDict(std::string(prefs::kTouchpadDeviceSettingsDictPref), + std::move(devices_dict)); +} + +} // namespace + +TouchpadPrefHandlerImpl::TouchpadPrefHandlerImpl() = default; +TouchpadPrefHandlerImpl::~TouchpadPrefHandlerImpl() = default; + +void TouchpadPrefHandlerImpl::InitializeTouchpadSettings( + PrefService* pref_service, + mojom::Touchpad* touchpad) { + if (!pref_service) { + touchpad->settings = GetDefaultTouchpadSettings(); + return; + } + + const auto& devices_dict = + pref_service->GetDict(prefs::kTouchpadDeviceSettingsDictPref); + const auto* settings_dict = devices_dict.FindDict(touchpad->device_key); + ForceTouchpadSettingPersistence force_persistence; + if (settings_dict) { + touchpad->settings = + RetrieveTouchpadSettings(pref_service, *touchpad, *settings_dict); + } else if (Shell::Get()->input_device_tracker()->WasDevicePreviouslyConnected( + InputDeviceTracker::InputDeviceCategory::kTouchpad, + touchpad->device_key)) { + touchpad->settings = + GetTouchpadSettingsFromPrefs(pref_service, force_persistence); + } else { + touchpad->settings = GetDefaultTouchpadSettings(); + } + DCHECK(touchpad->settings); + + UpdateTouchpadSettingsImpl(pref_service, *touchpad, force_persistence); +} + +void TouchpadPrefHandlerImpl::UpdateTouchpadSettings( + PrefService* pref_service, + const mojom::Touchpad& touchpad) { + UpdateTouchpadSettingsImpl(pref_service, touchpad, + /*force_persistence=*/{}); +} + } // namespace ash
diff --git a/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_impl.h b/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_impl.h index 2bef2b7..c2f0c4c 100644 --- a/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_impl.h +++ b/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_impl.h
@@ -25,15 +25,6 @@ mojom::Touchpad* touchpad) override; void UpdateTouchpadSettings(PrefService* pref_service, const mojom::Touchpad& touchpad) override; - - private: - mojom::TouchpadSettingsPtr GetNewTouchpadSettings( - PrefService* prefs, - const mojom::Touchpad& touchpad); - mojom::TouchpadSettingsPtr RetrieveTouchpadSettings( - PrefService* prefs, - const mojom::Touchpad& touchpad, - const base::Value::Dict& settings_dict); }; } // namespace ash
diff --git a/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_unittest.cc b/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_unittest.cc index 3ec8bbc..1d6dcc62 100644 --- a/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_unittest.cc +++ b/ash/system/input_device_settings/pref_handlers/touchpad_pref_handler_unittest.cc
@@ -45,6 +45,18 @@ /*haptic_sensitivity=*/kDefaultHapticSensitivity, /*haptic_enabled=*/kDefaultHapticFeedbackEnabled); +const mojom::TouchpadSettings kTouchpadSettingsNotDefault( + /*sensitivity=*/1, + /*reverse_scrolling=*/!kDefaultReverseScrolling, + /*acceleration_enabled=*/!kDefaultAccelerationEnabled, + /*tap_to_click_enabled=*/!kDefaultTapToClickEnabled, + /*three_finger_click_enabled=*/!kDefaultThreeFingerClickEnabled, + /*tap_dragging_enabled=*/!kDefaultTapDraggingEnabled, + /*scroll_sensitivity=*/1, + /*scroll_acceleration=*/!kDefaultScrollAcceleration, + /*haptic_sensitivity=*/1, + /*haptic_enabled=*/!kDefaultHapticFeedbackEnabled); + const mojom::TouchpadSettings kTouchpadSettings1( /*sensitivity=*/1, /*reverse_scrolling=*/false, @@ -97,25 +109,47 @@ // We are using these test constants as a a way to differentiate values // retrieved from prefs or default touchpad settings. pref_service_->registry()->RegisterIntegerPref(prefs::kTouchpadSensitivity, - kTestSensitivity); + kDefaultSensitivity); pref_service_->registry()->RegisterBooleanPref(prefs::kNaturalScroll, - kTestReverseScrolling); + kDefaultReverseScrolling); pref_service_->registry()->RegisterBooleanPref(prefs::kTouchpadAcceleration, - kTestAccelerationEnabled); + kDefaultAccelerationEnabled); pref_service_->registry()->RegisterBooleanPref(prefs::kTapToClickEnabled, - kTestTapToClickEnabled); + kDefaultTapToClickEnabled); pref_service_->registry()->RegisterBooleanPref( - prefs::kEnableTouchpadThreeFingerClick, kTestThreeFingerClickEnabled); + prefs::kEnableTouchpadThreeFingerClick, + kDefaultThreeFingerClickEnabled); pref_service_->registry()->RegisterBooleanPref(prefs::kTapDraggingEnabled, - kTestTapDraggingEnabled); + kDefaultTapDraggingEnabled); pref_service_->registry()->RegisterIntegerPref( - prefs::kTouchpadScrollSensitivity, kTestSensitivity); + prefs::kTouchpadScrollSensitivity, kDefaultSensitivity); pref_service_->registry()->RegisterBooleanPref( - prefs::kTouchpadScrollAcceleration, kTestScrollAcceleration); + prefs::kTouchpadScrollAcceleration, kDefaultScrollAcceleration); pref_service_->registry()->RegisterIntegerPref( - prefs::kTouchpadHapticClickSensitivity, kTestHapticSensitivity); + prefs::kTouchpadHapticClickSensitivity, kDefaultHapticSensitivity); pref_service_->registry()->RegisterBooleanPref( - prefs::kTouchpadHapticFeedback, kTestHapticFeedbackEnabled); + prefs::kTouchpadHapticFeedback, kDefaultHapticFeedbackEnabled); + + pref_service_->SetUserPref(prefs::kTouchpadSensitivity, + base::Value(kTestSensitivity)); + pref_service_->SetUserPref(prefs::kNaturalScroll, + base::Value(kTestReverseScrolling)); + pref_service_->SetUserPref(prefs::kTouchpadAcceleration, + base::Value(kTestAccelerationEnabled)); + pref_service_->SetUserPref(prefs::kTapToClickEnabled, + base::Value(kTestTapToClickEnabled)); + pref_service_->SetUserPref(prefs::kEnableTouchpadThreeFingerClick, + base::Value(kTestThreeFingerClickEnabled)); + pref_service_->SetUserPref(prefs::kTapDraggingEnabled, + base::Value(kTestTapDraggingEnabled)); + pref_service_->SetUserPref(prefs::kTouchpadScrollSensitivity, + base::Value(kTestSensitivity)); + pref_service_->SetUserPref(prefs::kTouchpadScrollAcceleration, + base::Value(kTestScrollAcceleration)); + pref_service_->SetUserPref(prefs::kTouchpadHapticClickSensitivity, + base::Value(kTestHapticSensitivity)); + pref_service_->SetUserPref(prefs::kTouchpadHapticFeedback, + base::Value(kTestHapticFeedbackEnabled)); } void CheckTouchpadSettingsAndDictAreEqual( @@ -123,53 +157,85 @@ const base::Value::Dict& settings_dict) { const auto sensitivity = settings_dict.FindInt(prefs::kTouchpadSettingSensitivity); - ASSERT_TRUE(sensitivity.has_value()); - EXPECT_EQ(settings.sensitivity, sensitivity); + if (sensitivity.has_value()) { + EXPECT_EQ(settings.sensitivity, sensitivity); + } else { + EXPECT_EQ(settings.sensitivity, kDefaultSensitivity); + } const auto reverse_scrolling = settings_dict.FindBool(prefs::kTouchpadSettingReverseScrolling); - ASSERT_TRUE(reverse_scrolling.has_value()); - EXPECT_EQ(settings.reverse_scrolling, reverse_scrolling); + if (reverse_scrolling.has_value()) { + EXPECT_EQ(settings.reverse_scrolling, reverse_scrolling); + } else { + EXPECT_EQ(settings.reverse_scrolling, kDefaultReverseScrolling); + } const auto acceleration_enabled = settings_dict.FindBool(prefs::kTouchpadSettingAccelerationEnabled); - ASSERT_TRUE(acceleration_enabled.has_value()); - EXPECT_EQ(settings.acceleration_enabled, acceleration_enabled); + if (acceleration_enabled.has_value()) { + EXPECT_EQ(settings.acceleration_enabled, acceleration_enabled); + } else { + EXPECT_EQ(settings.acceleration_enabled, kDefaultAccelerationEnabled); + } const auto scroll_sensitivity = settings_dict.FindInt(prefs::kTouchpadSettingScrollSensitivity); - ASSERT_TRUE(scroll_sensitivity.has_value()); - EXPECT_EQ(settings.scroll_sensitivity, scroll_sensitivity); + if (scroll_sensitivity.has_value()) { + EXPECT_EQ(settings.scroll_sensitivity, scroll_sensitivity); + } else { + EXPECT_EQ(settings.scroll_sensitivity, kDefaultSensitivity); + } const auto scroll_acceleration = settings_dict.FindBool(prefs::kTouchpadSettingScrollAcceleration); - ASSERT_TRUE(scroll_acceleration.has_value()); - EXPECT_EQ(settings.scroll_acceleration, scroll_acceleration); + if (scroll_acceleration.has_value()) { + EXPECT_EQ(settings.scroll_acceleration, scroll_acceleration); + } else { + EXPECT_EQ(settings.scroll_acceleration, kDefaultScrollAcceleration); + } const auto tap_to_click_enabled = settings_dict.FindBool(prefs::kTouchpadSettingTapToClickEnabled); - ASSERT_TRUE(tap_to_click_enabled.has_value()); - EXPECT_EQ(settings.tap_to_click_enabled, tap_to_click_enabled); + if (tap_to_click_enabled.has_value()) { + EXPECT_EQ(settings.tap_to_click_enabled, tap_to_click_enabled); + } else { + EXPECT_EQ(settings.tap_to_click_enabled, kDefaultTapToClickEnabled); + } const auto three_finger_click_enabled = settings_dict.FindBool(prefs::kTouchpadSettingThreeFingerClickEnabled); - ASSERT_TRUE(three_finger_click_enabled.has_value()); - EXPECT_EQ(settings.three_finger_click_enabled, three_finger_click_enabled); + if (three_finger_click_enabled.has_value()) { + EXPECT_EQ(settings.three_finger_click_enabled, + three_finger_click_enabled); + } else { + EXPECT_EQ(settings.three_finger_click_enabled, + kDefaultThreeFingerClickEnabled); + } const auto tap_dragging_enabled = settings_dict.FindBool(prefs::kTouchpadSettingTapDraggingEnabled); - ASSERT_TRUE(tap_dragging_enabled.has_value()); - EXPECT_EQ(settings.tap_dragging_enabled, tap_dragging_enabled); + if (tap_dragging_enabled.has_value()) { + EXPECT_EQ(settings.tap_dragging_enabled, tap_dragging_enabled); + } else { + EXPECT_EQ(settings.tap_dragging_enabled, kDefaultTapDraggingEnabled); + } const auto haptic_sensitivity = settings_dict.FindInt(prefs::kTouchpadSettingHapticSensitivity); - ASSERT_TRUE(haptic_sensitivity.has_value()); - EXPECT_EQ(settings.haptic_sensitivity, haptic_sensitivity); + if (haptic_sensitivity.has_value()) { + EXPECT_EQ(settings.haptic_sensitivity, haptic_sensitivity); + } else { + EXPECT_EQ(settings.haptic_sensitivity, kDefaultHapticSensitivity); + } const auto haptic_enabled = settings_dict.FindBool(prefs::kTouchpadSettingHapticEnabled); - ASSERT_TRUE(haptic_enabled.has_value()); - EXPECT_EQ(settings.haptic_enabled, haptic_enabled); + if (haptic_enabled.has_value()) { + EXPECT_EQ(settings.haptic_enabled, haptic_enabled); + } else { + EXPECT_EQ(settings.haptic_enabled, kDefaultHapticFeedbackEnabled); + } } void CallUpdateTouchpadSettings(const std::string& device_key, @@ -191,6 +257,16 @@ return std::move(touchpad->settings); } + const base::Value::Dict* GetSettingsDict(const std::string& device_key) { + const auto& devices_dict = + pref_service_->GetDict(prefs::kTouchpadDeviceSettingsDictPref); + EXPECT_EQ(1u, devices_dict.size()); + const auto* settings_dict = devices_dict.FindDict(device_key); + EXPECT_NE(nullptr, settings_dict); + + return settings_dict; + } + protected: std::unique_ptr<TouchpadPrefHandlerImpl> pref_handler_; std::unique_ptr<TestingPrefServiceSimple> pref_service_; @@ -330,6 +406,54 @@ *settings_dict); } +TEST_F(TouchpadPrefHandlerTest, + TransitionPeriodSettingsPersistedWhenUserChosen) { + mojom::Touchpad touchpad; + touchpad.device_key = kTouchpadKey1; + Shell::Get()->input_device_tracker()->OnTouchpadConnected(touchpad); + + pref_service_->SetUserPref(prefs::kTouchpadSensitivity, + base::Value(kDefaultSensitivity)); + pref_service_->SetUserPref(prefs::kNaturalScroll, + base::Value(kDefaultReverseScrolling)); + pref_service_->SetUserPref(prefs::kTouchpadAcceleration, + base::Value(kDefaultAccelerationEnabled)); + pref_service_->SetUserPref(prefs::kTapToClickEnabled, + base::Value(kDefaultTapToClickEnabled)); + pref_service_->SetUserPref(prefs::kTapDraggingEnabled, + base::Value(kDefaultTapDraggingEnabled)); + pref_service_->SetUserPref(prefs::kTouchpadScrollSensitivity, + base::Value(kDefaultSensitivity)); + pref_service_->SetUserPref(prefs::kTouchpadScrollAcceleration, + base::Value(kDefaultScrollAcceleration)); + pref_service_->SetUserPref(prefs::kTouchpadHapticClickSensitivity, + base::Value(kDefaultHapticSensitivity)); + pref_service_->SetUserPref(prefs::kTouchpadHapticFeedback, + base::Value(kDefaultHapticFeedbackEnabled)); + + auto settings = CallInitializeTouchpadSettings(kTouchpadKey1); + EXPECT_EQ(kTouchpadSettingsDefault, *settings); + + const auto* settings_dict = GetSettingsDict(kTouchpadKey1); + EXPECT_TRUE(settings_dict->contains(prefs::kTouchpadSettingSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kTouchpadSettingReverseScrolling)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingAccelerationEnabled)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingTapToClickEnabled)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingTapDraggingEnabled)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingScrollSensitivity)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingScrollAcceleration)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingHapticSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kTouchpadSettingHapticEnabled)); + CheckTouchpadSettingsAndDictAreEqual(kTouchpadSettingsDefault, + *settings_dict); +} + TEST_F(TouchpadPrefHandlerTest, TouchpadObserveredInTransitionPeriod) { mojom::Touchpad touchpad; touchpad.device_key = kTouchpadKey1; @@ -350,6 +474,70 @@ ASSERT_EQ(settings->haptic_enabled, kTestHapticFeedbackEnabled); } +TEST_F(TouchpadPrefHandlerTest, DefaultNotPersistedUntilUpdated) { + CallUpdateTouchpadSettings(kTouchpadKey1, kTouchpadSettingsDefault); + + const auto* settings_dict = GetSettingsDict(kTouchpadKey1); + EXPECT_FALSE(settings_dict->contains(prefs::kTouchpadSettingSensitivity)); + EXPECT_FALSE( + settings_dict->contains(prefs::kTouchpadSettingReverseScrolling)); + EXPECT_FALSE( + settings_dict->contains(prefs::kTouchpadSettingAccelerationEnabled)); + EXPECT_FALSE( + settings_dict->contains(prefs::kTouchpadSettingTapToClickEnabled)); + EXPECT_FALSE( + settings_dict->contains(prefs::kTouchpadSettingTapDraggingEnabled)); + EXPECT_FALSE( + settings_dict->contains(prefs::kTouchpadSettingScrollSensitivity)); + EXPECT_FALSE( + settings_dict->contains(prefs::kTouchpadSettingScrollAcceleration)); + EXPECT_FALSE( + settings_dict->contains(prefs::kTouchpadSettingHapticSensitivity)); + EXPECT_FALSE(settings_dict->contains(prefs::kTouchpadSettingHapticEnabled)); + CheckTouchpadSettingsAndDictAreEqual(kTouchpadSettingsDefault, + *settings_dict); + + CallUpdateTouchpadSettings(kTouchpadKey1, kTouchpadSettingsNotDefault); + settings_dict = GetSettingsDict(kTouchpadKey1); + EXPECT_TRUE(settings_dict->contains(prefs::kTouchpadSettingSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kTouchpadSettingReverseScrolling)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingAccelerationEnabled)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingTapToClickEnabled)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingTapDraggingEnabled)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingScrollSensitivity)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingScrollAcceleration)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingHapticSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kTouchpadSettingHapticEnabled)); + CheckTouchpadSettingsAndDictAreEqual(kTouchpadSettingsNotDefault, + *settings_dict); + + CallUpdateTouchpadSettings(kTouchpadKey1, kTouchpadSettingsDefault); + settings_dict = GetSettingsDict(kTouchpadKey1); + EXPECT_TRUE(settings_dict->contains(prefs::kTouchpadSettingSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kTouchpadSettingReverseScrolling)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingAccelerationEnabled)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingTapToClickEnabled)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingTapDraggingEnabled)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingScrollSensitivity)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingScrollAcceleration)); + EXPECT_TRUE( + settings_dict->contains(prefs::kTouchpadSettingHapticSensitivity)); + EXPECT_TRUE(settings_dict->contains(prefs::kTouchpadSettingHapticEnabled)); + CheckTouchpadSettingsAndDictAreEqual(kTouchpadSettingsDefault, + *settings_dict); +} + class TouchpadSettingsPrefConversionTest : public TouchpadPrefHandlerTest, public testing::WithParamInterface< @@ -383,12 +571,7 @@ TEST_P(TouchpadSettingsPrefConversionTest, CheckConversion) { CallUpdateTouchpadSettings(device_key_, settings_); - const auto& devices_dict = - pref_service_->GetDict(prefs::kTouchpadDeviceSettingsDictPref); - ASSERT_EQ(1u, devices_dict.size()); - auto* settings_dict = devices_dict.FindDict(device_key_); - ASSERT_NE(nullptr, settings_dict); - + const auto* settings_dict = GetSettingsDict(device_key_); CheckTouchpadSettingsAndDictAreEqual(settings_, *settings_dict); }
diff --git a/ash/system/network/network_list_network_header_view.cc b/ash/system/network/network_list_network_header_view.cc index 67ec65d..bf2ee98e 100644 --- a/ash/system/network/network_list_network_header_view.cc +++ b/ash/system/network/network_list_network_header_view.cc
@@ -8,6 +8,7 @@ #include "ash/constants/ash_features.h" #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" +#include "ash/style/switch.h" #include "ash/system/model/system_tray_model.h" #include "ash/system/network/network_list_header_view.h" #include "ash/system/network/tray_network_state_model.h" @@ -41,13 +42,19 @@ toggle_ = toggle.get(); if (features::IsQsRevampEnabled()) { + auto qs_toggle = std::make_unique<Switch>( + base::BindRepeating(&NetworkListNetworkHeaderView::ToggleButtonPressed, + weak_factory_.GetWeakPtr())); + qs_toggle->SetAccessibleName(l10n_util::GetStringUTF16(label_id)); + qs_toggle->SetID(kQsToggleButtonId); + qs_toggle_ = qs_toggle.get(); auto image_view = std::make_unique<views::ImageView>(); image_view->SetImage(ui::ImageModel::FromVectorIcon( vector_icon, cros_tokens::kCrosSysOnSurface)); entry_row()->AddViewAndLabel(std::move(image_view), l10n_util::GetStringUTF16(label_id)); entry_row()->SetExpandable(true); - entry_row()->AddRightView(toggle.release()); + entry_row()->AddRightView(qs_toggle.release()); } else { container()->AddView(TriView::Container::END, toggle.release()); } @@ -58,16 +65,24 @@ void NetworkListNetworkHeaderView::SetToggleState(bool enabled, bool is_on, bool animate_toggle) { - toggle_->SetEnabled(enabled); - toggle_->SetAcceptsEvents(enabled); - if (features::IsQsRevampEnabled()) { entry_row()->SetEnabled(enabled); - // Update the on/off label. + // Update the on/off label. entry_row()->text_label()->SetText(l10n_util::GetStringUTF16( is_on ? enabled_label_id_ : IDS_ASH_QUICK_SETTINGS_NETWORK_DISABLED)); + + qs_toggle_->SetEnabled(enabled); + qs_toggle_->SetCanProcessEventsWithinSubtree(enabled); + if (animate_toggle) { + qs_toggle_->AnimateIsOn(is_on); + } else { + qs_toggle_->SetIsOn(is_on); + } + return; } + toggle_->SetEnabled(enabled); + toggle_->SetAcceptsEvents(enabled); if (animate_toggle) { toggle_->AnimateIsOn(is_on); return; @@ -81,7 +96,11 @@ void NetworkListNetworkHeaderView::OnToggleToggled(bool is_on) {} void NetworkListNetworkHeaderView::SetToggleVisibility(bool visible) { - toggle_->SetVisible(visible); + if (features::IsQsRevampEnabled()) { + qs_toggle_->SetVisible(visible); + } else { + toggle_->SetVisible(visible); + } } void NetworkListNetworkHeaderView::ToggleButtonPressed() { @@ -96,8 +115,14 @@ // disabling of mobile radio. The toggle will get unlocked in the next // call to SetToggleState(). Note that we don't disable/enable // because that would clear focus. - toggle_->SetAcceptsEvents(false); - OnToggleToggled(has_new_state ? toggle_->GetIsOn() : !toggle_->GetIsOn()); + if (features::IsQsRevampEnabled()) { + qs_toggle_->SetAcceptsEvents(false); + OnToggleToggled(has_new_state ? qs_toggle_->GetIsOn() + : !qs_toggle_->GetIsOn()); + } else { + toggle_->SetAcceptsEvents(false); + OnToggleToggled(has_new_state ? toggle_->GetIsOn() : !toggle_->GetIsOn()); + } } } // namespace ash
diff --git a/ash/system/network/network_list_network_header_view.h b/ash/system/network/network_list_network_header_view.h index dc4612de..1e68334 100644 --- a/ash/system/network/network_list_network_header_view.h +++ b/ash/system/network/network_list_network_header_view.h
@@ -6,6 +6,7 @@ #define ASH_SYSTEM_NETWORK_NETWORK_LIST_NETWORK_HEADER_VIEW_H_ #include "ash/ash_export.h" +#include "ash/style/switch.h" #include "ash/system/network/network_list_header_view.h" #include "ash/system/tray/tri_view.h" #include "base/memory/weak_ptr.h" @@ -57,6 +58,7 @@ // Used for testing. static constexpr int kToggleButtonId = NetworkListHeaderView::kTitleLabelViewId + 1; + static constexpr int kQsToggleButtonId = kToggleButtonId + 1; private: friend class NetworkListNetworkHeaderViewTest; @@ -72,8 +74,10 @@ TrayNetworkStateModel* model_; int const enabled_label_id_; - // ToggleButton to toggle section on or off. + // `ToggleButton` to toggle section on or off. views::ToggleButton* toggle_ = nullptr; + // `KnobSwitch` to toggle section on or off. + Switch* qs_toggle_ = nullptr; Delegate* delegate_ = nullptr;
diff --git a/ash/system/network/network_list_view_controller_unittest.cc b/ash/system/network/network_list_view_controller_unittest.cc index bc86e46..f28334b 100644 --- a/ash/system/network/network_list_view_controller_unittest.cc +++ b/ash/system/network/network_list_view_controller_unittest.cc
@@ -15,6 +15,7 @@ #include "ash/shell.h" #include "ash/strings/grit/ash_strings.h" #include "ash/style/ash_color_provider.h" +#include "ash/style/switch.h" #include "ash/system/model/system_tray_model.h" #include "ash/system/network/network_detailed_network_view_impl.h" #include "ash/system/network/network_utils.h" @@ -225,6 +226,36 @@ return GetWifiSubHeader()->toggle_; } + Switch* GetQsMobileToggleButton() { return GetMobileSubHeader()->qs_toggle_; } + + Switch* GetQsWifiToggleButton() { return GetWifiSubHeader()->qs_toggle_; } + + void CheckWifiToggleButtonStatus(bool toggled_on) { + if (IsQsRevampEnabled()) { + EXPECT_TRUE(GetQsWifiToggleButton()->GetVisible()); + EXPECT_TRUE(GetQsWifiToggleButton()->GetEnabled()); + EXPECT_EQ(GetQsWifiToggleButton()->GetIsOn(), toggled_on); + } else { + EXPECT_TRUE(GetWifiToggleButton()->GetVisible()); + EXPECT_TRUE(GetWifiToggleButton()->GetEnabled()); + EXPECT_EQ(GetWifiToggleButton()->GetIsOn(), toggled_on); + } + } + + void CheckMobileToggleButtonStatus(bool enabled, + bool toggled_on, + bool visible = true) { + if (IsQsRevampEnabled()) { + EXPECT_EQ(GetQsMobileToggleButton()->GetVisible(), visible); + EXPECT_EQ(GetQsMobileToggleButton()->GetEnabled(), enabled); + EXPECT_EQ(GetQsMobileToggleButton()->GetIsOn(), toggled_on); + } else { + EXPECT_EQ(GetMobileToggleButton()->GetVisible(), visible); + EXPECT_EQ(GetMobileToggleButton()->GetEnabled(), enabled); + EXPECT_EQ(GetMobileToggleButton()->GetIsOn(), toggled_on); + } + } + IconButton* GetAddEsimButton() { return FindViewById<IconButton*>( NetworkListMobileHeaderViewImpl::kAddESimButtonId); @@ -298,7 +329,7 @@ // Expect that the view at `index` is a network item, and that it is an // wifi network. - if (!wifi_network_count && GetWifiToggleButton()->GetIsOn()) { + if (!wifi_network_count && GetQsWifiToggleButton()->GetIsOn()) { // When no WiFi networks are available, status message is shown. EXPECT_NE(nullptr, GetWifiStatusMessage()); } @@ -592,9 +623,7 @@ ASSERT_THAT(GetWifiSubHeader(), NotNull()); EXPECT_THAT(GetWifiSeparator(), IsNull()); - EXPECT_TRUE(GetWifiToggleButton()->GetVisible()); - EXPECT_TRUE(GetWifiToggleButton()->GetEnabled()); - EXPECT_TRUE(GetWifiToggleButton()->GetIsOn()); + CheckWifiToggleButtonStatus(/*toggled_on=*/true); histogram_tester.ExpectBucketCount("ChromeOS.SystemTray.Network.SectionShown", DetailedViewSection::kWifiSection, 1); @@ -606,9 +635,7 @@ cros_network()->SetDeviceProperties(properties.Clone()); ASSERT_THAT(GetWifiSubHeader(), NotNull()); - EXPECT_TRUE(GetWifiToggleButton()->GetVisible()); - EXPECT_TRUE(GetWifiToggleButton()->GetEnabled()); - EXPECT_FALSE(GetWifiToggleButton()->GetIsOn()); + CheckWifiToggleButtonStatus(/*toggled_on=*/false); histogram_tester.ExpectBucketCount("ChromeOS.SystemTray.Network.SectionShown", DetailedViewSection::kWifiSection, 1); } @@ -913,9 +940,7 @@ cros_network()->SetDeviceProperties(properties.Clone()); ASSERT_THAT(GetMobileStatusMessage(), NotNull()); - EXPECT_TRUE(GetMobileToggleButton()->GetVisible()); - EXPECT_FALSE(GetMobileToggleButton()->GetEnabled()); - EXPECT_FALSE(GetMobileToggleButton()->GetIsOn()); + CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/false); EXPECT_EQ( l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR), GetMobileStatusMessage()->label()->GetText()); @@ -927,9 +952,7 @@ ASSERT_THAT(GetMobileSubHeader(), NotNull()); EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS), GetMobileStatusMessage()->label()->GetText()); - EXPECT_TRUE(GetMobileToggleButton()->GetEnabled()); - EXPECT_TRUE(GetMobileToggleButton()->GetIsOn()); - EXPECT_TRUE(GetMobileToggleButton()->GetVisible()); + CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/true); // No message is shown when there are available networks. cros_network()->AddNetworkAndDevice( @@ -938,9 +961,7 @@ ConnectionStateType::kConnected)); EXPECT_THAT(GetMobileStatusMessage(), IsNull()); - EXPECT_TRUE(GetMobileToggleButton()->GetEnabled()); - EXPECT_TRUE(GetMobileToggleButton()->GetIsOn()); - EXPECT_TRUE(GetMobileToggleButton()->GetVisible()); + CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/true); // Message shown again when list is empty. cros_network()->ClearNetworksAndDevices(); @@ -949,15 +970,17 @@ ASSERT_THAT(GetMobileStatusMessage(), NotNull()); EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS), GetMobileStatusMessage()->label()->GetText()); - EXPECT_TRUE(GetMobileToggleButton()->GetVisible()); + if (IsQsRevampEnabled()) { + EXPECT_TRUE(GetQsMobileToggleButton()->GetVisible()); + } else { + EXPECT_TRUE(GetMobileToggleButton()->GetVisible()); + } // No message is shown when inhibited. properties->inhibit_reason = InhibitReason::kResettingEuiccMemory; cros_network()->SetDeviceProperties(properties.Clone()); EXPECT_THAT(GetMobileStatusMessage(), IsNull()); - EXPECT_FALSE(GetMobileToggleButton()->GetEnabled()); - EXPECT_TRUE(GetMobileToggleButton()->GetIsOn()); - EXPECT_TRUE(GetMobileToggleButton()->GetVisible()); + CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/true); // Uninhibit the device. properties->inhibit_reason = InhibitReason::kNotInhibited; @@ -967,9 +990,7 @@ ASSERT_THAT(GetMobileStatusMessage(), NotNull()); EXPECT_EQ(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NO_MOBILE_NETWORKS), GetMobileStatusMessage()->label()->GetText()); - EXPECT_TRUE(GetMobileToggleButton()->GetEnabled()); - EXPECT_TRUE(GetMobileToggleButton()->GetIsOn()); - EXPECT_TRUE(GetMobileToggleButton()->GetVisible()); + CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/true); // When device is in disabling message is shown. properties->device_state = DeviceStateType::kDisabling; @@ -979,9 +1000,7 @@ EXPECT_EQ( l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_MOBILE_DISABLING), GetMobileStatusMessage()->label()->GetText()); - EXPECT_FALSE(GetMobileToggleButton()->GetEnabled()); - EXPECT_FALSE(GetMobileToggleButton()->GetIsOn()); - EXPECT_TRUE(GetMobileToggleButton()->GetVisible()); + CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/false); properties->device_state = DeviceStateType::kDisabled; cros_network()->SetDeviceProperties(properties.Clone()); @@ -998,9 +1017,7 @@ GetMobileStatusMessage()->label()->GetText()); } - EXPECT_TRUE(GetMobileToggleButton()->GetEnabled()); - EXPECT_FALSE(GetMobileToggleButton()->GetIsOn()); - EXPECT_TRUE(GetMobileToggleButton()->GetVisible()); + CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/false); // The toggle is not enabled, the cellular device SIM is locked, and user // cannot open the settings page. @@ -1011,7 +1028,11 @@ properties->sim_lock_status->lock_type = "lock"; cros_network()->SetDeviceProperties(properties.Clone()); - EXPECT_FALSE(GetMobileToggleButton()->GetEnabled()); + if (IsQsRevampEnabled()) { + EXPECT_FALSE(GetQsMobileToggleButton()->GetEnabled()); + } else { + EXPECT_FALSE(GetMobileToggleButton()->GetEnabled()); + } } TEST_P(NetworkListViewControllerTest, HasCorrectTetherStatusMessage) { @@ -1027,8 +1048,7 @@ ASSERT_THAT(GetMobileStatusMessage(), NotNull()); ASSERT_THAT(GetMobileSubHeader(), NotNull()); - EXPECT_TRUE(GetMobileToggleButton()->GetEnabled()); - EXPECT_TRUE(GetMobileToggleButton()->GetIsOn()); + CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/true); EXPECT_EQ( l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NO_MOBILE_DEVICES_FOUND), GetMobileStatusMessage()->label()->GetText()); @@ -1037,8 +1057,7 @@ properties->device_state = DeviceStateType::kUninitialized; cros_network()->SetDeviceProperties(properties.Clone()); SetBluetoothAdapterState(BluetoothSystemState::kEnabling); - EXPECT_FALSE(GetMobileToggleButton()->GetEnabled()); - EXPECT_TRUE(GetMobileToggleButton()->GetIsOn()); + CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/true); ASSERT_THAT(GetMobileStatusMessage(), NotNull()); EXPECT_EQ( l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR), @@ -1046,8 +1065,7 @@ // Set Bluetooth device to disabling. SetBluetoothAdapterState(BluetoothSystemState::kDisabling); - EXPECT_TRUE(GetMobileToggleButton()->GetEnabled()); - EXPECT_FALSE(GetMobileToggleButton()->GetIsOn()); + CheckMobileToggleButtonStatus(/*enabled=*/true, /*toggled_on=*/false); ASSERT_THAT(GetMobileStatusMessage(), NotNull()); EXPECT_EQ(l10n_util::GetStringUTF16( IDS_ASH_STATUS_TRAY_ENABLING_MOBILE_ENABLES_BLUETOOTH), @@ -1056,8 +1074,7 @@ // Simulate login as secondary user and disable Bluetooth device. LoginAsSecondaryUser(); SetBluetoothAdapterState(BluetoothSystemState::kDisabled); - EXPECT_FALSE(GetMobileToggleButton()->GetEnabled()); - EXPECT_FALSE(GetMobileToggleButton()->GetIsOn()); + CheckMobileToggleButtonStatus(/*enabled=*/false, /*toggled_on=*/false); ASSERT_THAT(GetMobileStatusMessage(), NotNull()); EXPECT_EQ(l10n_util::GetStringUTF16( IDS_ASH_STATUS_TRAY_ENABLING_MOBILE_ENABLES_BLUETOOTH),
diff --git a/ash/system/phonehub/phone_hub_ui_controller.cc b/ash/system/phonehub/phone_hub_ui_controller.cc index f85dfc39..bf714768 100644 --- a/ash/system/phonehub/phone_hub_ui_controller.cc +++ b/ash/system/phonehub/phone_hub_ui_controller.cc
@@ -219,6 +219,14 @@ if (feature_status == FeatureStatus::kEnabledButDisconnected) phone_hub_manager_->GetConnectionScheduler()->ScheduleConnectionNow(); + if (features::IsEcheNetworkConnectionStateEnabled() && + feature_status == FeatureStatus::kEnabledAndConnected) { + if (phone_hub_manager_->GetEcheConnectionStatusHandler()) { + phone_hub_manager_->GetEcheConnectionStatusHandler() + ->CheckConnectionStatusForUi(); + } + } + phone_hub_manager_->GetBrowserTabsModelProvider()->TriggerRefresh(); RecordStatusOnBubbleOpened();
diff --git a/ash/system/phonehub/phone_hub_ui_controller_unittest.cc b/ash/system/phonehub/phone_hub_ui_controller_unittest.cc index b8eb5e5..a02926e 100644 --- a/ash/system/phonehub/phone_hub_ui_controller_unittest.cc +++ b/ash/system/phonehub/phone_hub_ui_controller_unittest.cc
@@ -3,7 +3,9 @@ // found in the LICENSE file. #include "ash/system/phonehub/phone_hub_ui_controller.h" +#include <memory> +#include "ash/constants/ash_features.h" #include "ash/shell.h" #include "ash/system/eche/eche_tray.h" #include "ash/system/phonehub/phone_hub_view_ids.h" @@ -45,7 +47,8 @@ // AshTestBase: void SetUp() override { - feature_list_.InitWithFeatures({features::kEcheSWA}, {}); + feature_list_.InitWithFeatures( + {features::kEcheSWA, features::kEcheNetworkConnectionState}, {}); AshTestBase::SetUp(); @@ -91,6 +94,11 @@ phone_status_model); } + void SetEcheConnectionStatusHandler( + eche_app::EcheConnectionStatusHandler* handler) { + phone_hub_manager_.set_eche_connection_hander(handler); + } + std::unique_ptr<PhoneHubContentView> OpenBubbleAndCreateView() { controller_->HandleBubbleOpened(); return controller_->CreateContentView(/*delegate=*/nullptr); @@ -281,6 +289,21 @@ phone_hub_metrics::Screen::kPhoneConnected, 1); } +TEST_F(PhoneHubUiControllerTest, PhoneConnected_HasConnectionHandler) { + base::HistogramTester histograms; + SetPhoneStatusModel(phonehub::CreateFakePhoneStatusModel()); + SetEcheConnectionStatusHandler( + std::make_unique<eche_app::EcheConnectionStatusHandler>().get()); + GetFeatureStatusProvider()->SetStatus(FeatureStatus::kEnabledAndConnected); + EXPECT_EQ(PhoneHubUiController::UiState::kPhoneConnected, + controller_->ui_state()); + + auto content_view = OpenBubbleAndCreateView(); + EXPECT_EQ(kPhoneConnectedView, content_view->GetID()); + histograms.ExpectBucketCount(kScreenOnOpenedMetric, + phone_hub_metrics::Screen::kPhoneConnected, 1); +} + TEST_F(PhoneHubUiControllerTest, UnavailableScreenLocked) { base::HistogramTester histograms; GetFeatureStatusProvider()->SetStatus(FeatureStatus::kLockOrSuspended);
diff --git a/ash/system/power/power_prefs.cc b/ash/system/power/power_prefs.cc index 2b6d33e2..16e1a2a4 100644 --- a/ash/system/power/power_prefs.cc +++ b/ash/system/power/power_prefs.cc
@@ -129,7 +129,7 @@ double GetAdaptiveChargingMinProbability() { // An AdaptiveCharging decision is considered to be reliable if the inference // score is higher than this number. - constexpr double kDefaultAdaptiveChargingMinProbability = 0.2; + constexpr double kDefaultAdaptiveChargingMinProbability = 0.35; return base::GetFieldTrialParamByFeatureAsDouble( ash::features::kAdaptiveCharging, "adaptive_charging_min_probability",
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc index be06b7a..117ebc7 100644 --- a/ash/system/privacy_hub/microphone_privacy_switch_controller.cc +++ b/ash/system/privacy_hub/microphone_privacy_switch_controller.cc
@@ -191,10 +191,8 @@ if (visible) { if (mic_muted_by_mute_switch_) { - if (!features::IsPrivacyIndicatorsEnabled()) { - privacy_hub_notification_controller->ShowHardwareSwitchNotification( - SensorDisabledNotificationDelegate::Sensor::kMicrophone); - } + privacy_hub_notification_controller->ShowHardwareSwitchNotification( + SensorDisabledNotificationDelegate::Sensor::kMicrophone); } else { privacy_hub_notification_controller->ShowSoftwareSwitchNotification( SensorDisabledNotificationDelegate::Sensor::kMicrophone); @@ -218,10 +216,8 @@ Shell::Get()->system_notification_controller()->privacy_hub(); if (mic_muted_by_mute_switch_) { - if (!features::IsPrivacyIndicatorsEnabled()) { - privacy_hub_notification_controller->UpdateHardwareSwitchNotification( - SensorDisabledNotificationDelegate::Sensor::kMicrophone); - } + privacy_hub_notification_controller->UpdateHardwareSwitchNotification( + SensorDisabledNotificationDelegate::Sensor::kMicrophone); } else { privacy_hub_notification_controller->UpdateSoftwareSwitchNotification( SensorDisabledNotificationDelegate::Sensor::kMicrophone);
diff --git a/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc b/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc index af5d061..244612d 100644 --- a/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc +++ b/ash/system/privacy_hub/microphone_privacy_switch_controller_unittest.cc
@@ -490,7 +490,7 @@ EXPECT_FALSE(GetSWSwitchNotification()); message_center::Notification* notification = GetHWSwitchNotification(); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(notification); return; } @@ -518,7 +518,7 @@ message_center::Notification* notification = GetHWSwitchNotification(); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(notification); return; } @@ -552,13 +552,6 @@ IDS_MICROPHONE_MUTED_NOTIFICATION_ACTION_BUTTON), notification->buttons()[0].title); } - - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { - // The rest of the test tests interaction between the hardware and software - // notifications, and the hardware notification is not shown when Video - // Conference or Privacy Indicator is enabled. - return; - } // Toggle microphone mute switch and verify that new notification appears // with a "Learn more" button. SetMicrophoneMuteSwitchState(/*muted=*/true); @@ -566,7 +559,7 @@ EXPECT_FALSE(GetSWSwitchNotification()); notification = GetHWSwitchNotification(); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(notification); } else { ASSERT_TRUE(notification); @@ -596,23 +589,20 @@ EXPECT_TRUE(GetSWSwitchPopupNotification()); } - // Toggle microphone mute hardware switch and verify that toggling mute switch - // creates new hardware switch pop up notification and the software switch + // Toggle microphone mute switch and verify that toggling mute switch creates + // new hardware switch pop up notification and the software switch // notification is removed. SetMicrophoneMuteSwitchState(/*muted=*/true); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(GetHWSwitchNotification()); EXPECT_FALSE(GetHWSwitchNotification()); - // The rest of the test is not relevant as the hardware switch notification - // is not shown. - return; + } else { + // Verify the notification popup is shown. + EXPECT_TRUE(GetHWSwitchNotification()); + EXPECT_TRUE(GetHWSwitchNotification()); } - // Verify the notification popup is shown. - EXPECT_TRUE(GetHWSwitchNotification()); - EXPECT_TRUE(GetHWSwitchNotification()); - // The software switch notification is instantly hidden. EXPECT_FALSE(GetSWSwitchNotification()); @@ -631,7 +621,7 @@ SetMicrophoneMuteSwitchState(/*muted=*/true); LaunchApp(u"junior"); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(GetHWSwitchNotification()); EXPECT_FALSE(GetHWSwitchNotification()); } else { @@ -663,7 +653,7 @@ // Add another audio input stream, and verify the notification popup shows. LaunchApp(u"junior1"); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(GetHWSwitchNotification()); EXPECT_FALSE(GetHWSwitchPopupNotification()); } else { @@ -680,7 +670,7 @@ CloseApp(u"junior1"); // Verify that notification popup is not reshown. - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(GetHWSwitchNotification()); } else { EXPECT_TRUE(GetHWSwitchNotification()); @@ -689,7 +679,7 @@ // Adding another stream shows a popup again. LaunchApp(u"rose"); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(GetHWSwitchNotification()); EXPECT_FALSE(GetHWSwitchPopupNotification()); } else { @@ -783,7 +773,7 @@ // Toggle the hw switch. SetMicrophoneMuteSwitchState(/*muted=*/true); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(GetHWSwitchNotification()); EXPECT_FALSE(GetHWSwitchPopupNotification()); } else { @@ -862,7 +852,7 @@ LaunchApp(app1); notification_ptr = GetHWSwitchNotification(); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(notification_ptr); } else { ASSERT_TRUE(notification_ptr); @@ -877,7 +867,7 @@ CloseApp(app2); notification_ptr = GetHWSwitchNotification(); - if (IsVideoConferenceEnabled() || IsPrivacyIndicatorsEnabled()) { + if (IsVideoConferenceEnabled()) { EXPECT_FALSE(notification_ptr); } else { ASSERT_TRUE(notification_ptr);
diff --git a/ash/system/privacy_hub/privacy_hub_notification_controller.cc b/ash/system/privacy_hub/privacy_hub_notification_controller.cc index 9e79543..aef3655 100644 --- a/ash/system/privacy_hub/privacy_hub_notification_controller.cc +++ b/ash/system/privacy_hub/privacy_hub_notification_controller.cc
@@ -172,11 +172,6 @@ void PrivacyHubNotificationController::ShowHardwareSwitchNotification( const Sensor sensor) { - if (features::IsPrivacyIndicatorsEnabled() || - features::IsVideoConferenceEnabled()) { - return; - } - switch (sensor) { case Sensor::kMicrophone: { RemoveSensor(sensor); @@ -213,10 +208,6 @@ void PrivacyHubNotificationController::UpdateHardwareSwitchNotification( const Sensor sensor) { - if (features::IsPrivacyIndicatorsEnabled() || - features::IsVideoConferenceEnabled()) { - return; - } switch (sensor) { case Sensor::kMicrophone: { microphone_hw_switch_notification_->Update();
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc index b015ada..9caf0ce 100644 --- a/ash/system/status_area_widget.cc +++ b/ash/system/status_area_widget.cc
@@ -15,6 +15,7 @@ #include "ash/projector/projector_annotation_tray.h" #include "ash/public/cpp/shelf_config.h" #include "ash/session/session_controller_impl.h" +#include "ash/shelf/drag_handle.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shelf/shelf_widget.h" @@ -276,6 +277,21 @@ status_area_widget_delegate_->OnStatusAreaCollapseStateChanged( collapse_state_); + + bool overlap = + shelf_->shelf_widget()->GetDragHandle()->GetBoundsInScreen().Intersects( + status_area_widget_delegate_->GetBoundsInScreen()); + + if (collapse_state_ == CollapseState::EXPANDED && overlap) { + // Hide the drag handle if the status_area_widget_delegate_ overlaps + // expected drag handle bounds. Otherwise show the drag handle. + shelf_->shelf_widget()->GetDragHandle()->HideDragHandleNudge( + contextual_tooltip::DismissNudgeReason::kOther, + /*animate*/ false); + shelf_->shelf_widget()->GetDragHandle()->SetVisible(false); + } else if (collapse_state_ == CollapseState::COLLAPSED) { + shelf_->shelf_widget()->GetDragHandle()->SetVisible(true); + } } void StatusAreaWidget::LogVisiblePodCountMetric() {
diff --git a/ash/user_education/user_education_controller_unittest.cc b/ash/user_education/user_education_controller_unittest.cc index f27dffec..2d89d85c 100644 --- a/ash/user_education/user_education_controller_unittest.cc +++ b/ash/user_education/user_education_controller_unittest.cc
@@ -16,35 +16,55 @@ // UserEducationControllerTest ------------------------------------------------- // Base class for tests of the `UserEducationController` parameterized by -// whether the Welcome Tour feature is enabled. +// whether user education features are enabled. class UserEducationControllerTest : public AshTestBase, - public testing::WithParamInterface</*welcome_tour_enabled=*/bool> { + public testing::WithParamInterface< + std::tuple</*capture_mode_tour_enabled=*/bool, + /*holding_space_tour_enabled=*/bool, + /*welcome_tour_enabled=*/bool>> { public: UserEducationControllerTest() { std::vector<base::test::FeatureRef> enabled_features; std::vector<base::test::FeatureRef> disabled_features; + (IsCaptureModeTourEnabled() ? enabled_features : disabled_features) + .emplace_back(features::kCaptureModeTour); + (IsHoldingSpaceTourEnabled() ? enabled_features : disabled_features) + .emplace_back(features::kHoldingSpaceTour); (IsWelcomeTourEnabled() ? enabled_features : disabled_features) .emplace_back(features::kWelcomeTour); scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); } + // Returns whether the Capture Mode Tour is enabled given test + // parameterization. + bool IsCaptureModeTourEnabled() const { return std::get<0>(GetParam()); } + + // Returns whether the Holding Space Tour is enabled given test + // parameterization. + bool IsHoldingSpaceTourEnabled() const { return std::get<1>(GetParam()); } + // Returns whether the Welcome Tour is enabled given test parameterization. - bool IsWelcomeTourEnabled() const { return GetParam(); } + bool IsWelcomeTourEnabled() const { return std::get<2>(GetParam()); } private: base::test::ScopedFeatureList scoped_feature_list_; }; -INSTANTIATE_TEST_SUITE_P(All, - UserEducationControllerTest, - /*welcome_tour_enabled=*/testing::Bool()); +INSTANTIATE_TEST_SUITE_P( + All, + UserEducationControllerTest, + testing::Combine(/*capture_mode_tour_enabled=*/testing::Bool(), + /*holding_space_tour_enabled=*/testing::Bool(), + /*welcome_tour_enabled=*/testing::Bool())); // Tests ----------------------------------------------------------------------- -// Verifies that the controller exists if and only if Welcome Tour is enabled. +// Verifies that the controller exists iff user education features are enabled. TEST_P(UserEducationControllerTest, Exists) { - EXPECT_EQ(!!UserEducationController::Get(), IsWelcomeTourEnabled()); + EXPECT_EQ(!!UserEducationController::Get(), IsCaptureModeTourEnabled() || + IsHoldingSpaceTourEnabled() || + IsWelcomeTourEnabled()); } } // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn index e3518fb..b49d877 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -4552,7 +4552,6 @@ "test/android/javatests/src/org/chromium/base/test/util/Manual.java", "test/android/javatests/src/org/chromium/base/test/util/Matchers.java", "test/android/javatests/src/org/chromium/base/test/util/MaxAndroidSdkLevel.java", - "test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java", "test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java", "test/android/javatests/src/org/chromium/base/test/util/PackageManagerWrapper.java", "test/android/javatests/src/org/chromium/base/test/util/PayloadCallbackHelper.java",
diff --git a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java index 605046e..7c9071d 100644 --- a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java +++ b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
@@ -13,7 +13,6 @@ import org.chromium.base.library_loader.LibraryLoader; import org.chromium.base.test.BaseJUnit4ClassRunner; -import org.chromium.base.test.util.MetricsUtils.HistogramDelta; /** * Tests for the Java API for recording UMA histograms. @@ -193,4 +192,35 @@ Assert.assertEquals(0, oneCount.getDelta()); Assert.assertEquals(1, twoCount.getDelta()); } + + /** + * Helper class that snapshots the given bucket of the given UMA histogram on its creation, + * allowing to inspect the number of samples recorded during its lifetime. + */ + private static class HistogramDelta { + private final String mHistogram; + private final int mSampleValue; + + private final int mInitialCount; + + private int get() { + return RecordHistogram.getHistogramValueCountForTesting(mHistogram, mSampleValue); + } + + /** + * Snapshots the given bucket of the given histogram. + * @param histogram name of the histogram to snapshot + * @param sampleValue the bucket that contains this value will be snapshot + */ + public HistogramDelta(String histogram, int sampleValue) { + mHistogram = histogram; + mSampleValue = sampleValue; + mInitialCount = get(); + } + + /** Returns the number of samples of the snapshot bucket recorded since creation */ + public int getDelta() { + return get() - mInitialCount; + } + } }
diff --git a/base/base_switches.cc b/base/base_switches.cc index 88613473..8e0a485 100644 --- a/base/base_switches.cc +++ b/base/base_switches.cc
@@ -132,10 +132,7 @@ const char kDisableUsbKeyboardDetect[] = "disable-usb-keyboard-detect"; #endif -// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch -// of lacros-chrome is complete. -#if BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \ - !BUILDFLAG(IS_CHROMEOS_LACROS) +#if BUILDFLAG(IS_LINUX) // The /dev/shm partition is too small in certain VM environments, causing // Chrome to fail or crash (see http://crbug.com/715363). Use this flag to // work-around this issue (a temporary directory will always be used to create
diff --git a/base/base_switches.h b/base/base_switches.h index 4f5dd6b..cead11f 100644 --- a/base/base_switches.h +++ b/base/base_switches.h
@@ -41,10 +41,7 @@ extern const char kDisableUsbKeyboardDetect[]; #endif -// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch -// of lacros-chrome is complete. -#if BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \ - !BUILDFLAG(IS_CHROMEOS_LACROS) +#if BUILDFLAG(IS_LINUX) extern const char kDisableDevShmUsage[]; #endif
diff --git a/base/task/task_features.cc b/base/task/task_features.cc index dad6e0ae..b5861fe 100644 --- a/base/task/task_features.cc +++ b/base/task/task_features.cc
@@ -39,10 +39,6 @@ "RemoveCanceledTasksInTaskQueue2", base::FEATURE_ENABLED_BY_DEFAULT); -BASE_FEATURE(kAlwaysAbandonScheduledTask, - "AlwaysAbandonScheduledTask", - base::FEATURE_ENABLED_BY_DEFAULT); - BASE_FEATURE(kDelayFirstWorkerWake, "DelayFirstWorkerWake", base::FEATURE_DISABLED_BY_DEFAULT);
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java deleted file mode 100644 index 8283ccf7..0000000 --- a/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java +++ /dev/null
@@ -1,47 +0,0 @@ -// Copyright 2014 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.base.test.util; - -import org.chromium.base.metrics.RecordHistogram; - -/** - * Helpers for testing UMA metrics. - */ -public class MetricsUtils { - /** - * - * Helper class that snapshots the given bucket of the given UMA histogram on its creation, - * allowing to inspect the number of samples recorded during its lifetime. - * - * @deprecated Use {@link HistogramWatcher} instead. - */ - @Deprecated - public static class HistogramDelta { - private final String mHistogram; - private final int mSampleValue; - - private final int mInitialCount; - - private int get() { - return RecordHistogram.getHistogramValueCountForTesting(mHistogram, mSampleValue); - } - - /** - * Snapshots the given bucket of the given histogram. - * @param histogram name of the histogram to snapshot - * @param sampleValue the bucket that contains this value will be snapshot - */ - public HistogramDelta(String histogram, int sampleValue) { - mHistogram = histogram; - mSampleValue = sampleValue; - mInitialCount = get(); - } - - /** Returns the number of samples of the snapshot bucket recorded since creation */ - public int getDelta() { - return get() - mInitialCount; - } - } -}
diff --git a/base/timer/timer.cc b/base/timer/timer.cc index 8f00af2..c7d1bf3 100644 --- a/base/timer/timer.cc +++ b/base/timer/timer.cc
@@ -21,29 +21,6 @@ namespace base { namespace internal { -namespace { - -// Cache of the state of the kAlwaysAbandonScheduledTask feature. This avoids -// the need to constantly query its enabled state through -// FeatureList::IsEnabled(). -bool g_is_always_abandon_scheduled_task_enabled = true; - -} // namespace - -// static -void TimerBase::InitializeFeatures() { - // Since kAlwaysAbandonScheduledTask is not constexpr (forbidden for - // Features), it cannot be used to initialize - // |g_is_always_abandon_scheduled_task_enabled| at compile time. At least - // DCHECK that its initial value matches the default value of the feature - // here. - DCHECK_EQ( - g_is_always_abandon_scheduled_task_enabled, - kAlwaysAbandonScheduledTask.default_state == FEATURE_ENABLED_BY_DEFAULT); - g_is_always_abandon_scheduled_task_enabled = - FeatureList::IsEnabled(kAlwaysAbandonScheduledTask); -} - TimerBase::TimerBase(const Location& posted_from) : posted_from_(posted_from) { // It is safe for the timer to be created on a different thread/sequence than // the one from which the timer APIs are called. The first call to the @@ -59,19 +36,6 @@ bool TimerBase::IsRunning() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - // When the `kAlwaysAbandonScheduledTask` feature is enabled, checking - // `delayed_task_handle_.IsValid()` is sufficient to determine if the - // timer is running. When the feature is disabled, the delayed task - // is not abandoned when the timer is stopped and the handle remains - // valid, so it's necessary to also check `is_running_` (set to false - // from `Stop()`). - // - // TODO(crbug.com/1262205): Remove the `is_running_` check once the - // "AlwaysAbandonScheduledTask" feature is launched. - if (!is_running_) - return false; - return delayed_task_handle_.IsValid(); } @@ -89,7 +53,6 @@ void TimerBase::Stop() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - is_running_ = false; AbandonScheduledTask(); OnStop(); @@ -133,17 +96,7 @@ } void DelayTimerBase::AbandonAndStop() { - // Note: Stop() is more or less re-implemented here because it cannot be - // called without rebinding the |sequence_checker_| to the current sequence - // after the call to AbandonScheduledTask(). - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - is_running_ = false; - - AbandonScheduledTask(); - - OnStop(); - // No more member accesses here: |this| could be deleted at this point. + Stop(); } void DelayTimerBase::Reset() { @@ -151,49 +104,14 @@ EnsureNonNullUserTask(); - if (!g_is_always_abandon_scheduled_task_enabled) { - // If there's no pending task, start one up and return. - if (!delayed_task_handle_.IsValid()) { - ScheduleNewTask(delay_); - return; - } - - // Set the new |desired_run_time_|. - if (delay_ > Microseconds(0)) - desired_run_time_ = Now() + delay_; - else - desired_run_time_ = TimeTicks(); - - // We can use the existing scheduled task if it arrives before the new - // |desired_run_time_|. - if (desired_run_time_ >= scheduled_run_time_) { - is_running_ = true; - return; - } - } - // We can't reuse the |scheduled_task_|, so abandon it and post a new one. AbandonScheduledTask(); ScheduleNewTask(delay_); } -// TODO(1262205): Merge with TimerBase::Stop() once the "always abandon -// scheduled task" feature is launched. -void DelayTimerBase::Stop() { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - is_running_ = false; - if (g_is_always_abandon_scheduled_task_enabled) - AbandonScheduledTask(); - - OnStop(); - // No more member accesses here: |this| could be deleted after Stop() call. -} - void DelayTimerBase::ScheduleNewTask(TimeDelta delay) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!delayed_task_handle_.IsValid()); - is_running_ = true; // Ignore negative deltas. // TODO(pmonette): Fix callers providing negative deltas and ban passing them. @@ -207,7 +125,7 @@ delayed_task_handle_ = GetTaskRunner()->PostCancelableDelayedTask( base::subtle::PostDelayedTaskPassKey(), posted_from_, timer_callback_, delay); - scheduled_run_time_ = desired_run_time_ = Now() + delay; + desired_run_time_ = Now() + delay; } TimeTicks DelayTimerBase::Now() const { @@ -219,24 +137,6 @@ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!delayed_task_handle_.IsValid()) << posted_from_.ToString(); - // The timer may have been stopped. - if (!is_running_) - return; - - // First check if we need to delay the task because of a new target time. - if (desired_run_time_ > scheduled_run_time_) { - // Now() can be expensive, so only call it if we know the user has changed - // the |desired_run_time_|. - TimeTicks now = Now(); - // Task runner may have called us late anyway, so only post a continuation - // task if the |desired_run_time_| is in the future. - if (desired_run_time_ > now) { - // Post a new task to span the remaining time. - ScheduleNewTask(desired_run_time_ - now); - return; - } - } - RunUserTask(); // No more member accesses here: |this| could be deleted at this point. } @@ -308,6 +208,7 @@ } void RepeatingTimer::OnStop() {} + void RepeatingTimer::RunUserTask() { // Make a local copy of the task to run in case the task destroy the timer // instance. @@ -346,6 +247,7 @@ } void RetainingOneShotTimer::OnStop() {} + void RetainingOneShotTimer::RunUserTask() { // Make a local copy of the task to run in case the task destroys the timer // instance. @@ -382,7 +284,6 @@ void DeadlineTimer::ScheduleNewTask(TimeTicks deadline, subtle::DelayPolicy delay_policy) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - is_running_ = true; if (!timer_callback_) { timer_callback_ = @@ -446,7 +347,6 @@ void MetronomeTimer::ScheduleNewTask() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - is_running_ = true; // The next wake up is scheduled at the next aligned time which is at least // `interval_ / 2` after now. `interval_ / 2` is added to avoid playing
diff --git a/base/timer/timer.h b/base/timer/timer.h index 10fc7c9..afe8302a 100644 --- a/base/timer/timer.h +++ b/base/timer/timer.h
@@ -88,10 +88,6 @@ // This class wraps logic shared by all timers. class BASE_EXPORT TimerBase { public: - // Initializes the state of all the timer features. Must be invoked after - // FeatureList initialization and while Chrome is still single-threaded. - static void InitializeFeatures(); - TimerBase(const TimerBase&) = delete; TimerBase& operator=(const TimerBase&) = delete; @@ -141,10 +137,6 @@ // Location in user code. Location posted_from_ GUARDED_BY_CONTEXT(sequence_checker_); - // If true, |user_task_| is scheduled to run sometime in the future. - // TODO(1262205): Remove once kAlwaysAbandonScheduledTask is gone. - bool is_running_ GUARDED_BY_CONTEXT(sequence_checker_) = false; - // The handle to the posted delayed task. DelayedTaskHandle delayed_task_handle_ GUARDED_BY_CONTEXT(sequence_checker_); @@ -170,12 +162,8 @@ // the timer is not running, this will start it by posting a task. virtual void Reset(); - void Stop() override; - - // Abandons the scheduled task (if any) and stops the timer (if running). Use - // this instead of Stop() only if the timer will need to be used or destroyed - // on another sequence. - // TODO(1262205): Remove once kAlwaysAbandonScheduledTask is gone. + // DEPRECATED. Call Stop() instead. + // TODO(1262205): Remove this method and all callers. void AbandonAndStop(); TimeTicks desired_run_time() const { @@ -199,8 +187,7 @@ virtual void RunUserTask() = 0; // Schedules |OnScheduledTaskInvoked()| to run on the current sequence with - // the given |delay|. |scheduled_run_time_| and |desired_run_time_| are reset - // to Now() + delay. + // the given |delay|. |desired_run_time_| is reset to Now() + delay. void ScheduleNewTask(TimeDelta delay); void StartInternal(const Location& posted_from, TimeDelta delay); @@ -220,17 +207,9 @@ // Delay requested by user. TimeDelta delay_ GUARDED_BY_CONTEXT(sequence_checker_); - // The time at which the scheduled task is expected to fire. This time can be - // null if the task must be run immediately. - TimeTicks scheduled_run_time_ GUARDED_BY_CONTEXT(sequence_checker_); - // The desired run time of |user_task_|. The user may update this at any time, - // even if their previous request has not run yet. If |desired_run_time_| is - // greater than |scheduled_run_time_|, a continuation task will be posted to - // wait for the remaining time. This allows us to reuse the pending task so as - // not to flood the delayed queues with orphaned tasks when the user code - // excessively Stops and Starts the timer. This time can be a "zero" TimeTicks - // if the task must be run immediately. + // even if their previous request has not run yet. This time can be a "zero" + // TimeTicks if the task must be run immediately. TimeTicks desired_run_time_ GUARDED_BY_CONTEXT(sequence_checker_); // The tick clock used to calculate the run time for scheduled tasks.
diff --git a/build/fuchsia/ffx_session.py b/build/fuchsia/ffx_session.py deleted file mode 100755 index c002842..0000000 --- a/build/fuchsia/ffx_session.py +++ /dev/null
@@ -1,619 +0,0 @@ -#!/usr/bin/env vpython3 -# 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. -"""A helper tool for running Fuchsia's `ffx`. -""" - -# Enable use of the print() built-in function. - -import argparse -import contextlib -import errno -import json -import logging -import os -import re -import shutil -import subprocess -import sys -import tempfile -import time - -import log_manager - -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), - 'test'))) - -from common import SDK_ROOT -from compatible_utils import get_host_arch, parse_host_port - -RUN_SUMMARY_SCHEMA = \ - 'https://fuchsia.dev/schema/ffx_test/run_summary-8d1dd964.json' - - -def get_ffx_path(): - """Returns the full path to `ffx`.""" - return os.path.join(SDK_ROOT, 'tools', get_host_arch(), 'ffx') - - -def format_host_port(host, port): - """Formats a host name or IP address and port number into a host:port string. - """ - # Wrap `host` in brackets if it looks like an IPv6 address - return ('[%s]:%d' if ':' in host else '%s:%d') % (host, port) - - -class FfxRunner(): - """A helper to run `ffx` commands.""" - - def __init__(self, log_manager): - self._ffx = get_ffx_path() - self._log_manager = log_manager - - def _get_daemon_status(self): - """Determines daemon status via `ffx daemon socket`. - - Returns: - dict of status of the socket. Status will have a key Running or - NotRunning to indicate if the daemon is running. - """ - status = json.loads( - self.run_ffx(['--machine', 'json', 'daemon', 'socket'], - check=True, - suppress_repair=True)) - if status.get('pid') and status.get('pid', {}).get('status', {}): - return status['pid']['status'] - return {'NotRunning': True} - - def _is_daemon_running(self): - return 'Running' in self._get_daemon_status() - - def _wait_for_daemon(self, start=True, timeout_seconds=100): - """Waits for daemon to reach desired state in a polling loop. - - Sleeps for 5s between polls. - - Args: - start: bool. Indicates to wait for daemon to start up. If False, - indicates waiting for daemon to die. - timeout_seconds: int. Number of seconds to wait for the daemon to reach - the desired status. - Raises: - TimeoutError: if the daemon does not reach the desired state in time. - """ - wanted_status = 'start' if start else 'stop' - sleep_period_seconds = 5 - attempts = int(timeout_seconds / sleep_period_seconds) - for i in range(attempts): - if self._is_daemon_running() == start: - return - if i != attempts: - logging.info('Waiting for daemon to %s...', wanted_status) - time.sleep(sleep_period_seconds) - - raise TimeoutError(f'Daemon did not {wanted_status} in time.') - - def _run_repair_command(self, output): - """Scans `output` for a self-repair command to run and, if found, runs it. - - If logging is enabled, `ffx` is asked to emit its own logs to the log - directory. - - Returns: - True if a repair command was found and ran successfully. False otherwise. - """ - # Check for a string along the lines of: - # "Run `ffx doctor --restart-daemon` for further diagnostics." - match = re.search('`ffx ([^`]+)`', output) - if not match or len(match.groups()) != 1: - return False # No repair command found. - args = match.groups()[0].split() - # Tell ffx to include the configuration file without prompting in case - # logging is enabled. - with self.scoped_config('doctor.record_config', 'true'): - # If the repair command is `ffx doctor` and logging is enabled, add the - # options to emit ffx logs to the logging directory. - if len(args) and args[0] == 'doctor' and \ - self._log_manager.IsLoggingEnabled(): - args.extend( - ('--record', '--output-dir', self._log_manager.GetLogDirectory())) - try: - self.run_ffx(args, suppress_repair=True) - self._wait_for_daemon(start=True) - except subprocess.CalledProcessError as cpe: - return False # Repair failed. - return True # Repair succeeded. - - def run_ffx(self, args, check=True, suppress_repair=False): - """Runs `ffx` with the given arguments, waiting for it to exit. - - If `ffx` exits with a non-zero exit code, the output is scanned for a - recommended repair command (e.g., "Run `ffx doctor --restart-daemon` for - further diagnostics."). If such a command is found, it is run and then the - original command is retried. This behavior can be suppressed via the - `suppress_repair` argument. - - Args: - args: A sequence of arguments to ffx. - check: If True, CalledProcessError is raised if ffx returns a non-zero - exit code. - suppress_repair: If True, do not attempt to find and run a repair command. - Returns: - A string containing combined stdout and stderr. - Raises: - CalledProcessError if `check` is true. - """ - log_file = self._log_manager.Open('ffx_log') \ - if self._log_manager.IsLoggingEnabled() else None - command = [self._ffx] - command.extend(args) - logging.debug(command) - if log_file: - print(command, file=log_file) - repair_succeeded = False - try: - # TODO(grt): Switch to subprocess.run() with encoding='utf-8' when p3 is - # supported. - process = subprocess.Popen(command, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout_data, stderr_data = process.communicate() - stdout_data = stdout_data.decode('utf-8') - stderr_data = stderr_data.decode('utf-8') - if check and process.returncode != 0: - # TODO(grt): Pass stdout and stderr as two args when p2 support is no - # longer needed. - raise subprocess.CalledProcessError( - process.returncode, command, '\n'.join((stdout_data, stderr_data))) - except subprocess.CalledProcessError as cpe: - if log_file: - log_file.write('Process exited with code %d. Output: %s\n' % - (cpe.returncode, cpe.output.strip())) - # Let the exception fly unless a repair command is found and succeeds. - if suppress_repair or not self._run_repair_command(cpe.output): - raise - repair_succeeded = True - - # If the original command failed but a repair command was found and - # succeeded, try one more time with the original command. - if repair_succeeded: - return self.run_ffx(args, check, suppress_repair=True) - - stripped_stdout = stdout_data.strip() - stripped_stderr = stderr_data.strip() - if log_file: - if process.returncode != 0 or stripped_stderr: - log_file.write('Process exited with code %d.' % process.returncode) - if stripped_stderr: - log_file.write(' Stderr:\n%s\n' % stripped_stderr) - if stripped_stdout: - log_file.write(' Stdout:\n%s\n' % stripped_stdout) - if not stripped_stderr and not stripped_stdout: - log_file.write('\n') - elif stripped_stdout: - log_file.write('%s\n' % stripped_stdout) - logging.debug( - 'ffx command returned %d with %s%s', process.returncode, - ('output "%s"' % stripped_stdout if stripped_stdout else 'no output'), - (' and error "%s".' % stripped_stderr if stripped_stderr else '.')) - return stdout_data - - def open_ffx(self, args): - """Runs `ffx` with some arguments. - Args: - args: A sequence of arguments to ffx. - Returns: - A subprocess.Popen object. - """ - log_file = self._log_manager.Open('ffx_log') \ - if self._log_manager.IsLoggingEnabled() else None - command = [self._ffx] - command.extend(args) - logging.debug(command) - if log_file: - print(command, file=log_file) - try: - # TODO(grt): Add encoding='utf-8' when p3 is supported. - return subprocess.Popen(command, - stdin=open(os.devnull, 'r'), - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - except: - logging.exception('Failed to open ffx') - if log_file: - print('Exception caught while opening ffx: %s' % str(sys.exc_info[1])) - raise - - @contextlib.contextmanager - def scoped_config(self, name, value): - """Temporarily overrides `ffx` configuration. - - Args: - name: The name of the property to set. - value: The value to associate with `name`. - - Returns: - Yields nothing. Restores the previous value upon exit. - """ - assert value is not None - # Cache the current value. - old_value = None - try: - old_value = self.run_ffx(['config', 'get', name]).strip() - except subprocess.CalledProcessError as cpe: - if cpe.returncode != 2: - raise # The failure was for something other than value not found. - # Set the new value if it is different. - if value != old_value: - self.run_ffx(['config', 'set', name, value]) - try: - yield None - finally: - if value == old_value: - return # There is no need to restore an old value. - # Clear the new value. - self.run_ffx(['config', 'remove', name]) - if old_value is None: - return - # Did removing the new value restore the original value on account of it - # either being the default or being set in a different scope? - if (self.run_ffx(['config', 'get', name], - check=False).strip() == old_value): - return - # If not, explicitly set the original value. - self.run_ffx(['config', 'set', name, old_value]) - - def list_targets(self): - """Returns the (possibly empty) list of targets known to ffx. - - Returns: - The list of targets parsed from the JSON output of `ffx target list`. - """ - json_targets = self.run_ffx(['target', 'list', '-f', 'json']) - if not json_targets: - return [] - try: - return json.loads(json_targets) - except ValueError: - # TODO(grt): Change to json.JSONDecodeError once p3 is supported. - return [] - - def list_active_targets(self): - """Gets the list of targets and filters down to the targets that are active. - - Returns: - An iterator over active FfxTargets. - """ - targets = [ - FfxTarget.from_target_list_json(self, json_target) - for json_target in self.list_targets() - ] - return filter(lambda target: target.get_ssh_address(), targets) - - def remove_stale_targets(self, address): - """Removes any targets from ffx that are listening at a given address. - - Args: - address: A string representation of the target's ip address. - """ - for target in self.list_targets(): - if target['rcs_state'] == 'N' and address in target['addresses']: - self.run_ffx(['target', 'remove', address]) - - @contextlib.contextmanager - def scoped_target_context(self, address, port): - """Temporarily adds a new target. - - Args: - address: The IP address at which the target is listening. - port: The port number on which the target is listening. - - Yields: - An FfxTarget for interacting with the target. - """ - target_id = format_host_port(address, port) - # -n allows `target add` to skip waiting for the device to come up, - # as this can take longer than the default wait period. - self.run_ffx(['target', 'add', '-n', target_id]) - try: - yield FfxTarget.from_address(self, address, port) - finally: - self.run_ffx(['target', 'remove', target_id], check=False) - - def get_node_name(self, address, port): - """Returns the node name for a target given its SSH address. - - Args: - address: The address at which the target's SSH daemon is listening. - port: The port number on which the daemon is listening. - - Returns: - The target's node name. - - Raises: - Exception: If the target cannot be found. - """ - for target in self.list_targets(): - if target['nodename'] and address in target['addresses']: - ssh_address = FfxTarget.from_target_list_json(target).get_ssh_address() - if ssh_address and ssh_address[1] == port: - return target['nodename'] - raise Exception('Failed to determine node name for target at %s' % - format_host_port(address, port)) - - def daemon_stop(self): - """Stops the ffx daemon.""" - self.run_ffx(['daemon', 'stop'], check=False, suppress_repair=True) - # Daemon should stop at this point. - self._wait_for_daemon(start=False) - - -class FfxTarget(): - """A helper to run `ffx` commands for a specific target.""" - - @classmethod - def from_address(cls, ffx_runner, address, port=None): - """Args: - ffx_runner: The runner to use to run ffx. - address: The target's address. - port: The target's port, defaults to None in which case it will target - the first device at the specified address - """ - return cls(ffx_runner, format_host_port(address, port) if port else address) - - @classmethod - def from_node_name(cls, ffx_runner, node_name): - """Args: - ffx_runner: The runner to use to run ffx. - node_name: The target's node name. - """ - return cls(ffx_runner, node_name) - - @classmethod - def from_target_list_json(cls, ffx_runner, json_target): - """Args: - ffx_runner: The runner to use to run ffx. - json_target: the json dict as returned from `ffx list targets` - """ - # Targets seen via `fx serve-remote` frequently have no name, so fall back - # to using the first address. - if json_target['nodename'].startswith('<unknown'): - return cls.from_address(ffx_runner, json_target['addresses'][0]) - return cls.from_node_name(ffx_runner, json_target['nodename']) - - def __init__(self, ffx_runner, target_id): - """Args: - ffx_runner: The runner to use to run ffx. - target_id: The target's node name or addr:port string. - """ - self._ffx_runner = ffx_runner - self._target_id = target_id - self._target_args = ('--target', target_id) - - def format_runner_options(self): - """Returns a string holding options suitable for use with the runner scripts - to run tests on this target.""" - try: - # First try extracting host:port from the target_id. - return '-d --host %s --port %d' % parse_host_port(self._target_args[1]) - except ValueError: - # Must be a simple node name. - pass - return '-d --node-name %s' % self._target_args[1] - - def wait(self, timeout=None): - """Waits for ffx to establish a connection with the target. - - Args: - timeout: The number of seconds to wait (60 if not specified). - """ - command = list(self._target_args) - command.extend(('target', 'wait')) - if timeout is not None: - command.extend(('-t', '%d' % int(timeout))) - self._ffx_runner.run_ffx(command) - - def get_ssh_address(self): - """Returns the host and port of the target's SSH address - - Returns: - A tuple of a host address string and a port number integer, - or None if there was an exception - """ - command = list(self._target_args) - command.extend(('target', 'get-ssh-address')) - try: - return parse_host_port(self._ffx_runner.run_ffx(command)) - except: - return None - - def open_ffx(self, command): - """Runs `ffx` for the target with some arguments. - Args: - command: A command and its arguments to run on the target. - Returns: - A subprocess.Popen object. - """ - args = list(self._target_args) - args.extend(command) - return self._ffx_runner.open_ffx(args) - - def __str__(self): - return self._target_id - - def __repr__(self): - return self._target_id - - -# TODO(grt): Derive from contextlib.AbstractContextManager when p3 is supported. -class FfxSession(): - """A context manager that manages a session for running a test via `ffx`. - - Upon entry, an instance of this class configures `ffx` to retrieve files - generated by a test and prepares a directory to hold these files either in a - LogManager's log directory or in tmp. On exit, any previous configuration of - `ffx` is restored and the temporary directory, if used, is deleted. - - The prepared directory is used when invoking `ffx test run`. - """ - - def __init__(self, log_manager): - """Args: - log_manager: A Target's LogManager. - """ - self._log_manager = log_manager - self._ffx = FfxRunner(log_manager) - self._own_output_dir = False - self._output_dir = None - self._run_summary = None - self._suite_summary = None - self._custom_artifact_directory = None - self._debug_data_directory = None - - def __enter__(self): - if self._log_manager.IsLoggingEnabled(): - # Use a subdir of the configured log directory to hold test outputs. - self._output_dir = os.path.join(self._log_manager.GetLogDirectory(), - 'test_outputs') - # TODO(grt): Use exist_ok=True when p3 is supported. - try: - os.makedirs(self._output_dir) - except OSError as ose: - if ose.errno != errno.EEXIST: - raise - else: - # Create a temporary directory to hold test outputs. - # TODO(grt): Switch to tempfile.TemporaryDirectory when p3 is supported. - self._own_output_dir = True - self._output_dir = tempfile.mkdtemp(prefix='ffx_session_tmp_') - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - # Restore the previous test.output_path setting. - if self._own_output_dir: - # Clean up the temporary output directory. - shutil.rmtree(self._output_dir, ignore_errors=True) - self._own_output_dir = False - self._output_dir = None - return False - - def get_output_dir(self): - """Returns the temporary output directory for the session.""" - assert self._output_dir, 'FfxSession must be used in a context' - return self._output_dir - - def test_run(self, ffx_target, component_uri, package_args): - """Runs a test on a target. - Args: - ffx_target: The target on which to run the test. - component_uri: The test component URI. - package_args: Arguments to the test package. - Returns: - A subprocess.Popen object. - """ - command = [ - '--config', 'test.experimental_structured_output=false', 'test', 'run', - '--output-directory', self._output_dir, component_uri, '--' - ] - command.extend(package_args) - return ffx_target.open_ffx(command) - - def _parse_test_outputs(self): - """Parses the output files generated by the test runner. - - The instance's `_custom_artifact_directory` member is set to the directory - holding output files emitted by the test. - - This function is idempotent, and performs no work if it has already been - called. - """ - if self._run_summary: - return # The files have already been parsed. - - # Parse the main run_summary.json file. - run_summary_path = os.path.join(self._output_dir, 'run_summary.json') - try: - with open(run_summary_path) as run_summary_file: - self._run_summary = json.load(run_summary_file) - except IOError as io_error: - logging.error('Error reading run summary file: %s', str(io_error)) - return - except ValueError as value_error: - logging.error('Error parsing run summary file %s: %s', run_summary_path, - str(value_error)) - return - - assert self._run_summary['schema_id'] == RUN_SUMMARY_SCHEMA, \ - 'Unsupported version found in %s' % run_summary_path - - run_artifact_dir = self._run_summary.get('data', {})['artifact_dir'] - for artifact_path, artifact in self._run_summary.get( - 'data', {})['artifacts'].items(): - if artifact['artifact_type'] == 'DEBUG': - self._debug_data_directory = os.path.join(self._output_dir, - run_artifact_dir, - artifact_path) - break - - # There should be precisely one suite for the test that ran. - self._suite_summary = self._run_summary.get('data', {}).get('suites', - [{}])[0] - - # Get the top-level directory holding all artifacts for this suite. - artifact_dir = self._suite_summary.get('artifact_dir') - if not artifact_dir: - logging.error('Failed to find suite\'s artifact_dir in %s', - run_summary_path) - return - - # Get the path corresponding to artifacts - for artifact_path, artifact in self._suite_summary['artifacts'].items(): - if artifact['artifact_type'] == 'CUSTOM': - self._custom_artifact_directory = os.path.join(self._output_dir, - artifact_dir, - artifact_path) - break - - def get_custom_artifact_directory(self): - """Returns the full path to the directory holding custom artifacts emitted - by the test, or None if the path cannot be determined. - """ - self._parse_test_outputs() - return self._custom_artifact_directory - - def get_debug_data_directory(self): - """Returns the full path to the directory holding custom artifacts emitted - by the test, or None if the path cannot be determined. - """ - self._parse_test_outputs() - return self._debug_data_directory - - -def make_arg_parser(): - parser = argparse.ArgumentParser( - description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) - parser.add_argument('--logs-dir', help='Directory to write logs to.') - parser.add_argument('--verbose', - '-v', - action='store_true', - default=False, - help='Enable debug logging') - return parser - - -def main(args): - args = make_arg_parser().parse_args(args) - - logging.basicConfig(format='%(asctime)s:%(levelname)s:%(name)s:%(message)s', - level=logging.DEBUG if args.verbose else logging.INFO) - log_mgr = log_manager.LogManager(args.logs_dir) - - with FfxSession(log_mgr) as ffx_session: - logging.info(ffx_session.get_output_dir()) - - return 0 - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:]))
diff --git a/build/fuchsia/log_manager.py b/build/fuchsia/log_manager.py deleted file mode 100644 index f2d142a..0000000 --- a/build/fuchsia/log_manager.py +++ /dev/null
@@ -1,53 +0,0 @@ -# Copyright 2020 The Chromium Authors -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -"""Creates and manages log file objects. - -Provides an object that handles opening and closing file streams for -logging purposes. -""" - -import os - - -class LogManager(object): - def __init__(self, logs_dir): - - # A dictionary with the log file path as the key and a file stream as value. - self._logs = {} - - self._logs_dir = logs_dir - if self._logs_dir: - if not os.path.isdir(self._logs_dir): - os.makedirs(self._logs_dir) - - def IsLoggingEnabled(self): - return self._logs_dir is not None - - def GetLogDirectory(self): - """Get the directory logs are placed into.""" - - return self._logs_dir - - def Open(self, log_file_name): - """Open a file stream with log_file_name in the logs directory.""" - - parent_dir = self.GetLogDirectory() - if not parent_dir: - return open(os.devnull, 'w') - log_file_path = os.path.join(parent_dir, log_file_name) - if log_file_path in self._logs: - return self._logs[log_file_path] - log_file = open(log_file_path, 'w', buffering=1) - self._logs[log_file_path] = log_file - return log_file - - def Stop(self): - for log in self._logs.values(): - log.close() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - self.Stop()
diff --git a/build/fuchsia/test/coveragetest.py b/build/fuchsia/test/coveragetest.py index 7dfd3d9..3a82e53c 100755 --- a/build/fuchsia/test/coveragetest.py +++ b/build/fuchsia/test/coveragetest.py
@@ -19,7 +19,7 @@ ] # The files will be tested without coverage requirements. -TESTED_FILES = ['common.py'] +TESTED_FILES = ['common.py', 'ffx_emulator.py'] def main():
diff --git a/build/fuchsia/test/ffx_emulator.py b/build/fuchsia/test/ffx_emulator.py new file mode 100644 index 0000000..9e0a3318 --- /dev/null +++ b/build/fuchsia/test/ffx_emulator.py
@@ -0,0 +1,144 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""Provide helpers for running Fuchsia's `ffx emu`.""" + +import argparse +import ast +import logging +import os +import json +import random +import subprocess + +from contextlib import AbstractContextManager + +from common import check_ssh_config_file, run_ffx_command, \ + SDK_ROOT +from compatible_utils import get_host_arch +from ffx_integration import ScopedFfxConfig + +_EMU_COMMAND_RETRIES = 3 + + +class FfxEmulator(AbstractContextManager): + """A helper for managing emulators.""" + def __init__(self, args: argparse.Namespace) -> None: + if args.product_bundle: + self._product_bundle = args.product_bundle + else: + target_cpu = get_host_arch() + self._product_bundle = f'terminal.qemu-{target_cpu}' + + self._enable_graphics = args.enable_graphics + self._hardware_gpu = args.hardware_gpu + self._logs_dir = args.logs_dir + self._with_network = args.with_network + self._node_name = 'fuchsia-emulator-' + str(random.randint(1, 9999)) + + # Set the download path parallel to Fuchsia SDK directory + # permanently so that scripts can always find the product bundles. + run_ffx_command(('config', 'set', 'pbms.storage.path', + os.path.join(SDK_ROOT, os.pardir, 'images'))) + + override_file = os.path.join(os.path.dirname(__file__), os.pardir, + 'sdk_override.txt') + self._scoped_pb_metadata = None + if os.path.exists(override_file): + with open(override_file) as f: + pb_metadata = f.read().split('\n') + pb_metadata.append('{sdk.root}/*.json') + self._scoped_pb_metadata = ScopedFfxConfig( + 'pbms.metadata', json.dumps((pb_metadata))) + + def __enter__(self) -> str: + """Start the emulator. + + Returns: + The node name of the emulator. + """ + + logging.info('Starting emulator %s', self._node_name) + if self._scoped_pb_metadata: + self._scoped_pb_metadata.__enter__() + check_ssh_config_file() + emu_command = [ + 'emu', 'start', self._product_bundle, '--name', self._node_name + ] + if not self._enable_graphics: + emu_command.append('-H') + if self._hardware_gpu: + emu_command.append('--gpu') + if self._logs_dir: + emu_command.extend( + ('-l', os.path.join(self._logs_dir, 'emulator_log'))) + if self._with_network: + emu_command.extend(('--net', 'tap')) + + # TODO(https://crbug.com/1336776): remove when ffx has native support + # for starting emulator on arm64 host. + if get_host_arch() == 'arm64': + + arm64_qemu_dir = os.path.join(SDK_ROOT, 'tools', 'arm64', + 'qemu_internal') + + # The arm64 emulator binaries are downloaded separately, so add + # a symlink to the expected location inside the SDK. + if not os.path.isdir(arm64_qemu_dir): + os.symlink( + os.path.join(SDK_ROOT, '..', '..', 'qemu-linux-arm64'), + arm64_qemu_dir) + + # Add the arm64 emulator binaries to the SDK's manifest.json file. + sdk_manifest = os.path.join(SDK_ROOT, 'meta', 'manifest.json') + with open(sdk_manifest, 'r+') as f: + data = json.load(f) + for part in data['parts']: + if part['meta'] == 'tools/x64/qemu_internal-meta.json': + part['meta'] = 'tools/arm64/qemu_internal-meta.json' + break + f.seek(0) + json.dump(data, f) + f.truncate() + + # Generate a meta file for the arm64 emulator binaries using its + # x64 counterpart. + qemu_arm64_meta_file = os.path.join(SDK_ROOT, 'tools', 'arm64', + 'qemu_internal-meta.json') + qemu_x64_meta_file = os.path.join(SDK_ROOT, 'tools', 'x64', + 'qemu_internal-meta.json') + with open(qemu_x64_meta_file) as f: + data = str(json.load(f)) + qemu_arm64_meta = data.replace(r'tools/x64', 'tools/arm64') + with open(qemu_arm64_meta_file, "w+") as f: + json.dump(ast.literal_eval(qemu_arm64_meta), f) + emu_command.extend(['--engine', 'qemu']) + + with ScopedFfxConfig('emu.start.timeout', '90'): + for _ in range(_EMU_COMMAND_RETRIES): + + # If the ffx daemon fails to establish a connection with + # the emulator after 85 seconds, that means the emulator + # failed to be brought up and a retry is needed. + # TODO(fxb/103540): Remove retry when start up issue is fixed. + try: + run_ffx_command(emu_command, timeout=85) + break + except (subprocess.TimeoutExpired, + subprocess.CalledProcessError): + run_ffx_command(('emu', 'stop')) + return self._node_name + + def __exit__(self, exc_type, exc_value, traceback) -> bool: + """Shutdown the emulator.""" + + logging.info('Stopping the emulator %s', self._node_name) + # The emulator might have shut down unexpectedly, so this command + # might fail. + run_ffx_command(('emu', 'stop', self._node_name), check=False) + + if self._scoped_pb_metadata: + self._scoped_pb_metadata.__exit__(exc_type, exc_value, traceback) + + # Do not suppress exceptions. + return False
diff --git a/build/fuchsia/test/ffx_emulator_unittests.py b/build/fuchsia/test/ffx_emulator_unittests.py new file mode 100755 index 0000000..81f1f61 --- /dev/null +++ b/build/fuchsia/test/ffx_emulator_unittests.py
@@ -0,0 +1,32 @@ +#!/usr/bin/env vpython3 +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""File for testing ffx_emulator.py.""" + +import argparse +import unittest + +from ffx_emulator import FfxEmulator + + +class FfxEmulatorTest(unittest.TestCase): + """Unittests for ffx_emulator.py""" + def test_use_random_node_name(self) -> None: + """FfxEmulator should not use a fixed node name.""" + # Allowing the test case to access FfxEmulator._node_name directly. + # pylint: disable=protected-access + self.assertNotEqual( + FfxEmulator( + argparse.Namespace( + **{ + 'product_bundle': None, + 'enable_graphics': False, + 'hardware_gpu': False, + 'logs_dir': '.', + 'with_network': False + }))._node_name, 'fuchsia-everlasting-emulator') + + +if __name__ == '__main__': + unittest.main()
diff --git a/build/fuchsia/test/ffx_integration.py b/build/fuchsia/test/ffx_integration.py index 2c0960e..507479b 100644 --- a/build/fuchsia/test/ffx_integration.py +++ b/build/fuchsia/test/ffx_integration.py
@@ -3,11 +3,9 @@ # found in the LICENSE file. """Provide helpers for running Fuchsia's `ffx`.""" -import ast import logging import os import json -import random import subprocess import sys import tempfile @@ -15,9 +13,7 @@ from contextlib import AbstractContextManager from typing import IO, Iterable, List, Optional -from common import check_ssh_config_file, run_ffx_command, \ - run_continuous_ffx_command, SDK_ROOT -from compatible_utils import get_host_arch +from common import run_continuous_ffx_command, run_ffx_command, SDK_ROOT _EMU_COMMAND_RETRIES = 3 RUN_SUMMARY_SCHEMA = \ @@ -89,134 +85,6 @@ run_ffx_command(('target', 'echo'), target_id) -class FfxEmulator(AbstractContextManager): - """A helper for managing emulators.""" - - def __init__(self, - enable_graphics: bool, - hardware_gpu: bool, - product_bundle: Optional[str], - with_network: bool, - logs_dir: Optional[str] = None) -> None: - if product_bundle: - self._product_bundle = product_bundle - else: - target_cpu = get_host_arch() - self._product_bundle = f'terminal.qemu-{target_cpu}' - - self._enable_graphics = enable_graphics - self._hardware_gpu = hardware_gpu - self._logs_dir = logs_dir - self._with_network = with_network - node_name_suffix = random.randint(1, 9999) - self._node_name = f'fuchsia-emulator-{node_name_suffix}' - - # Set the download path parallel to Fuchsia SDK directory - # permanently so that scripts can always find the product bundles. - run_ffx_command(('config', 'set', 'pbms.storage.path', - os.path.join(SDK_ROOT, os.pardir, 'images'))) - - override_file = os.path.join(os.path.dirname(__file__), os.pardir, - 'sdk_override.txt') - self._scoped_pb_metadata = None - if os.path.exists(override_file): - with open(override_file) as f: - pb_metadata = f.read().split('\n') - pb_metadata.append('{sdk.root}/*.json') - self._scoped_pb_metadata = ScopedFfxConfig( - 'pbms.metadata', json.dumps((pb_metadata))) - - def __enter__(self) -> str: - """Start the emulator. - - Returns: - The node name of the emulator. - """ - - if self._scoped_pb_metadata: - self._scoped_pb_metadata.__enter__() - check_ssh_config_file() - emu_command = [ - 'emu', 'start', self._product_bundle, '--name', self._node_name - ] - if not self._enable_graphics: - emu_command.append('-H') - if self._hardware_gpu: - emu_command.append('--gpu') - if self._logs_dir: - emu_command.extend( - ('-l', os.path.join(self._logs_dir, 'emulator_log'))) - if self._with_network: - emu_command.extend(('--net', 'tap')) - - # TODO(https://crbug.com/1336776): remove when ffx has native support - # for starting emulator on arm64 host. - if get_host_arch() == 'arm64': - - arm64_qemu_dir = os.path.join(SDK_ROOT, 'tools', 'arm64', - 'qemu_internal') - - # The arm64 emulator binaries are downloaded separately, so add - # a symlink to the expected location inside the SDK. - if not os.path.isdir(arm64_qemu_dir): - os.symlink( - os.path.join(SDK_ROOT, '..', '..', 'qemu-linux-arm64'), - arm64_qemu_dir) - - # Add the arm64 emulator binaries to the SDK's manifest.json file. - sdk_manifest = os.path.join(SDK_ROOT, 'meta', 'manifest.json') - with open(sdk_manifest, 'r+') as f: - data = json.load(f) - for part in data['parts']: - if part['meta'] == 'tools/x64/qemu_internal-meta.json': - part['meta'] = 'tools/arm64/qemu_internal-meta.json' - break - f.seek(0) - json.dump(data, f) - f.truncate() - - # Generate a meta file for the arm64 emulator binaries using its - # x64 counterpart. - qemu_arm64_meta_file = os.path.join(SDK_ROOT, 'tools', 'arm64', - 'qemu_internal-meta.json') - qemu_x64_meta_file = os.path.join(SDK_ROOT, 'tools', 'x64', - 'qemu_internal-meta.json') - with open(qemu_x64_meta_file) as f: - data = str(json.load(f)) - qemu_arm64_meta = data.replace(r'tools/x64', 'tools/arm64') - with open(qemu_arm64_meta_file, "w+") as f: - json.dump(ast.literal_eval(qemu_arm64_meta), f) - emu_command.extend(['--engine', 'qemu']) - - with ScopedFfxConfig('emu.start.timeout', '90'): - for _ in range(_EMU_COMMAND_RETRIES): - - # If the ffx daemon fails to establish a connection with - # the emulator after 85 seconds, that means the emulator - # failed to be brought up and a retry is needed. - # TODO(fxb/103540): Remove retry when start up issue is fixed. - try: - run_ffx_command(emu_command, timeout=85) - break - except (subprocess.TimeoutExpired, - subprocess.CalledProcessError): - run_ffx_command(('emu', 'stop')) - return self._node_name - - def __exit__(self, exc_type, exc_value, traceback) -> bool: - """Shutdown the emulator.""" - - # The emulator might have shut down unexpectedly, so this command - # might fail. - run_ffx_command(('emu', 'stop', self._node_name), check=False) - - if self._scoped_pb_metadata: - self._scoped_pb_metadata.__exit__(exc_type, exc_value, traceback) - - # Do not suppress exceptions. - return False - - class FfxTestRunner(AbstractContextManager): """A context manager that manages a session for running a test via `ffx`.
diff --git a/build/fuchsia/test/start_emulator.py b/build/fuchsia/test/start_emulator.py index 2b3416ab..897ea79 100755 --- a/build/fuchsia/test/start_emulator.py +++ b/build/fuchsia/test/start_emulator.py
@@ -10,7 +10,7 @@ import time from common import catch_sigterm, register_log_args -from ffx_integration import FfxEmulator +from ffx_emulator import FfxEmulator def register_emulator_args(parser: argparse.ArgumentParser, @@ -47,8 +47,7 @@ def create_emulator_from_args(args: argparse.Namespace) -> FfxEmulator: """Helper method for initializing an FfxEmulator class with parsed arguments.""" - return FfxEmulator(args.enable_graphics, args.hardware_gpu, - args.product_bundle, args.with_network, args.logs_dir) + return FfxEmulator(args) def main():
diff --git a/build/fuchsia/update_product_bundles.py b/build/fuchsia/update_product_bundles.py index 988d5974..a889d59 100755 --- a/build/fuchsia/update_product_bundles.py +++ b/build/fuchsia/update_product_bundles.py
@@ -15,13 +15,12 @@ import sys from contextlib import ExitStack -import ffx_session -import log_manager sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), 'test'))) import common +import ffx_integration _PRODUCT_BUNDLES = [ 'core.x64-dfv2', @@ -77,27 +76,23 @@ return json.load(f)['id'] -def remove_repositories(repo_names_to_remove, ffx_runner): +def remove_repositories(repo_names_to_remove): """Removes given repos from repo list. Repo MUST be present in list to succeed. Args: repo_names_to_remove: List of repo names (as strings) to remove. - ffx_runner: ffx_session.FfxRunner instance to run the command. """ for repo_name in repo_names_to_remove: - ffx_runner.run_ffx(('repository', 'remove', repo_name), check=True) + common.run_ffx_command(('repository', 'remove', repo_name), check=True) -def get_repositories(ffx_runner): +def get_repositories(): """Lists repositories that are available on disk. Also prunes repositories that are listed, but do not have an actual packages directory. - Args: - ffx_runner: An FfxRunner instance. - Returns: List of dictionaries containing info about the repositories. They have the following structure: @@ -111,7 +106,9 @@ """ repos = json.loads( - ffx_runner.run_ffx(('--machine', 'json', 'repository', 'list')).strip()) + common.run_ffx_command(('--machine', 'json', 'repository', 'list'), + check=True, + capture_output=True).stdout.strip()) to_prune = set() sdk_root_abspath = os.path.abspath(os.path.dirname(common.SDK_ROOT)) for repo in repos: @@ -126,26 +123,23 @@ repos = [repo for repo in repos if repo['name'] not in to_prune] - remove_repositories(to_prune, ffx_runner) + remove_repositories(to_prune) return repos -def update_repositories_list(ffx_runner): +def update_repositories_list(): """Used to prune stale repositories.""" - get_repositories(ffx_runner) + get_repositories() -def remove_product_bundle(product_bundle, ffx_runner): +def remove_product_bundle(product_bundle): """Removes product-bundle given.""" - ffx_runner.run_ffx(('product-bundle', 'remove', '-f', product_bundle)) + common.run_ffx_command(('product-bundle', 'remove', '-f', product_bundle)) -def get_product_bundle_urls(ffx_runner): +def get_product_bundle_urls(): """Retrieves URLs of available product-bundles. - Args: - ffx_runner: An FfxRunner instance. - Returns: List of dictionaries of structure, indicating whether the product-bundle has been downloaded. @@ -155,8 +149,8 @@ } """ # TODO(fxb/115328): Replaces with JSON API when available. - bundles = ffx_runner.run_ffx(('product-bundle', 'list'), check=True) - + bundles = common.run_ffx_command(('product-bundle', 'list'), + capture_output=True).stdout.strip() urls = [ line.strip() for line in bundles.splitlines() if 'gs://fuchsia' in line ] @@ -170,40 +164,34 @@ return structured_urls -def keep_product_bundles_by_sdk_version(sdk_version, ffx_runner): +def keep_product_bundles_by_sdk_version(sdk_version): """Prunes product bundles not containing the sdk_version given.""" - urls = get_product_bundle_urls(ffx_runner) + urls = get_product_bundle_urls() for url in urls: if url['downloaded'] and sdk_version not in url['url']: - remove_product_bundle(url['url'], ffx_runner) + remove_product_bundle(url['url']) -def get_product_bundles(ffx_runner): +def get_product_bundles(): """Lists all downloaded product-bundles for the given SDK. Cross-references the repositories with downloaded packages and the stated downloaded product-bundles to validate whether or not a product-bundle is present. Prunes invalid product-bundles with each call as well. - Args: - ffx_runner: An FfxRunner instance. - Returns: List of strings of product-bundle names downloaded and that FFX is aware of. """ downloaded_bundles = [] - for url in get_product_bundle_urls(ffx_runner): + for url in get_product_bundle_urls(): if url['downloaded']: # The product is separated by a # product = url['url'].split('#') downloaded_bundles.append(product[1]) - # For each downloaded bundle, need to verify whether ffx repository believes - # it exists. - to_prune_bundles_index = [] - repos = get_repositories(ffx_runner) + repos = get_repositories() # Some repo names do not match product-bundle names due to underscores. # Normalize them both. @@ -216,19 +204,19 @@ if name.replace('-', '_') in repo_names: return True - remove_product_bundle(name, ffx_runner) + remove_product_bundle(name) return False return list(filter(bundle_is_active, downloaded_bundles)) -def download_product_bundle(product_bundle, ffx_runner): +def download_product_bundle(product_bundle): """Download product bundles using the SDK.""" # This also updates the repository list, in case it is stale. - update_repositories_list(ffx_runner) + update_repositories_list() try: - ffx_runner.run_ffx( + common.run_ffx_command( ('product-bundle', 'get', product_bundle, '--force-repo')) except subprocess.CalledProcessError as cpe: logging.error('Product bundle download has failed. ' + @@ -236,22 +224,19 @@ raise -def get_current_signature(ffx_runner): +def get_current_signature(): """Determines the SDK version of the product-bundles associated with the SDK. Parses this information from the URLs of the product-bundle. - Args: - ffx_runner: An FfxRunner instance. - Returns: An SDK version string, or None if no product-bundle versions are downloaded. """ - product_bundles = get_product_bundles(ffx_runner) + product_bundles = get_product_bundles() if not product_bundles: logging.info('No product bundles - signature will default to None') return None - product_bundle_urls = get_product_bundle_urls(ffx_runner) + product_bundle_urls = get_product_bundle_urls() # Get the numbers, hope they're the same. signatures = set() @@ -299,11 +284,10 @@ 'found in the DEPS file.') with ExitStack() as stack: - ffx_runner = ffx_session.FfxRunner(log_manager.LogManager(None)) # Re-set the directory to which product bundles are downloaded so that # these bundles are located inside the Chromium codebase. - ffx_runner.run_ffx( + common.run_ffx_command( ('config', 'set', 'pbms.storage.path', common.IMAGES_ROOT)) logging.debug('Checking for override file') @@ -316,16 +300,17 @@ pb_metadata = f.read().strip().split('\n') pb_metadata.append('{sdk.root}/*.json') stack.enter_context( - ffx_runner.scoped_config('pbms.metadata', json.dumps((pb_metadata)))) + ffx_integration.ScopedFfxConfig('pbms.metadata', + json.dumps((pb_metadata)))) logging.debug('Applied overrides') logging.debug('Getting new SDK hash') new_sdk_hash = get_hash_from_sdk() - keep_product_bundles_by_sdk_version(new_sdk_hash, ffx_runner) + keep_product_bundles_by_sdk_version(new_sdk_hash) logging.debug('Checking for current signature') - curr_signature = get_current_signature(ffx_runner) + curr_signature = get_current_signature() - current_images = get_product_bundles(ffx_runner) + current_images = get_product_bundles() # If SDK versions match, remove the product bundles that are no longer # needed and download missing ones. @@ -335,34 +320,30 @@ for image in current_images: if image not in new_product_bundles: logging.debug('Removing no longer needed Fuchsia image %s' % image) - remove_product_bundle(image, ffx_runner) + remove_product_bundle(image) bundles_to_download = set(new_product_bundles) - \ set(current_images) for bundle in bundles_to_download: logging.debug('Downloading image: %s', image) - download_product_bundle(bundle, ffx_runner) + download_product_bundle(bundle) return 0 # If SDK versions do not match, remove all existing product bundles # and download the ones required. for pb in current_images: - remove_product_bundle(pb, ffx_runner) + remove_product_bundle(pb) logging.debug('Make clean images root') - curr_subdir = [] - if os.path.exists(common.IMAGES_ROOT): - curr_subdir = os.listdir(common.IMAGES_ROOT) common.make_clean_directory(common.IMAGES_ROOT) for pb in new_product_bundles: logging.debug('Downloading bundle: %s', pb) - download_product_bundle(pb, ffx_runner) + download_product_bundle(pb) - current_pb = get_product_bundles(ffx_runner) + current_pb = get_product_bundles() - diff = set(current_pb) - set(new_product_bundles) assert set(current_pb) == set(new_product_bundles), ( 'Failed to download expected set of product-bundles. ' f'Expected {new_product_bundles}, got {current_pb}')
diff --git a/build/fuchsia/update_product_bundles_test.py b/build/fuchsia/update_product_bundles_test.py index 0532a12..bb85454 100755 --- a/build/fuchsia/update_product_bundles_test.py +++ b/build/fuchsia/update_product_bundles_test.py
@@ -12,7 +12,6 @@ from parameterized import parameterized -import ffx_session import update_product_bundles sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), @@ -22,6 +21,14 @@ class TestUpdateProductBundles(unittest.TestCase): + def setUp(self): + ffx_mock = mock.Mock() + ffx_mock.returncode = 0 + self._ffx_patcher = mock.patch('common.run_ffx_command', + return_value=ffx_mock) + self._ffx_mock = self._ffx_patcher.start() + self.addCleanup(self._ffx_mock.stop) + def testConvertToProductBundleDefaultsUnknownImage(self): self.assertEqual( update_product_bundles.convert_to_product_bundle(['unknown-image']), @@ -62,13 +69,11 @@ self.assertRaises(RuntimeError, update_product_bundles.get_hash_from_sdk) - def testRemoveRepositoriesRunsRemoveOnGivenRepos(self): - ffx_runner = mock.create_autospec(ffx_session.FfxRunner, instance=True) + @mock.patch('common.run_ffx_command') + def testRemoveRepositoriesRunsRemoveOnGivenRepos(self, ffx_mock): + update_product_bundles.remove_repositories(['foo', 'bar', 'fizz', 'buzz']) - update_product_bundles.remove_repositories(['foo', 'bar', 'fizz', 'buzz'], - ffx_runner) - - ffx_runner.run_ffx.assert_has_calls([ + ffx_mock.assert_has_calls([ mock.call(('repository', 'remove', 'foo'), check=True), mock.call(('repository', 'remove', 'bar'), check=True), mock.call(('repository', 'remove', 'fizz'), check=True), @@ -80,8 +85,7 @@ def testGetRepositoriesPrunesReposThatDoNotExist(self, mock_abspath, mock_exists): with mock.patch('common.SDK_ROOT', 'some/path'): - ffx_runner = mock.create_autospec(ffx_session.FfxRunner, instance=True) - ffx_runner.run_ffx.return_value = json.dumps([{ + self._ffx_mock.return_value.stdout = json.dumps([{ "name": "terminal.qemu-x64", "spec": { "type": "pm", @@ -97,34 +101,30 @@ mock_exists.side_effect = [True, False] mock_abspath.side_effect = lambda x: x - self.assertEqual(update_product_bundles.get_repositories(ffx_runner), - [{ - "name": "terminal.qemu-x64", - "spec": { - "type": "pm", - "path": "some/path/that/exists" - } - }]) + self.assertEqual(update_product_bundles.get_repositories(), [{ + "name": "terminal.qemu-x64", + "spec": { + "type": "pm", + "path": "some/path/that/exists" + } + }]) - ffx_runner.run_ffx.assert_has_calls([ - mock.call(('--machine', 'json', 'repository', 'list')), + self._ffx_mock.assert_has_calls([ + mock.call(('--machine', 'json', 'repository', 'list'), + capture_output=True, + check=True), mock.call(('repository', 'remove', 'workstation-eng.chromebook-x64'), check=True) ]) def testRemoveProductBundle(self): - ffx_runner = mock.create_autospec(ffx_session.FfxRunner, instance=True) + update_product_bundles.remove_product_bundle('some-bundle-foo-bar') - update_product_bundles.remove_product_bundle('some-bundle-foo-bar', - ffx_runner) - - ffx_runner.run_ffx.assert_called_once_with( + self._ffx_mock.assert_called_once_with( ('product-bundle', 'remove', '-f', 'some-bundle-foo-bar')) def _InitFFXRunWithProductBundleList(self, sdk_version='10.20221114.2.1'): - ffx_runner = mock.create_autospec(ffx_session.FfxRunner, instance=True) - - ffx_runner.run_ffx.return_value = f""" + self._ffx_mock.return_value.stdout = f""" gs://fuchsia/{sdk_version}/bundles.json#workstation_eng.qemu-x64 gs://fuchsia/{sdk_version}/bundles.json#workstation_eng.chromebook-x64-dfv2 * gs://fuchsia/{sdk_version}/bundles.json#workstation_eng.chromebook-x64 @@ -134,11 +134,10 @@ *No need to fetch with `ffx product-bundle get ...`. """ - return ffx_runner def testGetProductBundleUrlsMarksDesiredAsDownloaded(self): - urls = update_product_bundles.get_product_bundle_urls( - self._InitFFXRunWithProductBundleList()) + self._InitFFXRunWithProductBundleList() + urls = update_product_bundles.get_product_bundle_urls() expected_urls = [{ 'url': 'gs://fuchsia/10.20221114.2.1/bundles.json#workstation_eng.qemu-x64', @@ -169,7 +168,7 @@ @mock.patch('update_product_bundles.get_repositories') def testGetProductBundlesExtractsProductBundlesFromURLs(self, mock_get_repos): - ffx_runner = self._InitFFXRunWithProductBundleList() + self._InitFFXRunWithProductBundleList() mock_get_repos.return_value = [{ 'name': 'workstation-eng.chromebook-x64' }, { @@ -179,7 +178,7 @@ }] self.assertEqual( - set(update_product_bundles.get_product_bundles(ffx_runner)), + set(update_product_bundles.get_product_bundles()), set([ 'workstation_eng.chromebook-x64', 'terminal.qemu-x64', @@ -189,7 +188,7 @@ @mock.patch('update_product_bundles.get_repositories') def testGetProductBundlesExtractsProductBundlesFromURLsFiltersMissingRepos( self, mock_get_repos): - ffx_runner = self._InitFFXRunWithProductBundleList() + self._InitFFXRunWithProductBundleList() # This will be missing two repos from the bundle list: # core and terminal.qemu-x64 @@ -201,34 +200,34 @@ 'name': 'terminal.qemu-arm64' }] - self.assertEqual(update_product_bundles.get_product_bundles(ffx_runner), + self.assertEqual(update_product_bundles.get_product_bundles(), ['workstation_eng.chromebook-x64']) - ffx_runner.run_ffx.assert_has_calls([ + self._ffx_mock.assert_has_calls([ mock.call(('product-bundle', 'remove', '-f', 'terminal.qemu-x64')), mock.call(('product-bundle', 'remove', '-f', 'core.x64-dfv2')), ], - any_order=True) + any_order=True) + @mock.patch('common.run_ffx_command') @mock.patch('update_product_bundles.update_repositories_list') def testDownloadProductBundleUpdatesRepoListBeforeCall( - self, mock_update_repo): - ffx_runner = mock.create_autospec(ffx_session.FfxRunner, instance=True) + self, mock_update_repo, mock_ffx): mock_sequence = mock.Mock() mock_sequence.attach_mock(mock_update_repo, 'update_repo_list') - mock_sequence.attach_mock(ffx_runner.run_ffx, 'run_ffx') + mock_sequence.attach_mock(mock_ffx, 'run_ffx_command') - update_product_bundles.download_product_bundle('some-bundle', ffx_runner) + update_product_bundles.download_product_bundle('some-bundle') mock_sequence.assert_has_calls([ - mock.call.update_repo_list(ffx_runner), - mock.call.run_ffx( + mock.call.update_repo_list(), + mock.call.run_ffx_command( ('product-bundle', 'get', 'some-bundle', '--force-repo')) ]) + @mock.patch('common.run_ffx_command') @mock.patch('update_product_bundles.get_product_bundle_urls') def testFilterProductBundleURLsRemovesBundlesWithoutGivenString( - self, mock_get_urls): - ffx_runner = mock.create_autospec(ffx_session.FfxRunner, instance=True) + self, mock_get_urls, mock_ffx): mock_get_urls.return_value = [ { 'url': 'some-url-has-buzz', @@ -243,27 +242,25 @@ 'downloaded': False, }, ] - update_product_bundles.keep_product_bundles_by_sdk_version( - 'buzz', ffx_runner) - ffx_runner.run_ffx.assert_called_once_with( + update_product_bundles.keep_product_bundles_by_sdk_version('buzz') + mock_ffx.assert_called_once_with( ('product-bundle', 'remove', '-f', 'some-url-to-remove-has-foo')) @mock.patch('update_product_bundles.get_repositories') def testGetCurrentSignatureReturnsNoneIfNoProductBundles( self, mock_get_repos): - ffx_runner = self._InitFFXRunWithProductBundleList() + self._InitFFXRunWithProductBundleList() # Forces no product-bundles mock_get_repos.return_value = [] # Mutes logs with self.assertLogs(): - self.assertIsNone( - update_product_bundles.get_current_signature(ffx_runner)) + self.assertIsNone(update_product_bundles.get_current_signature()) @mock.patch('update_product_bundles.get_repositories') def testGetCurrentSignatureParsesVersionCorrectly(self, mock_get_repos): - ffx_runner = self._InitFFXRunWithProductBundleList() + self._InitFFXRunWithProductBundleList() mock_get_repos.return_value = [{ 'name': 'workstation-eng.chromebook-x64' }, { @@ -271,20 +268,19 @@ }] self.assertEqual('10.20221114.2.1', - update_product_bundles.get_current_signature(ffx_runner)) + update_product_bundles.get_current_signature()) @mock.patch('update_product_bundles.get_repositories') def testGetCurrentSignatureParsesCustomArtifactsCorrectlys( self, mock_get_repos): - ffx_runner = self._InitFFXRunWithProductBundleList(sdk_version='51390009') + self._InitFFXRunWithProductBundleList(sdk_version='51390009') mock_get_repos.return_value = [{ 'name': 'workstation-eng.chromebook-x64' }, { 'name': 'terminal.qemu-x64' }] - self.assertEqual('51390009', - update_product_bundles.get_current_signature(ffx_runner)) + self.assertEqual('51390009', update_product_bundles.get_current_signature()) if __name__ == '__main__':
diff --git a/build/rust/tests/bindgen_test/src/lib.rs b/build/rust/tests/bindgen_test/src/lib.rs index dfd231d..c8672e0 100644 --- a/build/rust/tests/bindgen_test/src/lib.rs +++ b/build/rust/tests/bindgen_test/src/lib.rs
@@ -4,6 +4,7 @@ mod c_ffi { #![allow(dead_code)] + #![allow(non_snake_case)] #![allow(non_camel_case_types)] #![allow(non_upper_case_globals)] include!(env!("BINDGEN_RS_FILE"));
diff --git a/buildtools/deps_revisions.gni b/buildtools/deps_revisions.gni index 16d8d0c..9a37bd1 100644 --- a/buildtools/deps_revisions.gni +++ b/buildtools/deps_revisions.gni
@@ -5,5 +5,5 @@ declare_args() { # Used to cause full rebuilds on libc++ rolls. This should be kept in sync # with the libcxx_revision vars in //DEPS. - libcxx_revision = "af83f5d2fada265d8b5adc0a23a29e060907b3e7" + libcxx_revision = "e44019bfac2b2d3ebe1618628884f85c8600e322" }
diff --git a/cc/base/features.cc b/cc/base/features.cc index 583dff9..6c69172 100644 --- a/cc/base/features.cc +++ b/cc/base/features.cc
@@ -122,4 +122,7 @@ "MoreAggressiveSolidColorDetection", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kReducedFrameRateEstimation, + "kReducedFrameRateEstimation", + base::FEATURE_ENABLED_BY_DEFAULT); } // namespace features
diff --git a/cc/base/features.h b/cc/base/features.h index b853389..ed8f091 100644 --- a/cc/base/features.h +++ b/cc/base/features.h
@@ -109,6 +109,10 @@ // tiles. CC_BASE_EXPORT BASE_DECLARE_FEATURE(kMoreAggressiveSolidColorDetection); +// Allow CC FrameRateEstimater to reduce the frame rate to half of the default +// if the condition meets the requirement. +CC_BASE_EXPORT BASE_DECLARE_FEATURE(kReducedFrameRateEstimation); + } // namespace features #endif // CC_BASE_FEATURES_H_
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index 940ecc2..ab5e8fe 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc
@@ -157,7 +157,7 @@ draw_properties_.opacity, effect_node->HasRenderSurface() ? SkBlendMode::kSrcOver : effect_node->blend_mode, - GetSortingContextId()); + GetSortingContextId(), static_cast<uint32_t>(id())); state->is_fast_rounded_corner = draw_properties_.is_fast_rounded_corner; } @@ -194,7 +194,7 @@ draw_properties().opacity, effect_node->HasRenderSurface() ? SkBlendMode::kSrcOver : effect_node->blend_mode, - GetSortingContextId()); + GetSortingContextId(), static_cast<uint32_t>(id())); state->is_fast_rounded_corner = draw_properties().is_fast_rounded_corner; }
diff --git a/cc/raster/raster_source_unittest.cc b/cc/raster/raster_source_unittest.cc index ff6a47a..a6470f1 100644 --- a/cc/raster/raster_source_unittest.cc +++ b/cc/raster/raster_source_unittest.cc
@@ -17,9 +17,14 @@ #include "cc/test/test_skcanvas.h" #include "cc/tiles/software_image_decode_cache.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkPixelRef.h" #include "third_party/skia/include/core/SkRefCnt.h" +#include "third_party/skia/include/core/SkScalar.h" #include "third_party/skia/include/core/SkShader.h" +#include "third_party/skia/include/core/SkSurfaceProps.h" #include "ui/gfx/geometry/axis_transform2d.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size_conversions.h"
diff --git a/cc/trees/frame_rate_estimator.cc b/cc/trees/frame_rate_estimator.cc index 717fe9e..e47b7be6 100644 --- a/cc/trees/frame_rate_estimator.cc +++ b/cc/trees/frame_rate_estimator.cc
@@ -5,6 +5,7 @@ #include "cc/trees/frame_rate_estimator.h" #include "base/task/sequenced_task_runner.h" +#include "cc/base/features.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" namespace cc { @@ -24,8 +25,11 @@ FrameRateEstimator::~FrameRateEstimator() = default; void FrameRateEstimator::SetFrameEstimationEnabled(bool enabled) { - if (enabled == frame_rate_estimation_enabled_) + static const bool feature_allowed = + base::FeatureList::IsEnabled(features::kReducedFrameRateEstimation); + if (!feature_allowed || enabled == frame_rate_estimation_enabled_) { return; + } frame_rate_estimation_enabled_ = enabled; last_draw_time_ = base::TimeTicks();
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index a3bc012..89f3522 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2683,11 +2683,13 @@ frame->deadline_in_frames.value_or(0u), CurrentBeginFrameArgs().interval, frame->use_default_lower_bound_deadline); + static const bool feature_allowed = + base::FeatureList::IsEnabled(features::kReducedFrameRateEstimation); constexpr auto kFudgeDelta = base::Milliseconds(1); constexpr auto kTwiceOfDefaultInterval = viz::BeginFrameArgs::DefaultInterval() * 2; constexpr auto kMinDelta = kTwiceOfDefaultInterval - kFudgeDelta; - if (mutator_host_->MainThreadAnimationsCount() == 0 && + if (feature_allowed && mutator_host_->MainThreadAnimationsCount() == 0 && !mutator_host_->HasSmilAnimation() && mutator_host_->NeedsTickAnimations() && !frame_rate_estimator_.input_priority_mode() &&
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/AddToBookmarksToolbarButtonController.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/AddToBookmarksToolbarButtonController.java index 36b1474..066dedb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/AddToBookmarksToolbarButtonController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/AddToBookmarksToolbarButtonController.java
@@ -10,9 +10,13 @@ import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.supplier.Supplier; +import org.chromium.chrome.R; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.BaseButtonDataProvider; import org.chromium.chrome.browser.toolbar.adaptive.AdaptiveToolbarButtonVariant; +import org.chromium.chrome.browser.user_education.IPHCommandBuilder; +import org.chromium.components.feature_engagement.EventConstants; +import org.chromium.components.feature_engagement.FeatureConstants; import org.chromium.components.feature_engagement.Tracker; /** @@ -42,10 +46,23 @@ } @Override + protected IPHCommandBuilder getIphCommandBuilder(Tab tab) { + return new IPHCommandBuilder(tab.getContext().getResources(), + FeatureConstants + .ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_ADD_TO_BOOKMARKS_FEATURE, + /* stringId = */ R.string.adaptive_toolbar_button_add_to_bookmarks_iph, + /* accessibilityStringId = */ + R.string.adaptive_toolbar_button_add_to_bookmarks_iph); + } + + @Override public void onClick(View view) { if (!mTabBookmarkerSupplier.hasValue() || !mActiveTabSupplier.hasValue()) return; - // TODO: Record IPH event using mTrackerSupplier. + if (mTrackerSupplier.hasValue()) { + mTrackerSupplier.get().notifyEvent( + EventConstants.ADAPTIVE_TOOLBAR_CUSTOMIZATION_ADD_TO_BOOKMARKS_OPENED); + } RecordUserAction.record("MobileTopToolbarAddToBookmarksButton"); mTabBookmarkerSupplier.get().addOrEditBookmark(mActiveTabSupplier.get());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java index 51db9bf2..ab12868 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
@@ -65,6 +65,7 @@ private PageLoadMetricsObserverImpl mPageLoadMetricsObserver; private boolean mShouldTrackStartupMetrics; private boolean mFirstVisibleContentRecorded; + private boolean mFirstVisibleContent2Recorded; private boolean mVisibleContentRecorded; // Records whether the tracked first navigation commit was recorded pre-the app being in the @@ -175,6 +176,7 @@ RecordHistogram.recordBooleanHistogram( FIRST_PAINT_OCCURRED_PRE_FOREGROUND_HISTOGRAM, false); recordFirstVisibleContent(durationMs); + recordFirstVisibleContent2(durationMs); recordVisibleContent(durationMs); } @@ -252,6 +254,7 @@ mFirstCommitTimeMs = SystemClock.uptimeMillis() - mActivityStartTimeMs; RecordHistogram.recordMediumTimesHistogram( "Startup.Android.Cold.TimeToFirstNavigationCommit2.Tabbed", mFirstCommitTimeMs); + recordFirstVisibleContent2(mFirstCommitTimeMs); } mShouldTrackStartupMetrics = false; @@ -296,9 +299,11 @@ } /** - * Record the time to first visible content. This metric acts as the Clank cold start guardian - * metric. Reports the minimum value of - * Startup.Android.Cold.TimeToFirstNavigationCommit.Tabbed and + * Records the legacy version of the time to first visible content. + * + * This metric acts as the Clank cold start guardian metric. + * + * Reports the minimum value of Startup.Android.Cold.TimeToFirstNavigationCommit.Tabbed and * Browser.PaintPreview.TabbedPlayer.TimeToFirstBitmap. * * @param durationMs duration in millis. @@ -312,6 +317,24 @@ } /** + * Records the time to first visible content. + * + * This metric aims to become the new the Clank cold start guardian metric. + * + * Reports the minimum value of Startup.Android.Cold.TimeToFirstNavigationCommit2.Tabbed and + * Browser.PaintPreview.TabbedPlayer.TimeToFirstBitmap. + * + * @param durationMs duration in millis. + */ + private void recordFirstVisibleContent2(long durationMs) { + if (mFirstVisibleContent2Recorded) return; + + mFirstVisibleContent2Recorded = true; + RecordHistogram.recordMediumTimesHistogram( + "Startup.Android.Cold.TimeToFirstVisibleContent2", durationMs); + } + + /** * Record the first Visible Content time. * This metric reports the minimum value of * Startup.Android.Cold.TimeToFirstContentfulPaint.Tabbed and
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java index acabeafa..44ec01a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/RequestDesktopUtils.java
@@ -8,6 +8,7 @@ import android.content.res.Resources; import android.os.Build; import android.text.TextUtils; +import android.view.Display; import androidx.annotation.IntDef; import androidx.annotation.NonNull; @@ -51,6 +52,7 @@ import org.chromium.components.ukm.UkmRecorder; import org.chromium.content_public.browser.ContentFeatureList; import org.chromium.ui.display.DisplayAndroid; +import org.chromium.ui.display.DisplayAndroidManager; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType; @@ -95,6 +97,8 @@ "default_on_on_low_end_devices"; static final String PARAM_GLOBAL_SETTING_DEFAULT_ON_ON_X86_DEVICES = "default_on_on_x86_devices"; + static final String PARAM_GLOBAL_SETTING_DEFAULT_ON_ON_EXTERNAL_DISPLAY = + "default_on_on_external_display"; static final String PARAM_GLOBAL_SETTING_DEFAULT_ON_SMALLEST_SCREEN_WIDTH = "default_on_smallest_screen_width"; static final int DEFAULT_GLOBAL_SETTING_DEFAULT_ON_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP = 600; @@ -391,13 +395,12 @@ return false; } - // TODO(shuyng): Add downgrade path support for smallestScreenWidthDp or displaySizeInInches - // change. // If the smallest screen size in dp is below threshold, avoid default-enabling the setting. if (context.getResources().getConfiguration().smallestScreenWidthDp < ChromeFeatureList.getFieldTrialParamByFeatureAsInt(feature, PARAM_GLOBAL_SETTING_DEFAULT_ON_SMALLEST_SCREEN_WIDTH, DEFAULT_GLOBAL_SETTING_DEFAULT_ON_SMALLEST_SCREEN_WIDTH_THRESHOLD_DP)) { + // TODO(shuyng): Add downgrade path support for smallestScreenWidthDp change. return false; } @@ -416,12 +419,17 @@ } SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getInstance(); + boolean isOnExternalDisplay = + !ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean( + feature, PARAM_GLOBAL_SETTING_DEFAULT_ON_ON_EXTERNAL_DISPLAY, false) + && isOnExternalDisplay(context); double screenSizeThreshold = ChromeFeatureList.getFieldTrialParamByFeatureAsDouble(feature, PARAM_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES, DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES); - if (displaySizeInInches < screenSizeThreshold + if (displaySizeInInches < screenSizeThreshold && !isOnExternalDisplay && sharedPreferencesManager.contains( ChromePreferenceKeys.DEFAULT_ENABLE_DESKTOP_SITE_GLOBAL_SETTING_COHORT)) { + // TODO(shuyng): Add downgrade path support for displaySizeInInches change. silentlyReportingCrashes( context, displaySizeInInches, "Display size falls below threshold"); } @@ -432,7 +440,8 @@ SingleCategorySettingsConstants .USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY); - boolean inCohort = !previouslyUpdatedByUser && displaySizeInInches >= screenSizeThreshold; + boolean inCohort = !previouslyUpdatedByUser && displaySizeInInches >= screenSizeThreshold + && !isOnExternalDisplay; boolean wouldEnable = !previouslyDefaultEnabled && inCohort; if (wouldEnable) { // Store a SharedPreferences key to tag the device as qualified for the feature @@ -469,11 +478,11 @@ Configuration config = context.getResources().getConfiguration(); String logMessage = String.format(Locale.US, message + ", silently reporting crashes for debugging, displaySizeInInches: %.1f " - + "displayWidth: %d displayHeight: %d xdpi: %.1f ydpi: %.1f " - + "densityDpi: %d screenWidthDp: %d screenHeightDp: %d", + + "displayWidth: %d displayHeight: %d xdpi: %.1f ydpi: %.1f densityDpi: %d " + + "screenWidthDp: %d screenHeightDp: %d onExternalDisplay: %b", displaySizeInInches, display.getDisplayWidth(), display.getDisplayHeight(), display.getXdpi(), display.getYdpi(), config.densityDpi, config.screenWidthDp, - config.screenHeightDp); + config.screenHeightDp, isOnExternalDisplay(context)); SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getInstance(); String previousDisplaySpec = sharedPreferencesManager.readString( ChromePreferenceKeys.DESKTOP_SITE_GLOBAL_SETTING_DEFAULT_ON_COHORT_DISPLAY_SPEC, @@ -494,10 +503,10 @@ String displaySpec = String.format(Locale.US, "lastDisplaySizeInInches: %.1f lastDisplayWidth: %d lastDisplayHeight: %d " + "lastXdpi: %.1f lastYdpi: %.1f lastDensityDpi: %d " - + "lastScreenWidthDp: %d lastScreenHeightDp: %d", + + "lastScreenWidthDp: %d lastScreenHeightDp: %d lastOnExternalDisplay: %b", displaySizeInInches, display.getDisplayWidth(), display.getDisplayHeight(), display.getXdpi(), display.getYdpi(), config.densityDpi, config.screenWidthDp, - config.screenHeightDp); + config.screenHeightDp, isOnExternalDisplay(context)); sharedPreferencesManager.writeString( ChromePreferenceKeys.DESKTOP_SITE_GLOBAL_SETTING_DEFAULT_ON_COHORT_DISPLAY_SPEC, displaySpec); @@ -976,4 +985,9 @@ } return abiStrings[0].toLowerCase(Locale.ROOT).contains("arm"); } + + private static boolean isOnExternalDisplay(Context context) { + Display display = DisplayAndroidManager.getDefaultDisplayForContext(context); + return display.getDisplayId() != Display.DEFAULT_DISPLAY; + } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java index 7283193..3501d5e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -41,6 +41,7 @@ import org.chromium.chrome.browser.app.omnibox.ActionChipsDelegateImpl; import org.chromium.chrome.browser.app.tab_activity_glue.TabReparentingController; import org.chromium.chrome.browser.back_press.BackPressManager; +import org.chromium.chrome.browser.bookmarks.AddToBookmarksToolbarButtonController; import org.chromium.chrome.browser.bookmarks.BookmarkModel; import org.chromium.chrome.browser.bookmarks.TabBookmarker; import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; @@ -1135,6 +1136,11 @@ AppCompatResources.getDrawable(mActivity, R.drawable.new_tab_icon), mActivityLifecycleDispatcher, mTabCreatorManagerSupplier, mActivityTabProvider, trackerSupplier); + AddToBookmarksToolbarButtonController addToBookmarksToolbarButtonController = + new AddToBookmarksToolbarButtonController(mActivityTabProvider, + AppCompatResources.getDrawable(mActivity, R.drawable.btn_star), + mActivity.getString(R.string.menu_bookmark), mTabBookmarkerSupplier, + trackerSupplier); AdaptiveToolbarButtonController adaptiveToolbarButtonController = new AdaptiveToolbarButtonController(mActivity, new SettingsLauncherImpl(), mActivityLifecycleDispatcher, new AdaptiveButtonActionMenuCoordinator(), @@ -1146,6 +1152,9 @@ adaptiveToolbarButtonController.addButtonVariant( AdaptiveToolbarButtonVariant.VOICE, voiceToolbarButtonController); adaptiveToolbarButtonController.addButtonVariant( + AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS, + addToBookmarksToolbarButtonController); + adaptiveToolbarButtonController.addButtonVariant( AdaptiveToolbarButtonVariant.TRANSLATE, translateToolbarButtonController); adaptiveToolbarButtonController.addButtonVariant( AdaptiveToolbarButtonVariant.PRICE_TRACKING, priceTrackingButtonController);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java index b422e8f..8710b13 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java
@@ -58,6 +58,8 @@ "Startup.Android.Cold.TimeToFirstContentfulPaint"; private static final String FIRST_VISIBLE_CONTENT_HISTOGRAM = "Startup.Android.Cold.TimeToFirstVisibleContent"; + private static final String FIRST_VISIBLE_CONTENT_HISTOGRAM2 = + "Startup.Android.Cold.TimeToFirstVisibleContent2"; private static final String VISIBLE_CONTENT_HISTOGRAM = "Startup.Android.Cold.TimeToVisibleContent"; private static final String FIRST_COMMIT_OCCURRED_PRE_FOREGROUND_HISTOGRAM = @@ -178,6 +180,9 @@ Assert.assertEquals(firstCommitSamples, RecordHistogram.getHistogramTotalCountForTesting( FIRST_VISIBLE_CONTENT_HISTOGRAM)); + Assert.assertEquals(expectedCount, + RecordHistogram.getHistogramTotalCountForTesting( + FIRST_VISIBLE_CONTENT_HISTOGRAM2)); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/AddToBookmarksToolbarButtonControllerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/AddToBookmarksToolbarButtonControllerUnitTest.java index bc32a1b..2b1192a 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/AddToBookmarksToolbarButtonControllerUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/bookmarks/AddToBookmarksToolbarButtonControllerUnitTest.java
@@ -29,6 +29,7 @@ import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.toolbar.ButtonData; +import org.chromium.components.feature_engagement.EventConstants; import org.chromium.components.feature_engagement.Tracker; import org.chromium.content_public.browser.WebContents; @@ -97,6 +98,8 @@ Assert.assertEquals( 1, mActionTester.getActionCount("MobileTopToolbarAddToBookmarksButton")); + verify(mTracker).notifyEvent( + EventConstants.ADAPTIVE_TOOLBAR_CUSTOMIZATION_ADD_TO_BOOKMARKS_OPENED); verify(mTabBookmarker).addOrEditBookmark(mTab); } }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareHelperUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareHelperUnitTest.java index c50970e..0dc419cbb 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareHelperUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/share/ShareHelperUnitTest.java
@@ -273,6 +273,26 @@ ShareHelper.shareWithSystemShareSheetUi(emptyShareParams(), null, false, provider); } + @Test + public void shareWithPreviewUri() { + ShareParams params = new ShareParams.Builder(mWindow, "title", JUnitTestGURLs.EXAMPLE_URL) + .setPreviewImageUri(mImageUri) + .setBypassFixingDomDistillerUrl(true) + .build(); + ShareHelper.shareWithSystemShareSheetUi(params, null, true); + + Intent nextIntent = Shadows.shadowOf(mActivity).peekNextStartedActivity(); + assertNotNull("Shared intent is null.", nextIntent); + assertEquals( + "Intent is not a chooser intent.", Intent.ACTION_CHOOSER, nextIntent.getAction()); + + // Verify the intent has the right preview Uri. + Intent sharingIntent = nextIntent.getParcelableExtra(Intent.EXTRA_INTENT); + assertEquals("Intent is not a SEND intent.", Intent.ACTION_SEND, sharingIntent.getAction()); + assertEquals("Preview image Uri not set correctly.", mImageUri, + sharingIntent.getClipData().getItemAt(0).getUri()); + } + private void selectComponentFromChooserIntent(Intent chooserIntent, ComponentName componentName) throws SendIntentException { Intent sendBackIntent = new Intent().putExtra(Intent.EXTRA_CHOSEN_COMPONENT, componentName);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java index 246efc7..e6dc132 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java
@@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.Resources; import android.os.Build; +import android.view.Display; import androidx.test.core.app.ApplicationProvider; @@ -54,6 +55,7 @@ import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowDisplayAndroid; +import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowDisplayAndroidManager; import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowSysUtils; import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowUmaSessionStats; import org.chromium.chrome.browser.tab.TabUtilsUnitTest.ShadowProfile; @@ -77,6 +79,7 @@ import org.chromium.content_public.browser.NavigationController; import org.chromium.content_public.browser.WebContents; import org.chromium.ui.display.DisplayAndroid; +import org.chromium.ui.display.DisplayAndroidManager; import org.chromium.ui.modaldialog.DialogDismissalCause; import org.chromium.ui.modaldialog.ModalDialogManager; import org.chromium.ui.modaldialog.ModalDialogManager.ModalDialogType; @@ -100,7 +103,8 @@ @RunWith(BaseRobolectricTestRunner.class) @Config(manifest = Config.NONE, shadows = {ShadowGURL.class, ShadowSysUtils.class, ShadowProfile.class, - ShadowUmaSessionStats.class, ShadowDisplayAndroid.class}) + ShadowUmaSessionStats.class, ShadowDisplayAndroid.class, + ShadowDisplayAndroidManager.class}) public class RequestDesktopUtilsUnitTest { @Rule public JniMocker mJniMocker = new JniMocker(); @@ -172,6 +176,20 @@ } } + @Implements(DisplayAndroidManager.class) + static class ShadowDisplayAndroidManager { + private static Display sDisplay; + + public static void setDisplay(Display display) { + sDisplay = display; + } + + @Implementation + public static Display getDefaultDisplayForContext(Context context) { + return sDisplay; + } + } + @Mock private WebsitePreferenceBridge.Natives mWebsitePreferenceBridgeJniMock; @Mock @@ -196,6 +214,8 @@ private ObservableSupplier<Tab> mCurrentTabSupplier; @Mock private DisplayAndroid mDisplayAndroid; + @Mock + private Display mDisplay; private Tab mTab; private @ContentSettingValues int mRdsDefaultValue; @@ -271,6 +291,8 @@ when(mDisplayAndroid.getDisplayHeight()).thenReturn(2560); when(mDisplayAndroid.getXdpi()).thenReturn(275.5f); when(mDisplayAndroid.getYdpi()).thenReturn(276.5f); + ShadowDisplayAndroidManager.setDisplay(mDisplay); + when(mDisplay.getDisplayId()).thenReturn(Display.DEFAULT_DISPLAY); enableFeatureWithParams( ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS_LOGGING, null, false); } @@ -456,6 +478,27 @@ } @Test + public void testShouldDefaultEnableGlobalSetting_ExternalDisplay() { + Map<String, String> params = new HashMap<>(); + enableFeatureWithParams(ChromeFeatureList.REQUEST_DESKTOP_SITE_DEFAULTS, params, true); + when(mDisplay.getDisplayId()).thenReturn(/*non built-in display*/ 2); + boolean shouldDefaultEnable = RequestDesktopUtils.shouldDefaultEnableGlobalSetting( + RequestDesktopUtils.DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES, + mActivity); + Assert.assertFalse( + "Desktop site global setting should not be default-enabled on external display", + shouldDefaultEnable); + + when(mDisplay.getDisplayId()).thenReturn(Display.DEFAULT_DISPLAY); + shouldDefaultEnable = RequestDesktopUtils.shouldDefaultEnableGlobalSetting( + RequestDesktopUtils.DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES, + mActivity); + Assert.assertTrue( + "Desktop site global setting should be default-enabled on built-in display", + shouldDefaultEnable); + } + + @Test public void testShouldDefaultEnableGlobalSetting_WithLogging() { Map<String, String> params = new HashMap<>(); params.put(
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc index 99c6ee4f..d4b31d1 100644 --- a/chrome/app/chrome_main_delegate.cc +++ b/chrome/app/chrome_main_delegate.cc
@@ -939,7 +939,6 @@ } base::HangWatcher::InitializeOnMainThread(hang_watcher_process_type); - base::internal::TimerBase::InitializeFeatures(); base::InitializeCpuReductionExperiment(); base::sequence_manager::internal::SequenceManagerImpl::InitializeFeatures(); #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index eacc9c13..d17bb8e 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -5958,6 +5958,7 @@ "//chrome/services/mac_notifications/public/mojom", "//components/crash/core/app", "//components/metal_util", + "//components/policy/core/common:common_constants", "//components/power_metrics", "//components/remote_cocoa/browser:browser", "//sandbox/mac:seatbelt",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 5559a2f..3cc7af8 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -4231,6 +4231,12 @@ flag_descriptions::kAdaptiveButtonInTopToolbarTranslateDescription, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kAdaptiveButtonInTopToolbarTranslate)}, + {"adaptive-button-in-top-toolbar-add-to-bookmarks", + flag_descriptions::kAdaptiveButtonInTopToolbarAddToBookmarksName, + flag_descriptions::kAdaptiveButtonInTopToolbarAddToBookmarksDescription, + kOsAndroid, + FEATURE_VALUE_TYPE( + chrome::android::kAdaptiveButtonInTopToolbarAddToBookmarks)}, {"adaptive-button-in-top-toolbar-customization", flag_descriptions::kAdaptiveButtonInTopToolbarCustomizationName, flag_descriptions::kAdaptiveButtonInTopToolbarCustomizationDescription, @@ -5862,6 +5868,15 @@ kPageContentAnnotationsVariations, "PageContentAnnotations")}, + {"page-content-annotations-persist-salient-image-metadata", + flag_descriptions::kPageContentAnnotationsPersistSalientImageMetadataName, + flag_descriptions:: + kPageContentAnnotationsPersistSalientImageMetadataDescription, + kOsDesktop, + FEATURE_VALUE_TYPE( + optimization_guide::features:: + kPageContentAnnotationsPersistSalientImageMetadata)}, + {"page-entities-page-content-annotations", flag_descriptions::kPageEntitiesPageContentAnnotationsName, flag_descriptions::kPageEntitiesPageContentAnnotationsDescription, @@ -6067,6 +6082,10 @@ flag_descriptions::kNtpReducedLogoSpaceDescription, kOsDesktop, FEATURE_VALUE_TYPE(ntp_features::kNtpReducedLogoSpace)}, + {"ntp-single-row-shortcuts", flag_descriptions::kNtpSingleRowShortcutsName, + flag_descriptions::kNtpSingleRowShortcutsDescription, kOsDesktop, + FEATURE_VALUE_TYPE(ntp_features::kNtpSingleRowShortcuts)}, + {"ntp-middle-slot-promo-dismissal", flag_descriptions::kNtpMiddleSlotPromoDismissalName, flag_descriptions::kNtpMiddleSlotPromoDismissalDescription, kOsDesktop, @@ -7567,6 +7586,10 @@ flag_descriptions::kShimlessRMADisableDarkModeName, flag_descriptions::kShimlessRMADisableDarkModeDescription, kOsCrOS, FEATURE_VALUE_TYPE(ash::features::kShimlessRMADisableDarkMode)}, + {"shimless-rma-diagnostic-page", + flag_descriptions::kShimlessRMADiagnosticPageName, + flag_descriptions::kShimlessRMADiagnosticPageDescription, kOsCrOS, + FEATURE_VALUE_TYPE(ash::features::kShimlessRMADisableDarkMode)}, {"nearby-sharing-self-share-auto-accept", flag_descriptions::kNearbySharingSelfShareAutoAcceptName, flag_descriptions::kNearbySharingSelfShareAutoAcceptDescription, kOsCrOS, @@ -9689,6 +9712,11 @@ flag_descriptions::kPassthroughYuvRgbConversionDescription, kOsAll, FEATURE_VALUE_TYPE(features::kPassthroughYuvRgbConversion)}, + {"use-multi-plane-format-for-hardware-video", + flag_descriptions::kUseMultiPlaneFormatForHardwareVideoName, + flag_descriptions::kUseMultiPlaneFormatForHardwareVideoDescription, kOsAll, + FEATURE_VALUE_TYPE(media::kUseMultiPlaneFormatForHardwareVideo)}, + {"policy-merge-multi-source", flag_descriptions::kPolicyMergeMultiSourceName, flag_descriptions::kPolicyMergeMultiSourceDescription, kOsAll,
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 53752c95..9d3d078 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -50,6 +50,7 @@ #include "chrome/browser/policy/chrome_browser_policy_connector.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/profiles/profile_manager.h" @@ -83,6 +84,8 @@ #import "chrome/browser/ui/cocoa/tab_menu_bridge.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/profile_picker.h" +#include "chrome/browser/ui/startup/first_run_service.h" +#include "chrome/browser/ui/startup/launch_mode_recorder.h" #include "chrome/browser/ui/startup/startup_browser_creator.h" #include "chrome/browser/ui/startup/startup_browser_creator_impl.h" #include "chrome/browser/ui/startup/startup_tab.h" @@ -106,6 +109,7 @@ #include "components/handoff/handoff_utility.h" #include "components/keep_alive_registry/keep_alive_types.h" #include "components/keep_alive_registry/scoped_keep_alive.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" #include "components/sessions/core/tab_restore_service.h" #include "content/public/browser/download_manager.h" @@ -178,9 +182,36 @@ return browser; } +// Launches a browser window associated with |profile|. Checks if we are in the +// first run of Chrome to decide if we need to launch a browser or not. +// The profile can be `nullptr` and in that case the last-used profile will be +// used. +void LaunchBrowserStartup(Profile* profile) { + if (StartupProfileModeFromReason(ProfilePicker::GetStartupModeReason()) == + StartupProfileMode::kProfilePicker) { + ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint( + ProfilePicker::EntryPoint::kNewSessionOnExistingProcess)); + return; + } + CHECK(profile); + + base::AutoReset<bool> auto_reset_in_run(&g_is_opening_new_window, true); + StartupBrowserCreator browser_creator; + browser_creator.LaunchBrowser(*base::CommandLine::ForCurrentProcess(), + profile, base::FilePath(), + chrome::startup::IsProcessStartup::kNo, + chrome::startup::IsFirstRun::kYes, nullptr); +} + // Creates an empty browser window with the given profile and returns a pointer // to the new |Browser|. Browser* CreateBrowser(Profile* profile) { + // Closes the first run if we open a new window. + if (auto* fre_service = + FirstRunServiceFactory::GetForBrowserContext(profile)) { + fre_service->FinishFirstRunWithoutResumeTask(); + } + { base::AutoReset<bool> auto_reset_in_run(&g_is_opening_new_window, true); chrome::NewEmptyWindow(profile); @@ -213,15 +244,8 @@ // Session was restored. return; } - // No session to restore, proceed with normal startup. - if (StartupProfileModeFromReason(ProfilePicker::GetStartupModeReason()) == - StartupProfileMode::kProfilePicker) { - ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint( - ProfilePicker::EntryPoint::kNewSessionOnExistingProcess)); - } else { - CreateBrowser(profile); - } + LaunchBrowserStartup(profile); } CFStringRef BaseBundleID_CFString() { @@ -1412,6 +1436,7 @@ ProfilePicker::EntryPoint::kNewSessionOnExistingProcess)); } else { // Asynchronously load profile first if needed. + // TODO(crbug.com/1426857): Replace CreateBrowser by LaunchBrowserStartup app_controller_mac::RunInLastProfileSafely( base::BindOnce(base::IgnoreResult(&CreateBrowser)), app_controller_mac::kShowProfilePickerOnFailure); @@ -1755,7 +1780,7 @@ _profilePrefRegistrar = std::make_unique<PrefChangeRegistrar>(); _profilePrefRegistrar->Init(_lastProfile->GetPrefs()); _profilePrefRegistrar->Add( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, base::BindRepeating(&chrome::BrowserCommandController:: UpdateSharedCommandsForIncognitoAvailability, _menuState.get(), _lastProfile));
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm index f3fc82d..aa82566 100644 --- a/chrome/browser/app_controller_mac_browsertest.mm +++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -32,6 +32,7 @@ #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/browser_features.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/first_run/first_run.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/lifetime/application_lifetime_desktop.h" @@ -57,7 +58,9 @@ #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h" #include "chrome/browser/ui/cocoa/test/run_loop_testing.h" #include "chrome/browser/ui/profile_picker.h" +#include "chrome/browser/ui/profile_ui_test_utils.h" #include "chrome/browser/ui/search/ntp_test_utils.h" +#include "chrome/browser/ui/startup/first_run_service.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/ui_features.h" @@ -634,6 +637,49 @@ EXPECT_TRUE(browser_added_observer.Wait()); } +class AppControllerFirstRunBrowserTest : public AppControllerBrowserTest { + public: + void SetUpDefaultCommandLine(base::CommandLine* command_line) override { + InProcessBrowserTest::SetUpDefaultCommandLine(command_line); + command_line->RemoveSwitch(switches::kNoFirstRun); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_{kForYouFre}; +}; + +IN_PROC_BROWSER_TEST_F(AppControllerFirstRunBrowserTest, + OpenNewWindowWhileFreIsRunning) { + EXPECT_TRUE(ProfilePicker::IsFirstRunOpen()); + EXPECT_EQ(BrowserList::GetInstance()->size(), 0u); + AppController* ac = base::mac::ObjCCast<AppController>( + [[NSApplication sharedApplication] delegate]); + ASSERT_TRUE(ac); + NSMenu* menu = [ac applicationDockMenu:NSApp]; + ASSERT_TRUE(menu); + + NSMenuItem* item = [menu itemWithTag:IDC_NEW_WINDOW]; + ASSERT_TRUE(item); + [ac commandDispatch:item]; + + profiles::testing::WaitForPickerClosed(); + EXPECT_FALSE(ProfilePicker::IsFirstRunOpen()); + EXPECT_EQ(BrowserList::GetInstance()->size(), 1u); +} + +IN_PROC_BROWSER_TEST_F(AppControllerFirstRunBrowserTest, + ClickingChromeDockIconDoesNotOpenBrowser) { + EXPECT_TRUE(ProfilePicker::IsFirstRunOpen()); + EXPECT_EQ(BrowserList::GetInstance()->size(), 0u); + AppController* ac = base::mac::ObjCCast<AppController>( + [[NSApplication sharedApplication] delegate]); + ASSERT_TRUE(ac); + [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO]; + + EXPECT_EQ(BrowserList::GetInstance()->size(), 0u); + ProfilePicker::Hide(); +} + class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest { protected: AppControllerOpenShortcutBrowserTest()
diff --git a/chrome/browser/ash/app_list/search/app_discovery_metrics_manager.cc b/chrome/browser/ash/app_list/search/app_discovery_metrics_manager.cc index fb6f415..541d7ed 100644 --- a/chrome/browser/ash/app_list/search/app_discovery_metrics_manager.cc +++ b/chrome/browser/ash/app_list/search/app_discovery_metrics_manager.cc
@@ -55,6 +55,7 @@ .SetAppId(app_id) .SetAppName(std::string(app_title.begin(), app_title.end())) .SetFuzzyStringMatch(string_match_score) + .SetResultCategory(result->metrics_type()) .Record(); }
diff --git a/chrome/browser/ash/app_list/search/app_discovery_metrics_manager_unittest.cc b/chrome/browser/ash/app_list/search/app_discovery_metrics_manager_unittest.cc index 95012dfc..69446fd 100644 --- a/chrome/browser/ash/app_list/search/app_discovery_metrics_manager_unittest.cc +++ b/chrome/browser/ash/app_list/search/app_discovery_metrics_manager_unittest.cc
@@ -99,7 +99,8 @@ void ValidateAppLaunchEvent(const metrics::structured::Event& event, const std::string& app_id, const std::u16string& app_title, - double match_score) { + double match_score, + const ash::SearchResultType search_result_type) { cros_events::AppDiscovery_AppLauncherResultOpened expected_event; EXPECT_EQ(expected_event.project_name(), event.project_name()); @@ -107,7 +108,8 @@ expected_event.SetAppId(app_id) .SetAppName(std::string(app_title.begin(), app_title.end())) - .SetFuzzyStringMatch(match_score); + .SetFuzzyStringMatch(match_score) + .SetResultCategory(search_result_type); EXPECT_EQ(expected_event.metric_values(), event.metric_values()); } @@ -143,14 +145,16 @@ const std::u16string app_name = u"app_name"; const std::u16string query = u"app_name"; const std::string app_id = "id"; + const auto search_result_type = + ash::SearchResultType::PLAY_STORE_UNINSTALLED_APP; - TestSearchResult search_result( - app_id, app_name, ash::SearchResultType::PLAY_STORE_UNINSTALLED_APP); + TestSearchResult search_result(app_id, app_name, search_result_type); base::RunLoop run_loop; auto record_callback = base::BindLambdaForTesting( [&, this](const metrics::structured::Event& event) { - ValidateAppLaunchEvent(event, app_id, app_name, /*match_score=*/1.0); + ValidateAppLaunchEvent(event, app_id, app_name, /*match_score=*/1.0, + search_result_type); run_loop.Quit(); }); test_structured_metrics_provider()->SetOnEventsRecordClosure(record_callback); @@ -163,20 +167,21 @@ const std::u16string app_name = u"app_name"; const std::u16string query = u"app_name"; const std::string app_id = "id"; + const auto search_result_type = + ash::SearchResultType::PLAY_STORE_UNINSTALLED_APP; // Disable app-sync. sync_service()->SetDisableReasons( syncer::SyncService::DISABLE_REASON_ENTERPRISE_POLICY); - TestSearchResult search_result( - app_id, app_name, ash::SearchResultType::PLAY_STORE_UNINSTALLED_APP); + TestSearchResult search_result(app_id, app_name, search_result_type); base::RunLoop run_loop; auto record_callback = base::BindLambdaForTesting( [&, this](const metrics::structured::Event& event) { // App ID and app name will be stripped if app sync is disabled. ValidateAppLaunchEvent(event, /*app_id=*/"", /*app_title=*/u"", - /*match_score=*/1.0); + /*match_score=*/1.0, search_result_type); run_loop.Quit(); }); test_structured_metrics_provider()->SetOnEventsRecordClosure(record_callback);
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc index 2dd7d20..49fc7c6 100644 --- a/chrome/browser/autofill/autofill_interactive_uitest.cc +++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -664,16 +664,30 @@ {"address2", ""}, {"city", ""}, {"state", ""}, {"zip", ""}, {"country", ""}, {"phone", ""}}; +const struct { + const char* first_name = "Milton"; + const char* middle_name = "C."; + const char* last_name = "Waddams"; + const char* address1 = "4120 Freidrich Lane"; + const char* address2 = "Basement"; + const char* city = "Austin"; + const char* state_short = "TX"; + const char* state = "Texas"; + const char* zip = "78744"; + const char* country = "US"; + const char* phone = "15125551234"; +} kDefaultAddressValues; + const std::vector<FieldValue> kDefaultAddress{ - {"firstname", "Milton"}, - {"lastname", "Waddams"}, - {"address1", "4120 Freidrich Lane"}, - {"address2", "Basement"}, - {"city", "Austin"}, - {"state", "TX"}, - {"zip", "78744"}, - {"country", "US"}, - {"phone", "15125551234"}}; + {"firstname", kDefaultAddressValues.first_name}, + {"lastname", kDefaultAddressValues.last_name}, + {"address1", kDefaultAddressValues.address1}, + {"address2", kDefaultAddressValues.address2}, + {"city", kDefaultAddressValues.city}, + {"state", kDefaultAddressValues.state_short}, + {"zip", kDefaultAddressValues.zip}, + {"country", kDefaultAddressValues.country}, + {"phone", kDefaultAddressValues.phone}}; // Returns a copy of |fields| except that the value of `update.id` is set to // `update.value`. @@ -1083,10 +1097,13 @@ void CreateTestProfile() { AutofillProfile profile; - test::SetProfileInfo(&profile, "Milton", "C.", "Waddams", - "red.swingline@initech.com", "Initech", - "4120 Freidrich Lane", "Basement", "Austin", "Texas", - "78744", "US", "15125551234"); + test::SetProfileInfo( + &profile, kDefaultAddressValues.first_name, + kDefaultAddressValues.middle_name, kDefaultAddressValues.last_name, + "red.swingline@initech.com", "Initech", kDefaultAddressValues.address1, + kDefaultAddressValues.address2, kDefaultAddressValues.city, + kDefaultAddressValues.state, kDefaultAddressValues.zip, + kDefaultAddressValues.country, kDefaultAddressValues.phone); profile.set_use_count(9999999); // We want this to be the first profile. AddTestProfile(browser()->profile(), profile); } @@ -1428,6 +1445,7 @@ // Modify a field. ASSERT_TRUE(FocusField(GetElementById("state"), GetWebContents())); + ASSERT_NE(strcmp(kDefaultAddressValues.state_short, "CA"), 0); FillElementWithValue("state", "CA"); ASSERT_TRUE(AutofillFlow(GetElementById("firstname"), this));
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 05f418f..44da0bc 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3056,6 +3056,22 @@ HostContentSettingsMapFactory::GetForProfile(profile)); } +bool ChromeContentBrowserClient::MayDeleteServiceWorkerRegistration( + const GURL& scope, + content::BrowserContext* browser_context) { + DCHECK(browser_context); + DCHECK_CURRENTLY_ON(BrowserThread::UI); + +#if BUILDFLAG(ENABLE_EXTENSIONS) + if (!ChromeContentBrowserClientExtensionsPart:: + MayDeleteServiceWorkerRegistration(scope, browser_context)) { + return false; + } +#endif + + return true; +} + void ChromeContentBrowserClient:: UpdateEnabledBlinkRuntimeFeaturesInIsolatedWorker( content::BrowserContext* context,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 02dffaa..d2337ac 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -271,6 +271,9 @@ const absl::optional<url::Origin>& top_frame_origin, const GURL& script_url, content::BrowserContext* context) override; + bool MayDeleteServiceWorkerRegistration( + const GURL& scope, + content::BrowserContext* browser_context) override; void UpdateEnabledBlinkRuntimeFeaturesInIsolatedWorker( content::BrowserContext* context, const GURL& script_url,
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc index e1a7f22..62847fe 100644 --- a/chrome/browser/engagement/site_engagement_service_unittest.cc +++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -456,7 +456,8 @@ EngagementType::kNotificationInteraction, 4); } -TEST_F(SiteEngagementServiceTest, RestrictedToHTTPAndHTTPS) { +// TODO(https://crbug.com/1426914): Fix and enable this test. +TEST_F(SiteEngagementServiceTest, DISABLED_RestrictedToHTTPAndHTTPS) { // The https and http versions of www.google.com should be separate. GURL url1("ftp://www.google.com/"); GURL url2("file://blah");
diff --git a/chrome/browser/extensions/api/system_private/system_private_api.cc b/chrome/browser/extensions/api/system_private/system_private_api.cc index d7fa9669..67ea8225 100644 --- a/chrome/browser/extensions/api/system_private/system_private_api.cc +++ b/chrome/browser/extensions/api/system_private/system_private_api.cc
@@ -14,7 +14,7 @@ #include "chrome/browser/extensions/event_router_forwarder.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/api/system_private.h" -#include "chrome/common/pref_names.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" #include "google_apis/google_api_keys.h" @@ -26,8 +26,8 @@ namespace { -// Maps prefs::kIncognitoModeAvailability values (0 = enabled, ...) -// to strings exposed to extensions. +// Maps policy::policy_prefs::kIncognitoModeAvailability values (0 = enabled, +// ...) to strings exposed to extensions. const char* const kIncognitoModeAvailabilityStrings[] = { "enabled", "disabled", @@ -56,7 +56,8 @@ SystemPrivateGetIncognitoModeAvailabilityFunction::Run() { PrefService* prefs = Profile::FromBrowserContext(browser_context())->GetPrefs(); - int value = prefs->GetInteger(prefs::kIncognitoModeAvailability); + int value = + prefs->GetInteger(policy::policy_prefs::kIncognitoModeAvailability); EXTENSION_FUNCTION_VALIDATE( value >= 0 && value < static_cast<int>(std::size(kIncognitoModeAvailabilityStrings)));
diff --git a/chrome/browser/extensions/api/system_private/system_private_apitest.cc b/chrome/browser/extensions/api/system_private/system_private_apitest.cc index 329cad2..2f970f7a 100644 --- a/chrome/browser/extensions/api/system_private/system_private_apitest.cc +++ b/chrome/browser/extensions/api/system_private/system_private_apitest.cc
@@ -7,7 +7,7 @@ #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" -#include "chrome/common/pref_names.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" #include "content/public/test/browser_test.h" @@ -20,7 +20,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, GetIncognitoModeAvailability) { PrefService* pref_service = browser()->profile()->GetPrefs(); - pref_service->SetInteger(prefs::kIncognitoModeAvailability, 1); + pref_service->SetInteger(policy::policy_prefs::kIncognitoModeAvailability, 1); EXPECT_TRUE(RunExtensionTest("system/get_incognito_mode_availability", {}, {.load_as_component = true}))
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc index 8a4bd53..4e315a4 100644 --- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc +++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -36,6 +36,7 @@ #include "extensions/test/extension_test_message_listener.h" #include "extensions/test/result_catcher.h" #include "testing/gmock/include/gmock/gmock.h" +#include "ui/gl/gl_switches.h" #include "url/url_constants.h" namespace extensions { @@ -52,6 +53,7 @@ // Specify smallish window size to make testing of tab capture less CPU // intensive. command_line->AppendSwitchASCII(::switches::kWindowSize, "300,300"); + command_line->AppendSwitch(::switches::kUseGpuInTests); } void AddExtensionToCommandLineAllowlist() {
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc index 119a35b8..f1628be 100644 --- a/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc +++ b/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc
@@ -749,7 +749,6 @@ const char* kScript = R"( var ff = document.createElement('fencedframe'); - ff.mode = 'opaque-ads'; document.body.appendChild(ff); )"; EXPECT_TRUE(content::ExecJs(rfh, kScript));
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc index 14354d303..173f1b1 100644 --- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc +++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -12,6 +12,7 @@ #include <string> #include <vector> +#include "base/auto_reset.h" #include "base/command_line.h" #include "base/functional/bind.h" #include "base/metrics/histogram_macros.h" @@ -64,6 +65,7 @@ #include "extensions/browser/process_map.h" #include "extensions/browser/renderer_startup_helper.h" #include "extensions/browser/service_worker/service_worker_host.h" +#include "extensions/browser/service_worker_task_queue.h" #include "extensions/browser/url_loader_factory_manager.h" #include "extensions/browser/url_request_util.h" #include "extensions/browser/view_type_utils.h" @@ -96,6 +98,9 @@ namespace { +// If non-null, a scope of a service worker to always allow to be unregistered. +const GURL* g_allow_service_worker_unregistration_scope = nullptr; + // Used by the GetPrivilegeRequiredByUrl() and GetProcessPrivilege() functions // below. Extensions and hosted apps require different privileges to be // granted to their RenderProcessHosts. This classification allows us to make @@ -574,6 +579,53 @@ return ::extensions::AllowServiceWorker(scope, script_url, extension); } +bool ChromeContentBrowserClientExtensionsPart:: + MayDeleteServiceWorkerRegistration( + const GURL& scope, + content::BrowserContext* browser_context) { + // We only care about extension urls. + if (!scope.SchemeIs(kExtensionScheme)) { + return true; + } + + // Check if we're allowed to unregister this worker for testing purposes. + if (g_allow_service_worker_unregistration_scope && + *g_allow_service_worker_unregistration_scope == scope) { + return true; + } + + const Extension* extension = ExtensionRegistry::Get(browser_context) + ->enabled_extensions() + .GetExtensionOrAppByURL(scope); + if (!extension) { + return true; + } + + // We only consider service workers that are root-scoped and for service + // worker-based extensions. + if (scope != extension->url() || + !BackgroundInfo::IsServiceWorkerBased(extension)) { + return true; + } + + base::Version registered_version = + ServiceWorkerTaskQueue::Get(browser_context) + ->RetrieveRegisteredServiceWorkerVersion(extension->id()); + // The service worker was never fully registered; this can happen in the case + // of e.g. throwing errors in response to installation events (where the + // worker is registered, but then immediately unregistered). + if (!registered_version.IsValid()) { + return true; + } + + // Don't allow the unregistration of a valid, enabled service worker-based + // extension's background service worker. Doing so would put the extension in + // a broken state. The service worker registration is instead tied to the + // extension's enablement; it is unregistered when the extension is disabled + // or uninstalled. + return registered_version != extension->version(); +} + // static std::vector<url::Origin> ChromeContentBrowserClientExtensionsPart:: GetOriginsRequiringDedicatedProcess() { @@ -627,12 +679,20 @@ ->Exists(extension_id); } +// static bool ChromeContentBrowserClientExtensionsPart::AreExtensionsDisabledForProfile( content::BrowserContext* browser_context) { return AreKeyedServicesDisabledForProfileByDefault( Profile::FromBrowserContext(browser_context)); } +// static +base::AutoReset<const GURL*> ChromeContentBrowserClientExtensionsPart:: + AllowServiceWorkerUnregistrationForScopeForTesting(const GURL* scope) { + return base::AutoReset<const GURL*>( + &g_allow_service_worker_unregistration_scope, scope); +} + void ChromeContentBrowserClientExtensionsPart::RenderProcessWillLaunch( content::RenderProcessHost* host) { int id = host->GetID();
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h index f4118bbc..83248ca 100644 --- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h +++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.h
@@ -7,6 +7,7 @@ #include <memory> +#include "base/auto_reset.h" #include "base/gtest_prod_util.h" #include "chrome/browser/chrome_content_browser_client_parts.h" #include "components/download/public/common/quarantine_connection.h" @@ -81,6 +82,9 @@ const GURL& first_party_url, const GURL& script_url, content::BrowserContext* context); + static bool MayDeleteServiceWorkerRegistration( + const GURL& scope, + content::BrowserContext* browser_context); static std::vector<url::Origin> GetOriginsRequiringDedicatedProcess(); // Helper function to call InfoMap::SetSigninProcess(). @@ -104,6 +108,12 @@ static bool AreExtensionsDisabledForProfile( content::BrowserContext* browser_context); + // Temporarily allows unregistration of the service worker with the given + // `scope` for testing purposes; unregistration is allowed while the returned + // AutoReset remains in scope. + static base::AutoReset<const GURL*> + AllowServiceWorkerUnregistrationForScopeForTesting(const GURL* scope); + private: FRIEND_TEST_ALL_PREFIXES(ChromeContentBrowserClientExtensionsPartTest, IsolatedOriginsAndHostedAppWebExtents);
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc index 7bcd17f7..927b930 100644 --- a/chrome/browser/extensions/service_worker_apitest.cc +++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/auto_reset.h" #include "base/functional/bind.h" #include "base/functional/callback_helpers.h" #include "base/json/json_reader.h" @@ -21,6 +22,7 @@ #include "build/build_config.h" #include "chrome/browser/extensions/api/permissions/permissions_api.h" #include "chrome/browser/extensions/browsertest_util.h" +#include "chrome/browser/extensions/chrome_content_browser_client_extensions_part.h" #include "chrome/browser/extensions/chrome_test_extension_loader.h" #include "chrome/browser/extensions/crx_installer.h" #include "chrome/browser/extensions/error_console/error_console.h" @@ -2389,7 +2391,7 @@ // The registration should not have been stored, so we shouldn't cache the // extension version. base::Version stored_version = - service_worker_task_queue->RetrieveRegisteredServiceWorkerVersionForTest( + service_worker_task_queue->RetrieveRegisteredServiceWorkerVersion( extension->id()); EXPECT_FALSE(stored_version.IsValid()); } @@ -2840,24 +2842,47 @@ // Regression test for crbug.com/1271154. IN_PROC_BROWSER_TEST_F(ServiceWorkerTestWithEarlyReadyMesssage, PRE_MissingRegistrationMitigated) { - const Extension* extension = LoadExtension(test_data_dir_.AppendASCII( - "service_worker/worker_based_background/activate_ensures_register")); + const Extension* extension = LoadExtension( + test_data_dir_.AppendASCII( + "service_worker/worker_based_background/activate_ensures_register"), + {.wait_for_registration_stored = true}); ASSERT_TRUE(extension); - EXPECT_TRUE(WaitForMessage()); + ASSERT_TRUE(WaitForMessage()); + base::RunLoop().RunUntilIdle(); - // Unregister the extension service worker. + // Since we wait for the registration to be stored (and run until idle, + // guaranteeing all observers see the result), we should now have a stored + // version for the service worker in the extensions system. + ServiceWorkerTaskQueue* service_worker_task_queue = + ServiceWorkerTaskQueue::Get(browser()->profile()); + base::Version stored_version = + service_worker_task_queue->RetrieveRegisteredServiceWorkerVersion( + extension->id()); + { + // Bypass our unregistration protections to unregister the worker. Though + // we largely prevent this, it could still happen by means of e.g. + // disk or pref corruption. base::RunLoop run_loop; content::ServiceWorkerContext* context = GetServiceWorkerContext(profile()); - // The service worker is registered at the root scope. + const GURL& scope = extension->url(); + base::AutoReset<const GURL*> allow_worker_unregistration = + ChromeContentBrowserClientExtensionsPart:: + AllowServiceWorkerUnregistrationForScopeForTesting(&scope); + context->UnregisterServiceWorker( - extension->url(), - blink::StorageKey::CreateFirstParty(extension->origin()), + scope, blink::StorageKey::CreateFirstParty(extension->origin()), base::BindLambdaForTesting( - [&run_loop](bool success) { run_loop.Quit(); })); + [&run_loop](bool success) { run_loop.QuitWhenIdle(); })); run_loop.Run(); } + + // The version should still be stored in the extension system. + stored_version = + service_worker_task_queue->RetrieveRegisteredServiceWorkerVersion( + extension->id()); + EXPECT_TRUE(stored_version.IsValid()); } IN_PROC_BROWSER_TEST_F(ServiceWorkerTestWithEarlyReadyMesssage,
diff --git a/chrome/browser/extensions/service_worker_registration_apitest.cc b/chrome/browser/extensions/service_worker_registration_apitest.cc index 4b3d587..087a8e9e 100644 --- a/chrome/browser/extensions/service_worker_registration_apitest.cc +++ b/chrome/browser/extensions/service_worker_registration_apitest.cc
@@ -4,6 +4,7 @@ #include "base/test/test_future.h" #include "chrome/browser/extensions/extension_apitest.h" +#include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/service_worker_context.h" #include "content/public/browser/storage_partition.h" #include "content/public/test/browser_test.h" @@ -14,6 +15,7 @@ #include "extensions/common/extension.h" #include "extensions/common/mojom/manifest.mojom.h" #include "extensions/test/extension_test_message_listener.h" +#include "extensions/test/result_catcher.h" #include "extensions/test/test_extension_dir.h" namespace extensions { @@ -72,8 +74,7 @@ ASSERT_TRUE(task_queue); base::Version stored_version = - task_queue->RetrieveRegisteredServiceWorkerVersionForTest( - extension->id()); + task_queue->RetrieveRegisteredServiceWorkerVersion(extension->id()); ASSERT_TRUE(stored_version.IsValid()); EXPECT_EQ("0.1", stored_version.GetString()); EXPECT_EQ(content::ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER, @@ -247,4 +248,107 @@ GetServiceWorkerRegistrationState(*extension_ref)); } +// Verifies that a service worker registration associated with an extension's +// manifest cannot be removed via the `chrome.browsingData` API. +// Regression test for https://crbug.com/1392498. +IN_PROC_BROWSER_TEST_F(ServiceWorkerRegistrationApiTest, + RegistrationCannotBeRemovedByBrowsingDataAPI) { + // Load two extensions: one with a service worker-based background context and + // a second with access to the browsingData API. + static constexpr char kServiceWorkerManifest[] = + R"({ + "name": "Service Worker Extension", + "manifest_version": 3, + "version": "0.1", + "background": {"service_worker": "background.js"} + })"; + static constexpr char kServiceWorkerBackground[] = + R"(chrome.tabs.onCreated.addListener(tab => { + chrome.test.sendMessage('received event'); + });)"; + + TestExtensionDir service_worker_extension_dir; + service_worker_extension_dir.WriteManifest(kServiceWorkerManifest); + service_worker_extension_dir.WriteFile(FILE_PATH_LITERAL("background.js"), + kServiceWorkerBackground); + + static constexpr char kBrowsingDataManifest[] = + R"({ + "name": "Browsing Data Remover", + "manifest_version": 3, + "version": "0.1", + "permissions": ["browsingData"] + })"; + static constexpr char kClearDataJs[] = + R"(chrome.test.runTests([ + async function clearServiceWorkers() { + // From the extension's perspective, this call should succeed (it + // will remove any service workers for extensions that aren't the + // root-scoped background service worker). + await chrome.browsingData.removeServiceWorkers( + {originTypes: {extension: true}}); + chrome.test.succeed(); + }, + ]);)"; + + TestExtensionDir browsing_data_extension_dir; + browsing_data_extension_dir.WriteManifest(kBrowsingDataManifest); + browsing_data_extension_dir.WriteFile( + FILE_PATH_LITERAL("clear_data.html"), + R"(<html><script src="clear_data.js"></script></html>)"); + browsing_data_extension_dir.WriteFile(FILE_PATH_LITERAL("clear_data.js"), + kClearDataJs); + + const Extension* service_worker_extension = + LoadExtension(service_worker_extension_dir.UnpackedPath(), + {.wait_for_registration_stored = true}); + ASSERT_TRUE(service_worker_extension); + + const Extension* browsing_data_extension = + LoadExtension(browsing_data_extension_dir.UnpackedPath()); + ASSERT_TRUE(browsing_data_extension); + + auto open_new_tab = [this](const GURL& url) { + ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP)); + }; + + // Verify the initial state. The service worker-based extension should have a + // worker registered... + EXPECT_EQ(content::ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER, + GetServiceWorkerRegistrationState(*service_worker_extension)); + + const GURL about_blank("about:blank"); + + // ... And the worker should be able to receive incoming events. + { + ExtensionTestMessageListener listener("received event"); + open_new_tab(about_blank); + ASSERT_TRUE(listener.WaitUntilSatisfied()); + } + + // Open a page to the browsing data extension, which will trigger a call to + // the browsingData API to remove registered service workers for extensions. + { + ResultCatcher result_catcher; + open_new_tab(browsing_data_extension->GetResourceURL("clear_data.html")); + EXPECT_TRUE(result_catcher.GetNextResult()); + } + + // The removal above should *not* have resulted in the background service + // worker for the extension being removed (which would put the extension into + // a broken state). The only way to remove a service worker from an extension + // manifest is to uninstall the extension. + // The worker should still be registered, and should still receive new events. + EXPECT_EQ(content::ServiceWorkerCapability::SERVICE_WORKER_NO_FETCH_HANDLER, + GetServiceWorkerRegistrationState(*service_worker_extension)); + + { + ExtensionTestMessageListener listener("received event"); + open_new_tab(about_blank); + ASSERT_TRUE(listener.WaitUntilSatisfied()); + } +} + } // namespace extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index cac09668..c471ebe 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -44,6 +44,11 @@ "expiry_milestone": 99 }, { + "name": "adaptive-button-in-top-toolbar-add-to-bookmarks", + "owners": [ "salg@google.com", "chrome-segmentation-platform@google.com" ], + "expiry_milestone": 120 + }, + { "name": "adaptive-button-in-top-toolbar-customization", "owners": [ "shaktisahu", "chrome-segmentation-platform@google.com" ], "expiry_milestone": 120 @@ -1769,7 +1774,7 @@ { "name": "enable-accessibility-service", "owners": [ "katie", "//ui/accessibility/OWNERS" ], - "expiry_milestone": 120 + "expiry_milestone": 140 }, { "name": "enable-android-gamepad-vibration", @@ -2265,11 +2270,6 @@ "expiry_milestone": 111 }, { - "name": "enable-docked-magnifier-resizing", - "owners": [ "josiahk", "//ui/accessibility/OWNERS" ], - "expiry_milestone": 110 - }, - { "name": "enable-download-service-foreground-session", "owners": [ "rajendrant", "mcrouse", "chrome-intelligence-core@google.com" ], "expiry_milestone": 116 @@ -5179,6 +5179,11 @@ "expiry_milestone": 105 }, { + "name": "ntp-single-row-shortcuts", + "owners": [ "//components/search/OWNERS" ], + "expiry_milestone": 115 + }, + { "name": "ntp-view-hierarchy-repair", "owners": [ "adamta", "sczs" ], "expiry_milestone": 115 @@ -5697,6 +5702,11 @@ "expiry_milestone": 115 }, { + "name": "page-content-annotations-persist-salient-image-metadata", + "owners": [ "sophiechang", "chrome-intelligence-core@google.com"], + "expiry_milestone": 115 + }, + { "name": "page-entities-page-content-annotations", "owners": [ "sophiechang", "mcrouse", "chrome-intelligence-core@google.com"], "expiry_milestone": 115 @@ -6530,6 +6540,11 @@ "expiry_milestone": 116 }, { + "name": "shimless-rma-diagnostic-page", + "owners": [ "zentaro", "gavinwill", "cros-peripherals@google.com" ], + "expiry_milestone": 120 + }, + { "name": "shimless-rma-disable-dark-mode", "owners": [ "zentaro", "gavinwill", "cros-peripherals@google.com" ], "expiry_milestone": 120 @@ -7203,6 +7218,11 @@ "expiry_milestone": 128 }, { + "name": "use-multi-plane-format-for-hardware-video", + "owners": [ "hitawala", "vasilyt" ], + "expiry_milestone": 124 + }, + { "name": "use-nat64-for-ipv4-literal", "owners": [ "horo", "net-dev" ], "expiry_milestone": 120
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 5a5f51b9..c3c4298 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -2445,6 +2445,11 @@ const char kPageContentAnnotationsDescription[] = "Enables page content to be annotated on-device."; +const char kPageContentAnnotationsPersistSalientImageMetadataName[] = + "Page content annotations - Persist salient image metadata"; +const char kPageContentAnnotationsPersistSalientImageMetadataDescription[] = + "Enables salient image metadata per page load to be persisted on-device."; + const char kPageEntitiesPageContentAnnotationsName[] = "Page entities content annotations"; const char kPageEntitiesPageContentAnnotationsDescription[] = @@ -3463,6 +3468,12 @@ "Enable YUV to RGB and RGB to YUV conversion for media clients through " "passthrough command decoder"; +const char kUseMultiPlaneFormatForHardwareVideoName[] = + "Enable multi-plane formats for hardware video decoder"; +const char kUseMultiPlaneFormatForHardwareVideoDescription[] = + "Enable single shared image and mailbox for multi-plane formats for " + "hardware video decoder"; + const char kDurableClientHintsCacheName[] = "Persistent client hints"; const char kDurableClientHintsCacheDescription[] = "Persist the client hints cache beyond browser restarts."; @@ -4229,11 +4240,19 @@ const char kAdaptiveButtonInTopToolbarName[] = "Adaptive button in top toolbar"; const char kAdaptiveButtonInTopToolbarDescription[] = "Enables showing an adaptive action button in the top toolbar"; + const char kAdaptiveButtonInTopToolbarTranslateName[] = "Adaptive button in top toolbar - Translate button"; const char kAdaptiveButtonInTopToolbarTranslateDescription[] = "Enables a translate button in the top toolbar. Must be selected in " "Settings > Toolbar Shortcut."; +const char kAdaptiveButtonInTopToolbarAddToBookmarksName[] = + "Adaptive button in top toolbar - Add to bookmarks button"; +const char kAdaptiveButtonInTopToolbarAddToBookmarksDescription[] = + "Enables an add to bookmarks button in the top toolbar. Must be selected " + "in " + "Settings > Toolbar Shortcut."; + const char kAdaptiveButtonInTopToolbarCustomizationName[] = "Adaptive button in top toolbar customization"; const char kAdaptiveButtonInTopToolbarCustomizationDescription[] = @@ -4482,6 +4501,10 @@ const char kNtpSafeBrowsingModuleDescription[] = "Shows the safe browsing module on the New Tab Page."; +const char kNtpSingleRowShortcutsName[] = "NTP Single Row Shortcuts"; +const char kNtpSingleRowShortcutsDescription[] = + "Shows shortcuts in a single wide row on the New Tab Page."; + const char kEnableReaderModeName[] = "Enable Reader Mode"; const char kEnableReaderModeDescription[] = "Allows viewing of simplified web pages by selecting 'Customize and " @@ -6027,6 +6050,12 @@ const char kShimlessRMADisableDarkModeDescription[] = "Disable dark mode and only allow light mode in Shimless RMA"; +const char kShimlessRMADiagnosticPageName[] = + "Enable diagnostic page in Shimless RMA"; +const char kShimlessRMADiagnosticPageDescription[] = + "Enable the diagnostic page in Shimless RMA for showing detailed device " + "information"; + const char kSchedulerConfigurationName[] = "Scheduler Configuration"; const char kSchedulerConfigurationDescription[] = "Instructs the OS to use a specific scheduler configuration setting.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 95d739e..a3b9ffe 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -1367,6 +1367,10 @@ extern const char kPageContentAnnotationsName[]; extern const char kPageContentAnnotationsDescription[]; +extern const char kPageContentAnnotationsPersistSalientImageMetadataName[]; +extern const char + kPageContentAnnotationsPersistSalientImageMetadataDescription[]; + extern const char kPageEntitiesPageContentAnnotationsName[]; extern const char kPageEntitiesPageContentAnnotationsDescription[]; @@ -1985,6 +1989,9 @@ extern const char kPassthroughYuvRgbConversionName[]; extern const char kPassthroughYuvRgbConversionDescription[]; +extern const char kUseMultiPlaneFormatForHardwareVideoName[]; +extern const char kUseMultiPlaneFormatForHardwareVideoDescription[]; + extern const char kDurableClientHintsCacheName[]; extern const char kDurableClientHintsCacheDescription[]; @@ -2419,6 +2426,8 @@ extern const char kAdaptiveButtonInTopToolbarDescription[]; extern const char kAdaptiveButtonInTopToolbarTranslateName[]; extern const char kAdaptiveButtonInTopToolbarTranslateDescription[]; +extern const char kAdaptiveButtonInTopToolbarAddToBookmarksName[]; +extern const char kAdaptiveButtonInTopToolbarAddToBookmarksDescription[]; extern const char kAdaptiveButtonInTopToolbarCustomizationName[]; extern const char kAdaptiveButtonInTopToolbarCustomizationDescription[]; @@ -2575,6 +2584,9 @@ extern const char kNtpSafeBrowsingModuleName[]; extern const char kNtpSafeBrowsingModuleDescription[]; +extern const char kNtpSingleRowShortcutsName[]; +extern const char kNtpSingleRowShortcutsDescription[]; + extern const char kEnableReaderModeName[]; extern const char kEnableReaderModeDescription[]; @@ -3471,6 +3483,9 @@ extern const char kShimlessRMADisableDarkModeName[]; extern const char kShimlessRMADisableDarkModeDescription[]; +extern const char kShimlessRMADiagnosticPageName[]; +extern const char kShimlessRMADiagnosticPageDescription[]; + extern const char kSchedulerConfigurationName[]; extern const char kSchedulerConfigurationDescription[]; extern const char kSchedulerConfigurationConservative[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index a7202bb..02af7d8 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -159,6 +159,7 @@ &history_clusters::internal::kJourneys, &kAdaptiveButtonInTopToolbar, &kAdaptiveButtonInTopToolbarTranslate, + &kAdaptiveButtonInTopToolbarAddToBookmarks, &kAdaptiveButtonInTopToolbarCustomizationV2, &kAddEduAccountFromAccountSettingsForSupervisedUsers, &kAddToHomescreenIPH, @@ -435,6 +436,10 @@ "AdaptiveButtonInTopToolbarTranslate", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kAdaptiveButtonInTopToolbarAddToBookmarks, + "AdaptiveButtonInTopToolbarAddToBookmarks", + base::FEATURE_DISABLED_BY_DEFAULT); + BASE_FEATURE(kAdaptiveButtonInTopToolbarCustomizationV2, "AdaptiveButtonInTopToolbarCustomizationV2", base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index 0a4a29b..0215909 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -15,6 +15,7 @@ // Alphabetical: BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbar); BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarTranslate); +BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarAddToBookmarks); BASE_DECLARE_FEATURE(kAdaptiveButtonInTopToolbarCustomizationV2); BASE_DECLARE_FEATURE(kAddEduAccountFromAccountSettingsForSupervisedUsers); BASE_DECLARE_FEATURE(kAddToHomescreenIPH);
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 9a52713..e6593634 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
@@ -165,6 +165,8 @@ public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR = "AdaptiveButtonInTopToolbar"; public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_TRANSLATE = "AdaptiveButtonInTopToolbarTranslate"; + public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS = + "AdaptiveButtonInTopToolbarAddToBookmarks"; public static final String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2 = "AdaptiveButtonInTopToolbarCustomizationV2"; public static final String ADD_EDU_ACCOUNT_FROM_ACCOUNT_SETTINGS_FOR_SUPERVISED_USERS =
diff --git a/chrome/browser/incognito/android/incognito_utils_android.cc b/chrome/browser/incognito/android/incognito_utils_android.cc index 8cf37c25..117856e 100644 --- a/chrome/browser/incognito/android/incognito_utils_android.cc +++ b/chrome/browser/incognito/android/incognito_utils_android.cc
@@ -7,7 +7,7 @@ #include "chrome/browser/incognito/jni_headers/IncognitoUtils_jni.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "chrome/browser/profiles/profile_manager.h" -#include "chrome/common/pref_names.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" static jboolean JNI_IncognitoUtils_GetIncognitoModeEnabled(JNIEnv* env) { @@ -25,5 +25,6 @@ static jboolean JNI_IncognitoUtils_GetIncognitoModeManaged(JNIEnv* env) { PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetOriginalProfile()->GetPrefs(); - return prefs->IsManagedPreference(prefs::kIncognitoModeAvailability); + return prefs->IsManagedPreference( + policy::policy_prefs::kIncognitoModeAvailability); }
diff --git a/chrome/browser/media/cdm_document_service_impl.cc b/chrome/browser/media/cdm_document_service_impl.cc index 93086d3..9ee8c0177 100644 --- a/chrome/browser/media/cdm_document_service_impl.cc +++ b/chrome/browser/media/cdm_document_service_impl.cc
@@ -45,6 +45,7 @@ #include "base/files/file_enumerator.h" #include "base/files/file_util.h" +#include "base/metrics/histogram_functions.h" #include "base/system/sys_info.h" #include "base/task/task_traits.h" #include "base/task/thread_pool.h" @@ -368,11 +369,15 @@ auto* monitor = MediaFoundationServiceMonitor::GetInstance(); // Hardware context reset after power or display change is expected. - if (event == media::CdmEvent::kHardwareContextReset && - monitor->HasRecentPowerOrDisplayChange()) { - DVLOG(2) << __func__ - << ": HardwareContextReset ignored after power or display change"; - return; + if (event == media::CdmEvent::kHardwareContextReset) { + bool has_change = monitor->HasRecentPowerOrDisplayChange(); + base::UmaHistogramBoolean( + "Media.EME.MediaFoundationService.HardwareContextReset", has_change); + if (has_change) { + DVLOG(2) << __func__ + << ": HardwareContextReset ignored after power/display change"; + return; + } } // CdmDocumentServiceImpl is shared by all CDMs in the same RenderFrame.
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc index 00153dc..9519e5a2 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.cc
@@ -182,9 +182,11 @@ // Only record the start time for local routes bool is_route_local = false; + MediaSource source = MediaSource::ForAnyTab(); for (const auto& route : routes) { if (route.media_route_id() == new_route_id && route.is_local()) { is_route_local = true; + source = route.media_source(); } } @@ -199,7 +201,7 @@ MediaRoute::GetSinkIdFromMediaRouteId(new_route_id)), base::BindOnce(&AccessCodeCastSinkService::HandleMediaRouteAdded, access_code_sink_service_->GetWeakPtr(), - new_route_id, is_route_local)); + new_route_id, is_route_local, source)); } // No routes were removed. @@ -274,6 +276,7 @@ void AccessCodeCastSinkService::HandleMediaRouteAdded( const MediaRoute::Id route_id, const bool is_route_local, + const MediaSource media_source, const MediaSinkInternal* sink) { if (!IsSinkValidAccessCodeSink(sink)) return; @@ -282,8 +285,19 @@ current_route_start_times_[route_id] = base::Time::Now(); } + bool is_saved = sink->cast_data().discovery_type == + CastDiscoveryType::kAccessCodeRememberedDevice; + AccessCodeCastCastMode source_type = AccessCodeCastCastMode::kPresentation; + if (media_source.IsTabMirroringSource()) { + source_type = AccessCodeCastCastMode::kTabMirror; + } else if (media_source.IsDesktopMirroringSource()) { + source_type = AccessCodeCastCastMode::kDesktopMirror; + } else if (media_source.IsRemotePlaybackSource()) { + source_type = AccessCodeCastCastMode::kRemotePlayback; + } + AccessCodeCastMetrics::RecordAccessCodeRouteStarted( - GetAccessCodeDeviceDurationPref(profile_)); + GetAccessCodeDeviceDurationPref(profile_), is_saved, source_type); } void AccessCodeCastSinkService::OnAccessCodeRouteRemoved(
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h index 2cd901d..a8a28b1 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service.h
@@ -237,6 +237,7 @@ // Reports to metrics whenever the added route is to an access code sink. void HandleMediaRouteAdded(const MediaRoute::Id route_id, const bool is_route_local, + const MediaSource media_source, const MediaSinkInternal* sink); void OnAccessCodeRouteRemoved(const MediaSinkInternal* sink);
diff --git a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc index 8a432aa..7d7d543 100644 --- a/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc +++ b/chrome/browser/media/router/discovery/access_code/access_code_cast_sink_service_unittest.cc
@@ -1464,22 +1464,22 @@ histogram_tester.ExpectTotalCount( "AccessCodeCast.Discovery.DeviceDurationOnRoute", 0); - access_code_cast_sink_service_->HandleMediaRouteAdded(fake_route_1, true, - &cast_sink1); + access_code_cast_sink_service_->HandleMediaRouteAdded( + fake_route_1, true, MediaSource::ForAnyTab(), &cast_sink1); // The histogram should not be logged to after a non access code route starts. histogram_tester.ExpectTotalCount( "AccessCodeCast.Discovery.DeviceDurationOnRoute", 0); - access_code_cast_sink_service_->HandleMediaRouteAdded(fake_route_2, true, - &cast_sink2); + access_code_cast_sink_service_->HandleMediaRouteAdded( + fake_route_2, true, MediaSource::ForAnyTab(), &cast_sink2); // The histogram should log when a route starts to a new access code device. histogram_tester.ExpectBucketCount( "AccessCodeCast.Discovery.DeviceDurationOnRoute", 10, 1); - access_code_cast_sink_service_->HandleMediaRouteAdded(fake_route_3, true, - &cast_sink3); + access_code_cast_sink_service_->HandleMediaRouteAdded( + fake_route_3, true, MediaSource::ForAnyTab(), &cast_sink3); // The histogram should log when a route starts to a saved access code device. histogram_tester.ExpectBucketCount( @@ -1487,14 +1487,14 @@ // Ensure various pref values are can be logged. SetDeviceDurationPrefForTest(base::Seconds(100)); - access_code_cast_sink_service_->HandleMediaRouteAdded(fake_route_2, true, - &cast_sink2); + access_code_cast_sink_service_->HandleMediaRouteAdded( + fake_route_2, true, MediaSource::ForAnyTab(), &cast_sink2); histogram_tester.ExpectBucketCount( "AccessCodeCast.Discovery.DeviceDurationOnRoute", 100, 1); SetDeviceDurationPrefForTest(base::Seconds(1000)); - access_code_cast_sink_service_->HandleMediaRouteAdded(fake_route_2, true, - &cast_sink2); + access_code_cast_sink_service_->HandleMediaRouteAdded( + fake_route_2, true, MediaSource::ForAnyTab(), &cast_sink2); histogram_tester.ExpectBucketCount( "AccessCodeCast.Discovery.DeviceDurationOnRoute", 1000, 1);
diff --git a/chrome/browser/media/webrtc/capture_handle_browsertest.cc b/chrome/browser/media/webrtc/capture_handle_browsertest.cc index 267e09a..9b79746a5 100644 --- a/chrome/browser/media/webrtc/capture_handle_browsertest.cc +++ b/chrome/browser/media/webrtc/capture_handle_browsertest.cc
@@ -30,6 +30,7 @@ #include "content/public/test/browser_test_base.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/prerender_test_util.h" +#include "ui/gl/gl_switches.h" using content::WebContents; @@ -221,6 +222,7 @@ switches::kEnableExperimentalWebPlatformFeatures); command_line->AppendSwitchASCII( switches::kAutoSelectTabCaptureSourceByTitle, kCapturedTabTitle); + command_line->AppendSwitch(switches::kUseGpuInTests); } void TearDownOnMainThread() override {
diff --git a/chrome/browser/media/webrtc/conditional_focus_browsertest.cc b/chrome/browser/media/webrtc/conditional_focus_browsertest.cc index fb7f31bc..b9bcb49 100644 --- a/chrome/browser/media/webrtc/conditional_focus_browsertest.cc +++ b/chrome/browser/media/webrtc/conditional_focus_browsertest.cc
@@ -19,6 +19,7 @@ #include "content/public/common/content_switches.h" #include "content/public/test/browser_test.h" #include "third_party/blink/public/common/switches.h" +#include "ui/gl/gl_switches.h" namespace { @@ -73,6 +74,7 @@ switches::kAutoSelectTabCaptureSourceByTitle, kCapturedPageTitle); command_line->AppendSwitchASCII(blink::switches::kConditionalFocusWindowMs, "5000"); + command_line->AppendSwitch(switches::kUseGpuInTests); } WebContents* OpenTestPageInNewTab(const std::string& test_url) {
diff --git a/chrome/browser/media/webrtc/region_capture_browsertest.cc b/chrome/browser/media/webrtc/region_capture_browsertest.cc index f28a3af..c699d74 100644 --- a/chrome/browser/media/webrtc/region_capture_browsertest.cc +++ b/chrome/browser/media/webrtc/region_capture_browsertest.cc
@@ -33,6 +33,7 @@ #include "content/public/test/prerender_test_util.h" #include "testing/gmock/include/gmock/gmock-matchers.h" #include "third_party/blink/public/common/features.h" +#include "ui/gl/gl_switches.h" // TODO(crbug.com/1215089): Enable this test suite on Lacros. #if !BUILDFLAG(IS_CHROMEOS_LACROS) @@ -293,6 +294,7 @@ void SetUpCommandLine(base::CommandLine* command_line) override { command_line->AppendSwitch( switches::kEnableExperimentalWebPlatformFeatures); + command_line->AppendSwitch(switches::kUseGpuInTests); command_line_ = command_line; }
diff --git a/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc b/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc index 78a9a6c6..d430468a 100644 --- a/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc +++ b/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc
@@ -39,6 +39,7 @@ #include "content/public/test/browser_test_utils.h" #include "media/base/media_switches.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "ui/gl/gl_switches.h" namespace { static const char kMainWebrtcTestHtmlPage[] = "/webrtc/webrtc_jsep01_test.html"; @@ -231,6 +232,7 @@ command_line->AppendSwitchASCII(switches::kAutoSelectDesktopCaptureSource, "Entire screen"); command_line->AppendSwitch(switches::kEnableUserMediaScreenCapturing); + command_line->AppendSwitch(switches::kUseGpuInTests); } protected:
diff --git a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc index f3e8c04..e520684 100644 --- a/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc +++ b/chrome/browser/media/webrtc/webrtc_getdisplaymedia_browsertest.cc
@@ -44,6 +44,7 @@ #include "third_party/abseil-cpp/absl/types/optional.h" #include "third_party/blink/public/common/features.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/gl/gl_switches.h" #if BUILDFLAG(IS_MAC) #include "base/mac/mac_util.h" @@ -414,6 +415,7 @@ switches::kUseFakeDeviceForMediaStream, base::StringPrintf("display-media-type=%s", test_config_.display_surface)); + command_line->AppendSwitch(switches::kUseGpuInTests); } bool PreferCurrentTab() const override { @@ -587,6 +589,7 @@ switches::kEnableExperimentalWebPlatformFeatures); command_line->AppendSwitchASCII( switches::kAutoSelectTabCaptureSourceByTitle, kAppWindowTitle); + command_line->AppendSwitch(switches::kUseGpuInTests); } void SetUpOnMainThread() override { @@ -652,6 +655,7 @@ switches::kEnableExperimentalWebPlatformFeatures); command_line->AppendSwitchASCII( switches::kAutoSelectTabCaptureSourceByTitle, kSameOriginRenamedTitle); + command_line->AppendSwitch(switches::kUseGpuInTests); } void SetUpOnMainThread() override { @@ -824,6 +828,7 @@ switches::kUseFakeDeviceForMediaStream, base::StrCat({"display-media-type=", DisplaySurfaceTypeAsString(display_surface_type_)})); + command_line->AppendSwitch(switches::kUseGpuInTests); } std::string GetVideoTrackType() { @@ -1120,6 +1125,8 @@ switches::kEnableExperimentalWebPlatformFeatures); command_line->AppendSwitchASCII( switches::kAutoSelectTabCaptureSourceByTitle, kCapturedTabTitle); + command_line->AppendSwitch(switches::kUseGpuInTests); + if (!user_shared_audio_) { command_line->AppendSwitch(switches::kScreenCaptureAudioDefaultUnchecked); }
diff --git a/chrome/browser/page_load_metrics/observers/prefetch_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/prefetch_page_load_metrics_observer_unittest.cc index ca4d837..fff0b08 100644 --- a/chrome/browser/page_load_metrics/observers/prefetch_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/prefetch_page_load_metrics_observer_unittest.cc
@@ -99,7 +99,8 @@ bool in_main_frame_ = true; }; -TEST_F(PrefetchPageLoadMetricsObserverTest, DontRecordForNonHttp) { +// TODO(https://crbug.com/1426914): Fix and enable this test. +TEST_F(PrefetchPageLoadMetricsObserverTest, DISABLED_DontRecordForNonHttp) { set_navigation_url(GURL("chrome://version")); StartTest();
diff --git a/chrome/browser/password_manager/affiliation_service_factory.cc b/chrome/browser/password_manager/affiliation_service_factory.cc index 1630ee5..91411f1 100644 --- a/chrome/browser/password_manager/affiliation_service_factory.cc +++ b/chrome/browser/password_manager/affiliation_service_factory.cc
@@ -19,12 +19,7 @@ AffiliationServiceFactory::AffiliationServiceFactory() : ProfileKeyedServiceFactory( "AffiliationService", - ProfileSelections::Builder() - .WithRegular(ProfileSelection::kOriginalOnly) - // TODO(crbug.com/1418376): Check if this service is needed in - // Guest mode. - .WithGuest(ProfileSelection::kOriginalOnly) - .Build()) {} + ProfileSelections::BuildRedirectedInIncognitoNonExperimental()) {} AffiliationServiceFactory::~AffiliationServiceFactory() = default;
diff --git a/chrome/browser/permissions/permission_context_base_permissions_policy_unittest.cc b/chrome/browser/permissions/permission_context_base_permissions_policy_unittest.cc index f6139b4..2c5b7e0 100644 --- a/chrome/browser/permissions/permission_context_base_permissions_policy_unittest.cc +++ b/chrome/browser/permissions/permission_context_base_permissions_policy_unittest.cc
@@ -66,7 +66,9 @@ std::vector({blink::OriginWithPossibleWildcards( url::Origin::Create(GURL(origin)), /*has_subdomain_wildcard=*/false)}), - false, false); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false); } content::RenderFrameHost* result = content::RenderFrameHostTester::For(parent)->AppendChildWithPolicy( @@ -92,7 +94,9 @@ /*has_subdomain_wildcard=*/false); } navigation->SetPermissionsPolicyHeader( - {{feature, parsed_origins, false, false}}); + {{feature, parsed_origins, /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}); navigation->Commit(); *rfh = navigation->GetFinalRenderFrameHost(); }
diff --git a/chrome/browser/policy/test/policy_certs_browsertest.cc b/chrome/browser/policy/test/policy_certs_browsertest.cc index e8a3451..317b6c81 100644 --- a/chrome/browser/policy/test/policy_certs_browsertest.cc +++ b/chrome/browser/policy/test/policy_certs_browsertest.cc
@@ -563,48 +563,10 @@ ash::NetworkCertLoader::Get()->authority_certs())); } -// Test that the lock screen profile does not use the policy provided custom -// trusted anchors of the primary profile by default (i.e. if the -// PolicyProvidedTrustAnchorsAllowedAtLockScreen flag is disabled). -IN_PROC_BROWSER_TEST_F(PolicyProvidedCertsRegularUserTest, - LockScreenPrimaryProfileCertsFlagDisabled) { - ash::ScreenLockerTester locker; - locker.Lock(); - // Showing the reauth dialog will create the lock screen profile. - ash::LockScreenReauthDialogTestHelper::ShowDialogAndWait(); - ASSERT_THAT(ash::ProfileHelper::GetLockScreenProfile(), NotNull()); - - // Set policy provided trusted anchors on the primary profile. - user_policy_certs_helper_.SetRootCertONCUserPolicy( - browser()->profile(), - multi_profile_policy_helper_.policy_for_profile_1()); - - EXPECT_EQ(net::OK, - VerifyTestServerCert(browser()->profile(), - user_policy_certs_helper_.server_cert())); - // Verify that the lock screen can access the policy provided certs. - EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, - VerifyTestServerCert(ash::ProfileHelper::GetLockScreenProfile(), - user_policy_certs_helper_.server_cert())); -} - -class PolicyProvidedCertsLockScreenFeatureTest - : public PolicyProvidedCertsRegularUserTest { - protected: - PolicyProvidedCertsLockScreenFeatureTest() { - feature_list_.InitAndEnableFeature( - ash::features::kPolicyProvidedTrustAnchorsAllowedAtLockScreen); - } - ~PolicyProvidedCertsLockScreenFeatureTest() override = default; - - private: - base::test::ScopedFeatureList feature_list_; -}; - // Test that the lock screen profile uses the policy provided custom trusted // anchors of the primary profile when the // `PolicyProvidedTrustAnchorsAllowedAtLockScreen` flag is enabled. -IN_PROC_BROWSER_TEST_F(PolicyProvidedCertsLockScreenFeatureTest, +IN_PROC_BROWSER_TEST_F(PolicyProvidedCertsRegularUserTest, LockScreenPrimaryProfileCerts) { ash::ScreenLockerTester locker; locker.Lock(); @@ -628,7 +590,7 @@ // Test that the lock screen profile doesn't use the policy provided custom // trusted anchors of a secondary profile. -IN_PROC_BROWSER_TEST_F(PolicyProvidedCertsLockScreenFeatureTest, +IN_PROC_BROWSER_TEST_F(PolicyProvidedCertsRegularUserTest, LockScreenSecondaryProfileCerts) { ash::ScreenLockerTester locker; locker.Lock(); @@ -649,6 +611,44 @@ user_policy_certs_helper_.server_cert())); } +class PolicyProvidedCertsLockScreenFeatureTest + : public PolicyProvidedCertsRegularUserTest { + protected: + PolicyProvidedCertsLockScreenFeatureTest() { + feature_list_.InitAndDisableFeature( + ash::features::kPolicyProvidedTrustAnchorsAllowedAtLockScreen); + } + ~PolicyProvidedCertsLockScreenFeatureTest() override = default; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +// Test that the lock screen profile does not use the policy provided custom +// trusted anchors of the primary profile if the +// PolicyProvidedTrustAnchorsAllowedAtLockScreen flag is disabled. +IN_PROC_BROWSER_TEST_F(PolicyProvidedCertsLockScreenFeatureTest, + LockScreenPrimaryProfileCertsFlagDisabled) { + ash::ScreenLockerTester locker; + locker.Lock(); + // Showing the reauth dialog will create the lock screen profile. + ash::LockScreenReauthDialogTestHelper::ShowDialogAndWait(); + ASSERT_THAT(ash::ProfileHelper::GetLockScreenProfile(), NotNull()); + + // Set policy provided trusted anchors on the primary profile. + user_policy_certs_helper_.SetRootCertONCUserPolicy( + browser()->profile(), + multi_profile_policy_helper_.policy_for_profile_1()); + + EXPECT_EQ(net::OK, + VerifyTestServerCert(browser()->profile(), + user_policy_certs_helper_.server_cert())); + // Verify that the lock screen can access the policy provided certs. + EXPECT_EQ(net::ERR_CERT_AUTHORITY_INVALID, + VerifyTestServerCert(ash::ProfileHelper::GetLockScreenProfile(), + user_policy_certs_helper_.server_cert())); +} + #endif // BUILDFLAG(IS_CHROMEOS_ASH) } // namespace
diff --git a/chrome/browser/preferences/BUILD.gn b/chrome/browser/preferences/BUILD.gn index b520755..d6ee9b2 100644 --- a/chrome/browser/preferences/BUILD.gn +++ b/chrome/browser/preferences/BUILD.gn
@@ -42,6 +42,7 @@ "//components/offline_pages/core/prefetch/prefetch_prefs.cc", "//components/password_manager/core/common/password_manager_pref_names.cc", "//components/payments/core/payment_prefs.cc", + "//components/policy/core/common/policy_pref_names.cc", "//components/privacy_sandbox/privacy_sandbox_prefs.cc", "//components/safe_browsing/core/common/safe_browsing_prefs.cc", "//components/signin/public/base/signin_pref_names.cc",
diff --git a/chrome/browser/prefs/incognito_mode_prefs.cc b/chrome/browser/prefs/incognito_mode_prefs.cc index 0ee66fd5..dc0fc7f 100644 --- a/chrome/browser/prefs/incognito_mode_prefs.cc +++ b/chrome/browser/prefs/incognito_mode_prefs.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" @@ -54,15 +55,16 @@ // static void IncognitoModePrefs::SetAvailability(PrefService* prefs, const Availability availability) { - prefs->SetInteger(prefs::kIncognitoModeAvailability, + prefs->SetInteger(policy::policy_prefs::kIncognitoModeAvailability, static_cast<int>(availability)); } // static void IncognitoModePrefs::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { - registry->RegisterIntegerPref(prefs::kIncognitoModeAvailability, - static_cast<int>(kDefaultAvailability)); + registry->RegisterIntegerPref( + policy::policy_prefs::kIncognitoModeAvailability, + static_cast<int>(kDefaultAvailability)); #if BUILDFLAG(IS_ANDROID) registry->RegisterBooleanPref(prefs::kIncognitoReauthenticationForAndroid, false); @@ -124,7 +126,8 @@ const PrefService* pref_service, GetAvailabilityMode mode) { DCHECK(pref_service); - int pref_value = pref_service->GetInteger(prefs::kIncognitoModeAvailability); + int pref_value = pref_service->GetInteger( + policy::policy_prefs::kIncognitoModeAvailability); Availability result = kDefaultAvailability; bool valid = IntToAvailability(pref_value, &result); DCHECK(valid);
diff --git a/chrome/browser/prefs/incognito_mode_prefs_unittest.cc b/chrome/browser/prefs/incognito_mode_prefs_unittest.cc index 5ab9251..de550b47 100644 --- a/chrome/browser/prefs/incognito_mode_prefs_unittest.cc +++ b/chrome/browser/prefs/incognito_mode_prefs_unittest.cc
@@ -5,7 +5,7 @@ #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "base/test/gtest_util.h" -#include "chrome/common/pref_names.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/sync_preferences/testing_pref_service_syncable.h" #include "testing/gtest/include/gtest/gtest.h" @@ -38,19 +38,19 @@ } TEST_F(IncognitoModePrefsTest, GetAvailability) { - prefs_.SetUserPref(prefs::kIncognitoModeAvailability, + prefs_.SetUserPref(policy::policy_prefs::kIncognitoModeAvailability, std::make_unique<base::Value>(static_cast<int>( IncognitoModePrefs::Availability::kEnabled))); EXPECT_EQ(IncognitoModePrefs::Availability::kEnabled, IncognitoModePrefs::GetAvailability(&prefs_)); - prefs_.SetUserPref(prefs::kIncognitoModeAvailability, + prefs_.SetUserPref(policy::policy_prefs::kIncognitoModeAvailability, std::make_unique<base::Value>(static_cast<int>( IncognitoModePrefs::Availability::kDisabled))); EXPECT_EQ(IncognitoModePrefs::Availability::kDisabled, IncognitoModePrefs::GetAvailability(&prefs_)); - prefs_.SetUserPref(prefs::kIncognitoModeAvailability, + prefs_.SetUserPref(policy::policy_prefs::kIncognitoModeAvailability, std::make_unique<base::Value>(static_cast<int>( IncognitoModePrefs::Availability::kForced))); EXPECT_EQ(IncognitoModePrefs::Availability::kForced, @@ -60,7 +60,7 @@ typedef IncognitoModePrefsTest IncognitoModePrefsDeathTest; TEST_F(IncognitoModePrefsDeathTest, GetAvailabilityBadValue) { - prefs_.SetUserPref(prefs::kIncognitoModeAvailability, + prefs_.SetUserPref(policy::policy_prefs::kIncognitoModeAvailability, std::make_unique<base::Value>(-1)); EXPECT_DCHECK_DEATH({ IncognitoModePrefs::Availability availability =
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc b/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc index 1848ade..4c0e2f5d 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/search_preload_unified_browsertest.cc
@@ -20,7 +20,6 @@ #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service.h" #include "chrome/browser/preloading/prefetch/search_prefetch/search_prefetch_service_factory.h" #include "chrome/browser/preloading/prefetch/search_prefetch/search_preload_test_response_utils.h" -#include "chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h" #include "chrome/browser/preloading/prerender/prerender_manager.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_service_factory.h" @@ -1644,9 +1643,10 @@ base::test::ScopedFeatureList scoped_feature_list_; }; -// Tests cancelling prerenders should not delete the prefetched responses. +// Tests prerender is cancelled after SearchPrefetchService cancels prefetch +// requests. IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedFallbackBrowserTest, - PrefetchSucceedAfterPrerenderFailed) { + FetchPrerenderFetch) { base::HistogramTester histogram_tester; const GURL kInitialUrl = embedded_test_server()->GetURL("/empty.html"); const GURL kNavigatedUrl = embedded_test_server()->GetURL("/title1.html"); @@ -1693,6 +1693,10 @@ GetCanonicalSearchURL(expected_prerender_url)); EXPECT_TRUE(prefetch_status.has_value()); + // TODO: Use another metric to trigger whether prerender takes a prefetched + // response. + + // Navigate away to flush the metrics. ASSERT_TRUE( content::NavigateToURL(GetActiveWebContents(), expected_prerender_url)); histogram_tester.ExpectUniqueSample( @@ -1700,8 +1704,8 @@ SearchPrefetchStatus::kPrefetchServedForRealNavigation, 1); } -// Tests that prefetched response can be served to prerender client -// successfully. +// Tests prerender is cancelled after SearchPrefetchService cancels prefetch +// requests. IN_PROC_BROWSER_TEST_F(SearchPreloadUnifiedFallbackBrowserTest, FetchPrerenderActivated) { base::HistogramTester histogram_tester; @@ -1737,16 +1741,12 @@ EXPECT_TRUE(prefetch_status.has_value()); EXPECT_NE(prefetch_status.value(), SearchPrefetchStatus::kPrerendered); + // TODO: Use another metric to trigger whether prerender takes a prefetched + // response. content::test::PrerenderHostObserver prerender_observer( *GetActiveWebContents(), expected_prerender_url); NavigateToPrerenderedResult(expected_prerender_url); prerender_observer.WaitForActivation(); - WaitForActivatedPageLoaded(); - histogram_tester.ExpectBucketCount( - "Omnibox.SearchPreload.ResponseDataReaderFinalStatus.Prerender", - StreamingSearchPrefetchURLLoader::ResponseReader:: - ResponseDataReaderStatus::kCompleted, - 1); } // Tests that the SearchSuggestionService can trigger prerendering if it @@ -1800,16 +1800,10 @@ expected_prerender_url); NavigateToPrerenderedResult(expected_prerender_url); prerender_observer.WaitForActivation(); - WaitForActivatedPageLoaded(); // No prerender requests went through network. EXPECT_EQ(1, prerender_helper().GetRequestCount(expected_prefetch_url)); EXPECT_EQ(0, prerender_helper().GetRequestCount(expected_prerender_url)); - histogram_tester.ExpectBucketCount( - "Omnibox.SearchPreload.ResponseDataReaderFinalStatus.Prerender", - StreamingSearchPrefetchURLLoader::ResponseReader:: - ResponseDataReaderStatus::kCompleted, - 1); } // Tests that once prefetch encountered error, prerender would be canceled as @@ -1857,11 +1851,12 @@ prerender_observer.WaitForDestroyed(); WaitUntilStatusChangesTo(GetCanonicalSearchURL(expected_prefetch_url), {SearchPrefetchStatus::kRequestFailed}); + // TODO(crbug.com/1400881): We should have another metric to track the + // cancellation reason. histogram_tester.ExpectUniqueSample( - "Omnibox.SearchPreload.ResponseDataReaderFinalStatus.Prerender", - StreamingSearchPrefetchURLLoader::ResponseReader:: - ResponseDataReaderStatus::kFailedWithErrorCode, - 1); + "Prerender.Experimental.PrerenderHostFinalStatus.Embedder_" + "DefaultSearchEngine", + /*SearchPrefetchStatus::kPrefetchServedForRealNavigation*/ 16, 1); } // Edge case: when the prerendering navigation is still reading from the cache, @@ -1931,11 +1926,6 @@ // Prerender should not retry the request. EXPECT_EQ(0, prerender_helper().GetRequestCount(expected_prerender_url)); EXPECT_EQ(1, prerender_helper().GetRequestCount(expected_prefetch_url)); - histogram_tester.ExpectUniqueSample( - "Omnibox.SearchPreload.ResponseDataReaderFinalStatus.Prerender", - StreamingSearchPrefetchURLLoader::ResponseReader:: - ResponseDataReaderStatus::kCompleted, - 1); } class NoCancelSearchPreloadUnifiedFallbackBrowserTest @@ -1965,7 +1955,7 @@ // prefetched result in another tab and activate the prefetched response // successfully. IN_PROC_BROWSER_TEST_F(NoCancelSearchPreloadUnifiedFallbackBrowserTest, - OpenPrefetchedResponseInBackgroundedTab) { + ServingToPrerenderingUntilCompletion) { base::HistogramTester histogram_tester; set_service_deferral_type( SearchPreloadTestResponseDeferralType::kDeferChunkedResponseBody); @@ -2017,7 +2007,6 @@ ui::PAGE_TRANSITION_FROM_ADDRESS_BAR), /*is_renderer_initiated=*/false)); WaitUntilStatusChangesTo(GetCanonicalSearchURL(expected_prerender_url), {}); - // TODO(crbug.com/1423259): Ideally we should open the tab with the // prerendered result. prerender_observer.WaitForDestroyed(); @@ -2055,17 +2044,6 @@ EXPECT_TRUE(base::Contains(prefetch_inner_html, "PREFETCH")); EXPECT_EQ(0, prerender_helper().GetRequestCount(expected_prerender_url)); EXPECT_EQ(2, prerender_helper().GetRequestCount(expected_prefetch_url)); - - histogram_tester.ExpectBucketCount( - "Omnibox.SearchPreload.ResponseDataReaderFinalStatus.Prerender", - StreamingSearchPrefetchURLLoader::ResponseReader:: - ResponseDataReaderStatus::kDataWritingFailure, - 1); - histogram_tester.ExpectBucketCount( - "Omnibox.SearchPreload.ResponseDataReaderFinalStatus.Prerender", - StreamingSearchPrefetchURLLoader::ResponseReader:: - ResponseDataReaderStatus::kCompleted, - 1); } #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc b/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc index fa0d3aa..0a4aed6 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc +++ b/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
@@ -21,7 +21,6 @@ #include "chrome/browser/profiles/profile.h" #include "content/public/browser/storage_partition.h" #include "mojo/public/c/system/data_pipe.h" -#include "net/base/net_errors.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" #include "net/traffic_annotation/network_traffic_annotation.h" @@ -85,11 +84,6 @@ const network::URLLoaderCompletionStatus& status) { DCHECK(!url_loader_completion_status_); url_loader_completion_status_ = status; - if (url_loader_completion_status_->error_code != net::OK) { - // TODO(https://crbug.com/1400881): This status should only be kStarted - // after discarding the prerendered page upon pipeline creation failure. - status_ = ResponseDataReaderStatus::kFailedWithErrorCode; - } MaybeSendCompletionSignal(); } @@ -103,8 +97,6 @@ // TODO(https://crbug.com/1400881): Discard prerender. return; } - CHECK_EQ(status_, ResponseDataReaderStatus::kCreated); - status_ = ResponseDataReaderStatus::kStarted; forwarding_client_->OnReceiveResponse(resource_response->Clone(), std::move(consumer_handle), /*cached_metadata=*/absl::nullopt); @@ -128,9 +120,7 @@ } if (result != MOJO_RESULT_OK) { - CHECK_EQ(status_, ResponseDataReaderStatus::kStarted); - // This case is usually caused by the client stopping loading. - status_ = ResponseDataReaderStatus::kDataWritingFailure; + // Failed it; return; } @@ -158,49 +148,12 @@ return; } if (producer_handle_) { - if (url_loader_completion_status_->error_code == net::OK) { - CHECK_EQ(status_, ResponseDataReaderStatus::kStarted); - status_ = ResponseDataReaderStatus::kCompleted; - } forwarding_client_->OnComplete(*url_loader_completion_status_); } producer_handle_.reset(); } -void StreamingSearchPrefetchURLLoader::ResponseReader::OnDestroyed( - bool canceled_by_client) { - switch (status_) { - // Used to track the data pipe construction error. Do not care about client. - case ResponseDataReaderStatus::kCreated: - // Has completed serving. - case ResponseDataReaderStatus::kCompleted: - // For tracking reader failures. - case ResponseDataReaderStatus::kFailedWithErrorCode: - case ResponseDataReaderStatus::kDataWritingFailure: - // Has recorded the reason. - case ResponseDataReaderStatus::kCanceledByClient: - case ResponseDataReaderStatus::kCanceledByLoader: - return; - // The `StreamingSearchPrefetchURLLoader` is destroyed, so this instance - // is destroyed. - case ResponseDataReaderStatus::kStarted: - status_ = canceled_by_client - ? ResponseDataReaderStatus::kCanceledByClient - : ResponseDataReaderStatus::kCanceledByLoader; - return; - } -} - -StreamingSearchPrefetchURLLoader::ResponseReader::~ResponseReader() { - // Always ensure we recorded something on destruction. - OnDestroyed(/*canceled_by_client=*/false); - - // TODO(crbug.com/1400881): For now prerender is the only use case. After - // refactoring it should specify the client type. - base::UmaHistogramEnumeration( - "Omnibox.SearchPreload.ResponseDataReaderFinalStatus.Prerender", status_); -} - +StreamingSearchPrefetchURLLoader::ResponseReader::~ResponseReader() = default; void StreamingSearchPrefetchURLLoader::ResponseReader::FollowRedirect( const std::vector<std::string>& removed_headers, const net::HttpRequestHeaders& modified_headers, @@ -381,9 +334,6 @@ mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client) { DCHECK(prerender_utils::SearchPreloadShareableCacheIsEnabled()); DCHECK(streaming_prefetch_request_); - if (response_reader_for_prerender_) { - response_reader_for_prerender_->OnDestroyed(/* canceled_by_client=*/false); - } response_reader_for_prerender_ = std::make_unique<ResponseReader>( std::move(receiver), std::move(forwarding_client), base::BindOnce( @@ -399,8 +349,6 @@ void StreamingSearchPrefetchURLLoader::OnPrerenderForwardingDisconnect() { DCHECK(prerender_utils::SearchPreloadShareableCacheIsEnabled()); - DCHECK(response_reader_for_prerender_); - response_reader_for_prerender_->OnDestroyed(/*canceled_by_client=*/true); response_reader_for_prerender_.reset(); if (self_pointer_) { MaybeDeleteItself(); @@ -667,10 +615,6 @@ OnForwardingComplete(); return; } - status_ = status; - if (response_reader_for_prerender_) { - response_reader_for_prerender_->OnStatusCodeReady(status); - } if (streaming_prefetch_request_) { DCHECK(!forwarding_client_); @@ -682,6 +626,11 @@ return; } } + + status_ = status; + if (response_reader_for_prerender_) { + response_reader_for_prerender_->OnStatusCodeReady(status); + } } void StreamingSearchPrefetchURLLoader::RunEventQueue() {
diff --git a/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h b/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h index e756b74..2bbf3f54 100644 --- a/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h +++ b/chrome/browser/preloading/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
@@ -39,29 +39,6 @@ // `StreamingSearchPrefetchURLLoader`'s data cache. class ResponseReader : public network::mojom::URLLoader { public: - // These values are persisted to logs. Entries should not be renumbered and - // numeric values should never be reused. Recorded as - // SearchPrefetchResponseDataReaderStatus in logs. - enum class ResponseDataReaderStatus { - kCreated = 0, - // After this reader built a data pipe with the URLLoader that it is - // serving to successfully. - kStarted = 1, - // For a success serving case. - kCompleted = 2, - // Its `StreamingSearchPrefetchURLLoader` failed to read response from the - // internet successfully. - kFailedWithErrorCode = 3, - // It failed to push data to its client. - kDataWritingFailure = 4, - // The client is destroyed, so this instance is destroyed. - kCanceledByClient = 5, - // The `StreamingSearchPrefetchURLLoader` is destroyed, so this instance - // is destroyed. - kCanceledByLoader = 6, - kMaxValue = kCanceledByLoader, - }; - ResponseReader( mojo::PendingReceiver<network::mojom::URLLoader> forward_receiver, mojo::PendingRemote<network::mojom::URLLoaderClient> forwarding_client, @@ -95,7 +72,6 @@ void OnResponseDataComplete(int bytes_of_raw_data_to_transfer, const std::string& response_body); void OnStatusCodeReady(const network::URLLoaderCompletionStatus& status); - void OnDestroyed(bool canceled_by_client); private: // Checks if all data have be pushed to its consumer and the corresponding @@ -113,9 +89,6 @@ // Set to -1 when the URLLoader has not drained all data. int complete_size_bytes_to_transfer_ = -1; - // Tracking the current status. - ResponseDataReaderStatus status_ = ResponseDataReaderStatus::kCreated; - // Data pipe for pushing the received response to the client. mojo::ScopedDataPipeProducerHandle producer_handle_; std::unique_ptr<mojo::SimpleWatcher> handle_watcher_; @@ -284,7 +257,7 @@ // the navigation stack. raw_ptr<SearchPrefetchRequest> streaming_prefetch_request_; - // Whether we are serving from |body_content_|. + // Whether we are serving from |bdoy_content_|. bool serving_from_data_ = false; // The status returned from |network_url_loader_|.
diff --git a/chrome/browser/printing/system_access_process_print_browsertest.cc b/chrome/browser/printing/system_access_process_print_browsertest.cc index 810eb399..960fc92 100644 --- a/chrome/browser/printing/system_access_process_print_browsertest.cc +++ b/chrome/browser/printing/system_access_process_print_browsertest.cc
@@ -812,7 +812,7 @@ #if BUILDFLAG(ENABLE_OOP_PRINTING) -IN_PROC_BROWSER_TEST_P(SystemAccessProcessServicePrintBrowserTest, +IN_PROC_BROWSER_TEST_F(SystemAccessProcessSandboxedServicePrintBrowserTest, StartPrinting) { AddPrinter("printer1"); SetPrinterNameForSubsequentContexts("printer1"); @@ -867,7 +867,7 @@ #endif // BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_CUPS) } -IN_PROC_BROWSER_TEST_P(SystemAccessProcessServicePrintBrowserTest, +IN_PROC_BROWSER_TEST_F(SystemAccessProcessSandboxedServicePrintBrowserTest, StartPrintingMultipage) { AddPrinter("printer1"); SetPrinterNameForSubsequentContexts("printer1"); @@ -1353,7 +1353,7 @@ EXPECT_EQ(print_job_destruction_count(), 1); } -IN_PROC_BROWSER_TEST_P(SystemAccessProcessServicePrintBrowserTest, +IN_PROC_BROWSER_TEST_F(SystemAccessProcessSandboxedServicePrintBrowserTest, StartBasicPrint) { AddPrinter("printer1"); SetPrinterNameForSubsequentContexts("printer1"); @@ -1586,7 +1586,7 @@ EXPECT_EQ(print_job_construction_count(), 0); } -IN_PROC_BROWSER_TEST_P(SystemAccessProcessServicePrintBrowserTest, +IN_PROC_BROWSER_TEST_F(SystemAccessProcessSandboxedServicePrintBrowserTest, StartBasicPrintConcurrent) { ASSERT_TRUE(embedded_test_server()->Started()); GURL url(embedded_test_server()->GetURL("/printing/test3.html")); @@ -1622,7 +1622,7 @@ } #if BUILDFLAG(ENABLE_PRINT_PREVIEW) -IN_PROC_BROWSER_TEST_P(SystemAccessProcessServicePrintBrowserTest, +IN_PROC_BROWSER_TEST_F(SystemAccessProcessSandboxedServicePrintBrowserTest, SystemPrintFromPrintPreviewConcurrent) { AddPrinter("printer1"); SetPrinterNameForSubsequentContexts("printer1");
diff --git a/chrome/browser/profiles/incognito_mode_policy_handler.cc b/chrome/browser/profiles/incognito_mode_policy_handler.cc index f1d349f..844cdd3 100644 --- a/chrome/browser/profiles/incognito_mode_policy_handler.cc +++ b/chrome/browser/profiles/incognito_mode_policy_handler.cc
@@ -10,10 +10,10 @@ #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" -#include "chrome/common/pref_names.h" #include "chrome/credential_provider/common/gcp_strings.h" #include "components/policy/core/browser/policy_error_map.h" #include "components/policy/core/common/policy_map.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/policy/policy_constants.h" #include "components/prefs/pref_value_map.h" #include "components/strings/grit/components_strings.h" @@ -80,14 +80,14 @@ IncognitoModePrefs::Availability availability_enum_value; if (IncognitoModePrefs::IntToAvailability(availability->GetInt(), &availability_enum_value)) { - prefs->SetInteger(prefs::kIncognitoModeAvailability, + prefs->SetInteger(policy::policy_prefs::kIncognitoModeAvailability, static_cast<int>(availability_enum_value)); } } else if (deprecated_enabled) { // If kIncognitoModeAvailability is not specified, check the obsolete // kIncognitoEnabled. prefs->SetInteger( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, static_cast<int>(deprecated_enabled->GetBool() ? IncognitoModePrefs::Availability::kEnabled : IncognitoModePrefs::Availability::kDisabled));
diff --git a/chrome/browser/profiles/incognito_mode_policy_handler_unittest.cc b/chrome/browser/profiles/incognito_mode_policy_handler_unittest.cc index 9817753..6ceeaf7 100644 --- a/chrome/browser/profiles/incognito_mode_policy_handler_unittest.cc +++ b/chrome/browser/profiles/incognito_mode_policy_handler_unittest.cc
@@ -6,9 +6,9 @@ #include "base/memory/ptr_util.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" -#include "chrome/common/pref_names.h" #include "components/policy/core/browser/configuration_policy_pref_store.h" #include "components/policy/core/browser/configuration_policy_pref_store_test.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/policy/core/common/policy_types.h" #include "components/policy/policy_constants.h" @@ -50,7 +50,8 @@ void VerifyValues(IncognitoModePrefs::Availability availability) { const base::Value* value = nullptr; - EXPECT_TRUE(store_->GetValue(prefs::kIncognitoModeAvailability, &value)); + EXPECT_TRUE(store_->GetValue( + policy::policy_prefs::kIncognitoModeAvailability, &value)); EXPECT_EQ(base::Value(static_cast<int>(availability)), *value); } }; @@ -83,7 +84,8 @@ NoObsoletePolicyAndNoIncognitoAvailability) { SetPolicies(INCOGNITO_ENABLED_UNKNOWN, kIncognitoModeAvailabilityNotSet); const base::Value* value = nullptr; - EXPECT_FALSE(store_->GetValue(prefs::kIncognitoModeAvailability, &value)); + EXPECT_FALSE(store_->GetValue( + policy::policy_prefs::kIncognitoModeAvailability, &value)); } // Checks that if the obsolete IncognitoEnabled policy is set, if sets
diff --git a/chrome/browser/resources/new_tab_page/app.html b/chrome/browser/resources/new_tab_page/app.html index 60fbc56..6ebf410 100644 --- a/chrome/browser/resources/new_tab_page/app.html +++ b/chrome/browser/resources/new_tab_page/app.html
@@ -372,7 +372,8 @@ <dom-if if="[[lazyRender_]]" on-dom-change="onLazyRendered_"> <template> <template is="dom-if" if="[[shortcutsEnabled_]]"> - <cr-most-visited id="mostVisited" theme="[[theme_.mostVisited]]"> + <cr-most-visited id="mostVisited" theme="[[theme_.mostVisited]]" + single-row="[[singleRowShortcutsEnabled_]]"> </cr-most-visited> </template> <template is="dom-if" if="[[middleSlotPromoEnabled_]]">
diff --git a/chrome/browser/resources/new_tab_page/app.ts b/chrome/browser/resources/new_tab_page/app.ts index 1a79b5ce..f2ed4922 100644 --- a/chrome/browser/resources/new_tab_page/app.ts +++ b/chrome/browser/resources/new_tab_page/app.ts
@@ -229,6 +229,11 @@ value: () => loadTimeData.getBoolean('shortcutsEnabled'), }, + singleRowShortcutsEnabled_: { + type: Boolean, + value: () => loadTimeData.getBoolean('singleRowShortcutsEnabled'), + }, + modulesFreShown: { type: Boolean, reflectToAttribute: true,
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/suggest_tile.html b/chrome/browser/resources/new_tab_page/modules/history_clusters/suggest_tile.html index 4ea0ec6f..64778966 100644 --- a/chrome/browser/resources/new_tab_page/modules/history_clusters/suggest_tile.html +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/suggest_tile.html
@@ -52,7 +52,7 @@ .title { color: var(--color-new-tab-page-primary-foreground); - font-size: 14px; + font-size: var(--ntp-module-text-size); margin: auto 0; } </style>
diff --git a/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.html b/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.html index ef8b13a..f25890a0 100644 --- a/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.html +++ b/chrome/browser/resources/new_tab_page/modules/history_clusters/tile.html
@@ -75,27 +75,34 @@ } #title { + -webkit-box-orient: vertical; color: var(--color-new-tab-page-primary-foreground); - font-size: 16px; + display: -webkit-box; + font-size: var(--ntp-module-text-size); + margin: 16px; + max-width: calc(100% - 32px); white-space: initial; } :host([large-format]) #title { + -webkit-line-clamp: 2; height: 48px; - max-width: 298px; - padding: 16px 16px 24px; + line-height: 24px; + margin-bottom: 28px; } :host([medium-format]) #title { - height: 60px; + -webkit-line-clamp: 4; + height: 80px; + line-height: 20px; + margin-inline-start: 8px; max-width: 184px; - padding: 18px 16px 32px 8px; } :host([small-format]) #title { - height: 60px; - max-width: 136px; - padding: 18px 16px 32px 16px; + -webkit-line-clamp: 4; + height: 80px; + line-height: 20px; } #info-container { @@ -103,18 +110,17 @@ display: flex; flex-direction: row; font-size: 11px; - margin-bottom: 24px; + height: 20px; margin-inline: 16px; } - :host([medium-format]) #info-container { - margin-bottom: 14px; - margin-inline-start: 8px; + :host([large-format]) #info-container { + margin-bottom: 24px; } - :host([small-format]) #info-container { - height: 20px; - margin-bottom: 14px; + :host([medium-format]) #info-container { + margin-bottom: 12px; + margin-inline-start: 8px; } #label,
diff --git a/chrome/browser/resources/password_manager/prefs/pref_toggle_button.html b/chrome/browser/resources/password_manager/prefs/pref_toggle_button.html index b7ee3cb..2b4ef91 100644 --- a/chrome/browser/resources/password_manager/prefs/pref_toggle_button.html +++ b/chrome/browser/resources/password_manager/prefs/pref_toggle_button.html
@@ -16,8 +16,8 @@ } #labelWrapper { - padding: var(--cr-section-vertical-padding) 0; margin-inline-end: var(--control-label-spacing); + padding: var(--cr-section-vertical-padding) 0; } </style> <div id="outerRow" noSubLabel$="[[!subLabel]]">
diff --git a/chrome/browser/resources/settings/chromeos/OWNERS b/chrome/browser/resources/settings/chromeos/OWNERS index f1a43124..08aadc4 100644 --- a/chrome/browser/resources/settings/chromeos/OWNERS +++ b/chrome/browser/resources/settings/chromeos/OWNERS
@@ -13,15 +13,15 @@ cowmoo@chromium.org # Subdir OWNERS can approve global changes related to their subdir. -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/crostini_page/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/device_page/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/guest_os/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/internet_page/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/keyboard_shortcut_banner/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/multidevice_page/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/nearby_share_page/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_apps_page/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_bluetooth_page/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_languages_page/OWNERS -per-file BUILD.gn,lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_printing_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/crostini_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/device_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/guest_os/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/internet_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/keyboard_shortcut_banner/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/multidevice_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/nearby_share_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_apps_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_apps_page/app_notifications_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_bluetooth_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_languages_page/OWNERS +per-file lazy_load.ts,os_settings.gni,os_settings.ts=file://chrome/browser/resources/settings/chromeos/os_printing_page/OWNERS
diff --git a/chrome/browser/resources/settings/chromeos/device_page/device_page.html b/chrome/browser/resources/settings/chromeos/device_page/device_page.html index 4ccf4bc..bfad43d 100644 --- a/chrome/browser/resources/settings/chromeos/device_page/device_page.html +++ b/chrome/browser/resources/settings/chromeos/device_page/device_page.html
@@ -110,7 +110,7 @@ <os-settings-subpage page-title="$i18n{pointingStickTitle}"> <settings-per-device-pointing-stick is-device-settings-split-enabled="[[isDeviceSettingsSplitEnabled_]]" - pointingSticks="[[pointingSticks]"> + pointing-sticks="[[pointingSticks]]"> </settings-per-device-pointing-stick> </os-settings-subpage> </template>
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.html index 01854b32..89edc658 100644 --- a/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.html +++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.html
@@ -17,6 +17,10 @@ padding-inline-start: var(--cr-section-indent-width); } + .indented { + margin-inline-start: 32px; + } + .settings-box { margin-inline-end: var(--cr-section-padding); padding-inline-end: 0; @@ -190,5 +194,19 @@ sub-label="$i18n{chromeVoxEventLogDescription}" on-click="onEventLogTap_" external embedded> </cr-link-row> + <template is="dom-if" if="[[prefs.settings.a11y.chromevox.enable_event_stream_logging.value]]"> + <div class="indented"> + <template is="dom-repeat" items="[[eventStreamFilters_]]"> + <settings-toggle-button + id="[[item]]" + class="settings-box" + pref="[[getEventStreamFilterPref_(item, prefs.settings.a11y.chromevox.event_stream_filters)]]" + label="[[item]]" + on-settings-boolean-control-change="onEventStreamFilterPrefChanged_" + no-set-pref> + </settings-toggle-button> + </template> + </div> + </template> </div> </iron-collapse>
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.ts b/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.ts index 852991b6..27d7782 100644 --- a/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.ts +++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/chromevox_subpage.ts
@@ -28,10 +28,16 @@ import {getTemplate} from './chromevox_subpage.html.js'; import {ChromeVoxSubpageBrowserProxy, ChromeVoxSubpageBrowserProxyImpl} from './chromevox_subpage_browser_proxy.js'; +export {SettingsToggleButtonElement} from '../../controls/settings_toggle_button.js'; + const SYSTEM_VOICE = 'chromeos_system_voice'; const CHROMEVOX_EXTENSION_ID = 'mndnfokpggljbaajbnioimlmbfngpief'; const GOOGLE_TTS_EXTENSION_ID = 'gjjabgpgjpampikjhjpfhneeoapjbjaf'; const ESPEAK_TTS_EXTENSION_ID = 'dakbfdmgjiabojdgbiljlhgjbokobjpg'; +const EVENT_STREAM_FILTERS_PREF_KEY = + 'settings.a11y.chromevox.event_stream_filters'; + +type EventStreamFiltersPrefValue = Record<string, boolean>; /** * Represents a voice as sent from the TTS Handler class. @@ -169,6 +175,70 @@ type: Boolean, value: false, }, + + /** + * Event stream filters list. Should match + * SettingsManager.EVENT_STREAM_FILTERS from settings_manager.js. + */ + eventStreamFilters_: { + readOnly: true, + type: Array, + value() { + return [ + 'activedescendantchanged', + 'alert', + 'ariaAttributeChanged', + 'autocorrectionOccured', + 'blur', + 'checkedStateChanged', + 'childrenChanged', + 'clicked', + 'documentSelectionChanged', + 'documentTitleChanged', + 'expandedChanged', + 'focus', + 'focusContext', + 'hide', + 'hitTestResult', + 'hover', + 'imageFrameUpdated', + 'invalidStatusChanged', + 'layoutComplete', + 'liveRegionChanged', + 'liveRegionCreated', + 'loadComplete', + 'locationChanged', + 'mediaStartedPlaying', + 'mediaStoppedPlaying', + 'menuEnd', + 'menuItemSelected', + 'menuListValueChanged', + 'menuPopupEnd', + 'menuPopupStart', + 'menuStart', + 'mouseCanceled', + 'mouseDragged', + 'mouseMoved', + 'mousePressed', + 'mouseReleased', + 'rowCollapsed', + 'rowCountChanged', + 'rowExpanded', + 'scrollPositionChanged', + 'scrolledToAnchor', + 'selectedChildrenChanged', + 'selection', + 'selectionAdd', + 'selectionRemove', + 'show', + 'stateChanged', + 'textChanged', + 'textSelectionChanged', + 'treeChanged', + 'valueInTextFieldChanged', + ]; + }, + }, }; } @@ -299,6 +369,34 @@ 'chrome-extension://' + CHROMEVOX_EXTENSION_ID + '/chromevox/log_page/log.html'); } + + private getEventStreamFilterPref_(eventStreamFilter: string): + chrome.settingsPrivate.PrefObject<boolean> { + return { + key: '', + type: chrome.settingsPrivate.PrefType.BOOLEAN, + value: Boolean(this.prefs) && + this.getPref<EventStreamFiltersPrefValue>( + EVENT_STREAM_FILTERS_PREF_KEY) + .value[eventStreamFilter], + }; + } + + /** + * When an event stream filter checkbox is checked, update the dictionary pref + * of event stream filter states. + */ + private onEventStreamFilterPrefChanged_(e: Event): void { + // Get all eventStreamFilters, set new filter state. + const filter = e.target as SettingsToggleButtonElement; + const eventStreamFilters = { + ...this + .getPref<EventStreamFiltersPrefValue>(EVENT_STREAM_FILTERS_PREF_KEY) + .value, + [filter.id]: filter.checked, + }; + this.setPrefValue(EVENT_STREAM_FILTERS_PREF_KEY, eventStreamFilters); + } } declare global {
diff --git a/chrome/browser/share/android/java/res/values/dimens.xml b/chrome/browser/share/android/java/res/values/dimens.xml index eaa06cd4..658d69f70 100644 --- a/chrome/browser/share/android/java/res/values/dimens.xml +++ b/chrome/browser/share/android/java/res/values/dimens.xml
@@ -23,4 +23,7 @@ <!-- IPH for Link Toggle --> <dimen name="toggle_iph_y_inset">8dp</dimen> + + <!-- Android share sheet --> + <dimen name="share_preview_favicon_size">32dp</dimen> </resources>
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java index 6611306..800e7bd 100644 --- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java +++ b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetController.java
@@ -5,6 +5,10 @@ package org.chromium.chrome.browser.share.android_share_sheet; import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.SystemClock; import android.text.TextUtils; import androidx.annotation.VisibleForTesting; @@ -12,17 +16,27 @@ import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.Callback; import org.chromium.base.Log; +import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.supplier.Supplier; +import org.chromium.chrome.R; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.share.ChromeCustomShareAction; import org.chromium.chrome.browser.share.ChromeShareExtras; +import org.chromium.chrome.browser.share.ShareContentTypeHelper; +import org.chromium.chrome.browser.share.ShareContentTypeHelper.ContentType; import org.chromium.chrome.browser.share.ShareHelper; import org.chromium.chrome.browser.share.share_sheet.ChromeOptionShareCallback; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.ui.favicon.FaviconHelper; +import org.chromium.chrome.browser.ui.favicon.FaviconUtils; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.components.browser_ui.share.ShareImageFileUtils; import org.chromium.components.browser_ui.share.ShareParams; +import org.chromium.url.GURL; + +import java.util.Set; /** * Share sheet controller used to display Android share sheet. @@ -95,10 +109,10 @@ Profile profile = mProfileSupplier.get(); boolean isIncognito = mTabModelSelectorSupplier.hasValue() && mTabModelSelectorSupplier.get().isIncognitoSelected(); + Activity activity = params.getWindow().getActivity().get(); ChromeCustomShareAction.Provider provider = null; if (showCustomActions) { - Activity activity = params.getWindow().getActivity().get(); boolean isInMultiWindow = ApiCompatibilityUtils.isInMultiWindowMode(activity); var actionProvider = new AndroidCustomActionProvider(params.getWindow().getActivity().get(), @@ -121,8 +135,49 @@ String imageUrlToShare = getImageUrlToShare(params, chromeShareExtras); params.setUrl(imageUrlToShare); } - ShareHelper.shareWithSystemShareSheetUi( - params, profile, chromeShareExtras.saveLastUsed(), provider); + if (!isLinkSharing(params, chromeShareExtras)) { + ShareHelper.shareWithSystemShareSheetUi( + params, profile, chromeShareExtras.saveLastUsed(), provider); + return; + } + + long iconPrepStartTime = SystemClock.elapsedRealtime(); + ChromeCustomShareAction.Provider finalProvider = provider; + preparePreviewFavicon(activity, profile, params.getUrl(), (uri) -> { + RecordHistogram.recordTimesHistogram("Sharing.PreparePreviewFaviconDuration", + SystemClock.elapsedRealtime() - iconPrepStartTime); + params.setPreviewImageUri(uri); + ShareHelper.shareWithSystemShareSheetUi( + params, profile, chromeShareExtras.saveLastUsed(), finalProvider); + }); + } + + private static void preparePreviewFavicon( + Context context, Profile profile, String pageUrl, Callback<Uri> onUriReady) { + int size = context.getResources().getDimensionPixelSize(R.dimen.share_preview_favicon_size); + FaviconHelper faviconHelper = new FaviconHelper(); + faviconHelper.getLocalFaviconImageForURL( + profile, new GURL(pageUrl), size, (Bitmap icon, GURL iconUrl) -> { + onFaviconRetrieved(context, icon, size, onUriReady); + }); + } + + private static void onFaviconRetrieved( + Context context, Bitmap bitmap, int size, Callback<Uri> onImageUriAvailable) { + // If bitmap is not provided, fallback to the globe placeholder icon. + if (bitmap == null) { + bitmap = FaviconUtils.createGenericFaviconBitmap(context, size); + } + String fileName = String.valueOf(System.currentTimeMillis()); + ShareImageFileUtils.generateTemporaryUriFromBitmap(fileName, bitmap, onImageUriAvailable); + } + + private static boolean isLinkSharing(ShareParams params, ChromeShareExtras chromeShareExtras) { + @ContentType + Set<Integer> contents = ShareContentTypeHelper.getContentTypes(params, chromeShareExtras); + return contents.contains(ContentType.LINK_PAGE_VISIBLE) + || contents.contains(ContentType.LINK_PAGE_NOT_VISIBLE) + || contents.contains(ContentType.LINK_AND_TEXT); } private static String getImageUrlToShare(
diff --git a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java index 1fe3bf6e..c46ac4c 100644 --- a/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java +++ b/chrome/browser/share/android/javatests/src/org/chromium/chrome/browser/share/android_share_sheet/AndroidShareSheetControllerUnitTest.java
@@ -5,21 +5,28 @@ package org.chromium.chrome.browser.share.android_share_sheet; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; import android.app.Activity; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.ComponentName; import android.content.Intent; +import android.graphics.Bitmap; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; import android.text.TextUtils; +import androidx.annotation.Nullable; import androidx.core.os.BuildCompat; import androidx.lifecycle.Lifecycle.State; import androidx.test.ext.junit.rules.ActivityScenarioRule; @@ -40,9 +47,11 @@ import org.robolectric.annotation.Implements; import org.robolectric.shadows.ShadowLooper; +import org.chromium.base.Callback; import org.chromium.base.ContextUtils; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.HistogramWatcher; import org.chromium.base.test.util.JniMocker; import org.chromium.base.test.util.PayloadCallbackHelper; import org.chromium.chrome.R; @@ -55,11 +64,15 @@ import org.chromium.chrome.browser.share.ShareHelper; import org.chromium.chrome.browser.share.android_share_sheet.AndroidShareSheetControllerUnitTest.ShadowBuildCompatForU; import org.chromium.chrome.browser.share.android_share_sheet.AndroidShareSheetControllerUnitTest.ShadowChooserActionHelper; +import org.chromium.chrome.browser.share.android_share_sheet.AndroidShareSheetControllerUnitTest.ShadowShareImageFileUtils; import org.chromium.chrome.browser.share.send_tab_to_self.SendTabToSelfAndroidBridgeJni; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.browser.ui.favicon.FaviconHelper; +import org.chromium.chrome.browser.ui.favicon.FaviconHelperJni; import org.chromium.chrome.test.util.browser.Features; import org.chromium.components.browser_ui.bottomsheet.BottomSheetController; +import org.chromium.components.browser_ui.share.ShareImageFileUtils; import org.chromium.components.browser_ui.share.ShareParams; import org.chromium.components.browser_ui.share.ShareParams.TargetChosenCallback; import org.chromium.components.feature_engagement.Tracker; @@ -69,7 +82,9 @@ import org.chromium.ui.base.IntentRequestTracker; import org.chromium.ui.base.TestActivity; import org.chromium.ui.base.WindowAndroid; +import org.chromium.url.GURL; import org.chromium.url.JUnitTestGURLs; +import org.chromium.url.ShadowGURL; /** * Test for {@link AndroidShareSheetController} and {@link AndroidCustomActionProvider}. @@ -77,12 +92,17 @@ @RunWith(BaseRobolectricTestRunner.class) @Features.DisableFeatures( {ChromeFeatureList.WEBNOTES_STYLIZE, ChromeFeatureList.SEND_TAB_TO_SELF_SIGNIN_PROMO}) +@Config(shadows = {ShadowShareImageFileUtils.class, ShadowGURL.class}) public class AndroidShareSheetControllerUnitTest { private static final String INTENT_EXTRA_CHOOSER_CUSTOM_ACTIONS = "android.intent.extra.CHOOSER_CUSTOM_ACTIONS"; private static final String KEY_CHOOSER_ACTION_ICON = "icon"; private static final String KEY_CHOOSER_ACTION_NAME = "name"; private static final String KEY_CHOOSER_ACTION_ACTION = "action"; + private static final Uri TEST_WEB_FAVICON_PREVIEW_URI = + Uri.parse("content://test.web.favicon.preview"); + private static final Uri TEST_FALLBACK_FAVICON_PREVIEW_URI = + Uri.parse("content://test.fallback.favicon.preview"); @Rule public ActivityScenarioRule<TestActivity> mActivityScenario = @@ -99,6 +119,8 @@ @Mock UserPrefsJni mMockUserPrefsJni; @Mock + FaviconHelperJni mMockFaviconHelperJni; + @Mock BottomSheetController mBottomSheetController; @Mock TabModelSelector mTabModelSelector; @@ -113,6 +135,7 @@ private WindowAndroid mWindow; private PayloadCallbackHelper<Tab> mPrintCallback; private AndroidShareSheetController mController; + private Bitmap mTestWebFavicon; @Before public void setup() { @@ -128,6 +151,12 @@ PrefService service = mock(PrefService.class); doReturn(service).when(mMockUserPrefsJni).get(mProfile); doReturn(true).when(service).getBoolean(Pref.PRINTING_ENABLED); + // Set up favicon helper. + mJniMocker.mock(FaviconHelperJni.TEST_HOOKS, mMockFaviconHelperJni); + doReturn(1L).when(mMockFaviconHelperJni).init(); + mTestWebFavicon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + ShadowShareImageFileUtils.sExpectedWebBitmap = mTestWebFavicon; + setFaviconToFetchForTest(mTestWebFavicon); mActivityScenario.getScenario().onActivity((activity) -> mActivity = activity); mActivityScenario.getScenario().moveToState(State.RESUMED); @@ -250,6 +279,68 @@ sharingIntent.getStringExtra(Intent.EXTRA_TEXT)); } + @Test + public void shareTextWithPreviewFavicon() { + HistogramWatcher watcher = + HistogramWatcher.newSingleRecordWatcher("Sharing.PreparePreviewFaviconDuration"); + + ShareParams params = new ShareParams.Builder(mWindow, "title", JUnitTestGURLs.EXAMPLE_URL) + .setFileContentType("text/plain") + .setBypassFixingDomDistillerUrl(true) + .build(); + ChromeShareExtras chromeShareExtras = new ChromeShareExtras.Builder().build(); + mController.showShareSheet(params, chromeShareExtras, 1L); + + Intent intent = Shadows.shadowOf((Activity) mActivity).peekNextStartedActivity(); + Assert.assertNotNull("Preview clip data should not be null.", intent.getClipData()); + Assert.assertEquals("Image preview Uri is null.", TEST_WEB_FAVICON_PREVIEW_URI, + intent.getClipData().getItemAt(0).getUri()); + watcher.assertExpected(); + } + + @Test + public void shareTextWithPreviewWithFallbackFavicon() { + // Assume favicon is not available for this test. + setFaviconToFetchForTest(null); + + ShareParams params = new ShareParams.Builder(mWindow, "title", JUnitTestGURLs.EXAMPLE_URL) + .setFileContentType("text/plain") + .setBypassFixingDomDistillerUrl(true) + .build(); + ChromeShareExtras chromeShareExtras = new ChromeShareExtras.Builder().build(); + mController.showShareSheet(params, chromeShareExtras, 1L); + + Intent intent = Shadows.shadowOf((Activity) mActivity).peekNextStartedActivity(); + Assert.assertNotNull("Preview clip data should not be null.", intent.getClipData()); + Assert.assertEquals("Image preview Uri is not as expected.", + TEST_FALLBACK_FAVICON_PREVIEW_URI, intent.getClipData().getItemAt(0).getUri()); + } + + @Test + public void sharePlainTextDoesNotProvidePreview() { + ShareParams params = new ShareParams.Builder(mWindow, "", "") + .setFileContentType("text/plain") + .setText("text") + .setBypassFixingDomDistillerUrl(true) + .build(); + ChromeShareExtras chromeShareExtras = new ChromeShareExtras.Builder().build(); + mController.showShareSheet(params, chromeShareExtras, 1L); + + Intent intent = Shadows.shadowOf((Activity) mActivity).peekNextStartedActivity(); + Assert.assertNull("Preview clip data should be null.", intent.getClipData()); + verifyZeroInteractions(mMockFaviconHelperJni); + } + + private void setFaviconToFetchForTest(Bitmap favicon) { + doAnswer(invocation -> { + FaviconHelper.FaviconImageCallback callback = invocation.getArgument(4); + callback.onFaviconAvailable(favicon, GURL.emptyGURL()); + return null; + }) + .when(mMockFaviconHelperJni) + .getLocalFaviconImageForURL(anyLong(), eq(mProfile), any(), anyInt(), any()); + } + /** * Test implementation to build a ChooserAction. */ @@ -279,4 +370,20 @@ return true; } } + + // Shadow class to bypass actually saving the image as URL for this test. + @Implements(ShareImageFileUtils.class) + static class ShadowShareImageFileUtils { + static @Nullable Bitmap sExpectedWebBitmap; + + @Implementation + public static void generateTemporaryUriFromBitmap( + String fileName, Bitmap bitmap, Callback<Uri> callback) { + if (bitmap != null && bitmap.equals(sExpectedWebBitmap)) { + callback.onResult(TEST_WEB_FAVICON_PREVIEW_URI); + } else { + callback.onResult(TEST_FALLBACK_FAVICON_PREVIEW_URI); + } + } + } }
diff --git a/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc b/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc index b1637613..1431e09d 100644 --- a/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc +++ b/chrome/browser/signin/chromeos_mirror_account_consistency_browsertest.cc
@@ -12,11 +12,11 @@ #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h" #include "chrome/browser/ui/browser.h" -#include "chrome/common/pref_names.h" #include "chrome/test/base/ui_test_utils.h" #include "components/account_id/account_id.h" #include "components/google/core/common/google_switches.h" #include "components/network_session_configurator/common/network_switches.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" #include "components/signin/core/browser/signin_header_helper.h" #include "components/signin/public/base/signin_pref_names.h" @@ -139,7 +139,7 @@ // Incognito is always disabled for child accounts. PrefService* prefs = profile->GetPrefs(); prefs->SetInteger( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, static_cast<int>(IncognitoModePrefs::Availability::kDisabled)); ASSERT_EQ(1, signin::PROFILE_MODE_INCOGNITO_DISABLED);
diff --git a/chrome/browser/signin/header_modification_delegate_impl.cc b/chrome/browser/signin/header_modification_delegate_impl.cc index 19d59ea..e68d4a4e 100644 --- a/chrome/browser/signin/header_modification_delegate_impl.cc +++ b/chrome/browser/signin/header_modification_delegate_impl.cc
@@ -13,7 +13,7 @@ #include "chrome/browser/signin/chrome_signin_helper.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/sync/sync_service_factory.h" -#include "chrome/common/pref_names.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" #include "components/signin/public/base/signin_pref_names.h" #include "components/signin/public/identity_manager/account_info.h" @@ -95,7 +95,7 @@ identity_manager->FindExtendedAccountInfo(account).is_child_account; int incognito_mode_availability = - prefs->GetInteger(prefs::kIncognitoModeAvailability); + prefs->GetInteger(policy::policy_prefs::kIncognitoModeAvailability); #if BUILDFLAG(IS_ANDROID) incognito_mode_availability = incognito_enabled_
diff --git a/chrome/browser/supervised_user/supervised_user_pref_store.cc b/chrome/browser/supervised_user/supervised_user_pref_store.cc index 8e884073..36ba1db7 100644 --- a/chrome/browser/supervised_user/supervised_user_pref_store.cc +++ b/chrome/browser/supervised_user/supervised_user_pref_store.cc
@@ -151,7 +151,7 @@ // First-party sites use signed-in cookies to ensure that parental // restrictions are applied for Unicorn accounts. prefs_->SetInteger( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, static_cast<int>(IncognitoModePrefs::Availability::kDisabled)); }
diff --git a/chrome/browser/supervised_user/supervised_user_pref_store_unittest.cc b/chrome/browser/supervised_user/supervised_user_pref_store_unittest.cc index 71d46ca..352bce39 100644 --- a/chrome/browser/supervised_user/supervised_user_pref_store_unittest.cc +++ b/chrome/browser/supervised_user/supervised_user_pref_store_unittest.cc
@@ -146,7 +146,7 @@ // kIncognitoModeAvailability must be disabled for all supervised users. EXPECT_THAT( fixture.changed_prefs()->FindIntByDottedPath( - prefs::kIncognitoModeAvailability), + policy::policy_prefs::kIncognitoModeAvailability), Optional(static_cast<int>(IncognitoModePrefs::Availability::kDisabled))); // kSupervisedModeManualHosts does not have a hardcoded value.
diff --git a/chrome/browser/ui/android/favicon/BUILD.gn b/chrome/browser/ui/android/favicon/BUILD.gn index 7fe0f9e..cee8503 100644 --- a/chrome/browser/ui/android/favicon/BUILD.gn +++ b/chrome/browser/ui/android/favicon/BUILD.gn
@@ -23,6 +23,7 @@ "//components/url_formatter/android:url_formatter_java", "//content/public/android:content_java", "//third_party/androidx:androidx_annotation_annotation_java", + "//third_party/androidx:androidx_appcompat_appcompat_resources_java", "//third_party/androidx:androidx_core_core_java", "//ui/android:ui_java", "//url:gurl_java",
diff --git a/chrome/browser/ui/android/favicon/java/src/org/chromium/chrome/browser/ui/favicon/FaviconUtils.java b/chrome/browser/ui/android/favicon/java/src/org/chromium/chrome/browser/ui/favicon/FaviconUtils.java index db131d59..32c49443 100644 --- a/chrome/browser/ui/android/favicon/java/src/org/chromium/chrome/browser/ui/favicon/FaviconUtils.java +++ b/chrome/browser/ui/android/favicon/java/src/org/chromium/chrome/browser/ui/favicon/FaviconUtils.java
@@ -7,11 +7,14 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import androidx.annotation.ColorInt; import androidx.annotation.Nullable; +import androidx.appcompat.content.res.AppCompatResources; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import org.chromium.components.browser_ui.widget.RoundedIconGenerator; @@ -68,6 +71,21 @@ } /** + * Create a bitmap with corresponding size of a generic favicon. + * @param context {@link Context} to read the generic favicon. + * @param size Desired size of the bitmap. + * @return A generic globe favicon. + */ + public static Bitmap createGenericFaviconBitmap(Context context, int size) { + Bitmap bitmap = Bitmap.createBitmap(size, size, Config.ARGB_8888); + Drawable drawable = AppCompatResources.getDrawable(context, R.drawable.ic_globe_24dp); + drawable.setBounds(0, 0, size, size); + Canvas canvas = new Canvas(bitmap); + drawable.draw(canvas); + return bitmap; + } + + /** * Creates a {@link Drawable} with the provided icon with * nearest-neighbor scaling through {@link Bitmap#createScaledBitmap(Bitmap, int, int, * boolean)}, or a fallback monogram.
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index dde50890..fa55e75 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -3526,6 +3526,9 @@ <message name="IDS_ADAPTIVE_TOOLBAR_BUTTON_PREFERENCE_VOICE_SEARCH" desc="Title name for the voice search option in the preference."> Voice search </message> + <message name="IDS_ADAPTIVE_TOOLBAR_BUTTON_PREFERENCE_ADD_TO_BOOKMARKS" desc="Title name for the add to bookmarks option in the preference."> + Add to bookmarks + </message> <message name="IDS_ADAPTIVE_TOOLBAR_BUTTON_PREFERENCE_TRANSLATE" desc="Title name for the translate option in the preference."> Translate </message> @@ -3547,6 +3550,9 @@ <message name="IDS_ADAPTIVE_TOOLBAR_BUTTON_VOICE_SEARCH_IPH" desc="An in-product-help message for the voice search button."> Quickly search with your voice. To edit this shortcut, touch and hold. </message> + <message name="IDS_ADAPTIVE_TOOLBAR_BUTTON_ADD_TO_BOOKMARKS_IPH" desc="An in-product-help message for the add to bookmarks button."> + Quickly bookmark this page. To edit this shortcut, touch and hold. + </message> <message name="IDS_ADAPTIVE_TOOLBAR_BUTTON_TRANSLATE_IPH" desc="An in-product-help message for the voice search button."> Quickly translate this page. To edit this shortcut, touch and hold. </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ADAPTIVE_TOOLBAR_BUTTON_ADD_TO_BOOKMARKS_IPH.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ADAPTIVE_TOOLBAR_BUTTON_ADD_TO_BOOKMARKS_IPH.png.sha1 new file mode 100644 index 0000000..c251581 --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ADAPTIVE_TOOLBAR_BUTTON_ADD_TO_BOOKMARKS_IPH.png.sha1
@@ -0,0 +1 @@ +4b7f8076368ce26174085ba4e4e2df3ddddcd2e7 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ADAPTIVE_TOOLBAR_BUTTON_PREFERENCE_ADD_TO_BOOKMARKS.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ADAPTIVE_TOOLBAR_BUTTON_PREFERENCE_ADD_TO_BOOKMARKS.png.sha1 new file mode 100644 index 0000000..84f588b --- /dev/null +++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_ADAPTIVE_TOOLBAR_BUTTON_PREFERENCE_ADD_TO_BOOKMARKS.png.sha1
@@ -0,0 +1 @@ +ffc7b342d86702e60df30c4bf9f6d99004b7f1ba \ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/java/res/layout/radio_button_group_adaptive_toolbar_preference.xml b/chrome/browser/ui/android/toolbar/java/res/layout/radio_button_group_adaptive_toolbar_preference.xml index 8814590..5da7a92 100644 --- a/chrome/browser/ui/android/toolbar/java/res/layout/radio_button_group_adaptive_toolbar_preference.xml +++ b/chrome/browser/ui/android/toolbar/java/res/layout/radio_button_group_adaptive_toolbar_preference.xml
@@ -63,6 +63,15 @@ app:iconSrc="@drawable/ic_translate" app:primaryText="@string/adaptive_toolbar_button_preference_translate" /> + <org.chromium.components.browser_ui.widget.RadioButtonWithDescription + android:id="@+id/adaptive_option_add_to_bookmarks" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="@dimen/min_touch_target_size" + android:paddingTop="10dp" + app:iconSrc="@drawable/btn_star" + app:primaryText="@string/adaptive_toolbar_button_preference_add_to_bookmarks" /> + </org.chromium.components.browser_ui.widget.RadioButtonWithDescriptionLayout> </LinearLayout> \ No newline at end of file
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java index dad1722..723509c0 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarFeatures.java
@@ -149,6 +149,11 @@ ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_TRANSLATE); } + public static boolean isAdaptiveToolbarAddToBookmarksEnabled() { + return ChromeFeatureList.isEnabled( + ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS); + } + private static boolean isAnyContextualPageActionButtonEnabled() { return isPriceTrackingPageActionEnabled() || isReaderModePageActionEnabled(); }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStatePredictor.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStatePredictor.java index b467ea1..ac2c08e 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStatePredictor.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStatePredictor.java
@@ -152,6 +152,7 @@ case AdaptiveToolbarButtonVariant.SHARE: case AdaptiveToolbarButtonVariant.VOICE: case AdaptiveToolbarButtonVariant.TRANSLATE: + case AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS: return true; case AdaptiveToolbarButtonVariant.UNKNOWN: case AdaptiveToolbarButtonVariant.NONE: @@ -221,6 +222,8 @@ return VoiceRecognitionUtil.isVoiceSearchEnabled(mAndroidPermissionDelegate); case AdaptiveToolbarButtonVariant.TRANSLATE: return AdaptiveToolbarFeatures.isAdaptiveToolbarTranslateEnabled(); + case AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS: + return AdaptiveToolbarFeatures.isAdaptiveToolbarAddToBookmarksEnabled(); default: return true; }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStats.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStats.java index 8d09a9a..6cf3aa5 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStats.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/AdaptiveToolbarStats.java
@@ -22,7 +22,9 @@ AdaptiveToolbarRadioButtonState.AUTO_WITH_VOICE, AdaptiveToolbarRadioButtonState.NEW_TAB, AdaptiveToolbarRadioButtonState.SHARE, AdaptiveToolbarRadioButtonState.VOICE, AdaptiveToolbarRadioButtonState.TRANSLATE, - AdaptiveToolbarRadioButtonState.AUTO_WITH_TRANSLATE}) + AdaptiveToolbarRadioButtonState.AUTO_WITH_TRANSLATE, + AdaptiveToolbarRadioButtonState.ADD_TO_BOOKMARKS, + AdaptiveToolbarRadioButtonState.AUTO_WITH_ADD_TO_BOOKMARKS}) @Retention(RetentionPolicy.SOURCE) private @interface AdaptiveToolbarRadioButtonState { int UNKNOWN = 0; @@ -34,7 +36,9 @@ int VOICE = 6; int TRANSLATE = 7; int AUTO_WITH_TRANSLATE = 8; - int NUM_ENTRIES = 9; + int ADD_TO_BOOKMARKS = 9; + int AUTO_WITH_ADD_TO_BOOKMARKS = 10; + int NUM_ENTRIES = 11; } /** @@ -85,6 +89,8 @@ return AdaptiveToolbarRadioButtonState.SHARE; case AdaptiveToolbarButtonVariant.VOICE: return AdaptiveToolbarRadioButtonState.VOICE; + case AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS: + return AdaptiveToolbarRadioButtonState.ADD_TO_BOOKMARKS; case AdaptiveToolbarButtonVariant.TRANSLATE: return AdaptiveToolbarRadioButtonState.TRANSLATE; case AdaptiveToolbarButtonVariant.AUTO: @@ -95,6 +101,8 @@ return AdaptiveToolbarRadioButtonState.AUTO_WITH_SHARE; case AdaptiveToolbarButtonVariant.VOICE: return AdaptiveToolbarRadioButtonState.AUTO_WITH_VOICE; + case AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS: + return AdaptiveToolbarRadioButtonState.AUTO_WITH_ADD_TO_BOOKMARKS; case AdaptiveToolbarButtonVariant.TRANSLATE: return AdaptiveToolbarRadioButtonState.AUTO_WITH_TRANSLATE; }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarPreferenceFragment.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarPreferenceFragment.java index f59d531a..6d500ce 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarPreferenceFragment.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarPreferenceFragment.java
@@ -57,6 +57,8 @@ mRadioButtonGroup.setCanUseVoiceSearch(getCanUseVoiceSearch()); mRadioButtonGroup.setCanUseTranslate( AdaptiveToolbarFeatures.isAdaptiveToolbarTranslateEnabled()); + mRadioButtonGroup.setCanUseAddToBookmarks( + AdaptiveToolbarFeatures.isAdaptiveToolbarAddToBookmarksEnabled()); mRadioButtonGroup.setStatePredictor(new AdaptiveToolbarStatePredictor( new ActivityAndroidPermissionDelegate(new WeakReference(getActivity())))); mRadioButtonGroup.setOnPreferenceChangeListener((preference, newValue) -> {
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarPreferenceFragmentTest.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarPreferenceFragmentTest.java index 0540e96..886709b 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarPreferenceFragmentTest.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/AdaptiveToolbarPreferenceFragmentTest.java
@@ -46,7 +46,8 @@ @EnableFeatures({ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2}) @DisableFeatures({ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR, SettingsFeatureList.HIGHLIGHT_MANAGED_PREF_DISCLAIMER_ANDROID, - ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_TRANSLATE}) + ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_TRANSLATE, + ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS}) public class AdaptiveToolbarPreferenceFragmentTest { @Rule public TestRule mProcessor = new Features.JUnitProcessor(); @@ -201,6 +202,58 @@ }); } + @Test + @SmallTest + @EnableFeatures(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS) + public void testAddToBookmarksOption_Enabled() { + FragmentScenario<AdaptiveToolbarPreferenceFragment> scenario = + FragmentScenario.launchInContainer(AdaptiveToolbarPreferenceFragment.class, + Bundle.EMPTY, org.chromium.chrome.R.style.Theme_Chromium_Settings); + scenario.onFragment(fragment -> { + mRadioPreference = (RadioButtonGroupAdaptiveToolbarPreference) fragment.findPreference( + AdaptiveToolbarPreferenceFragment.PREF_ADAPTIVE_RADIO_GROUP); + + // Select Add to bookmarks. + Assert.assertEquals(R.id.adaptive_option_add_to_bookmarks, + getButton(AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS).getId()); + selectButton(AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS); + assertButtonCheckedCorrectly( + "Add to bookmarks", AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS); + Assert.assertEquals( + AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS, mRadioPreference.getSelection()); + Assert.assertEquals(AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS, + SharedPreferencesManager.getInstance().readInt( + ADAPTIVE_TOOLBAR_CUSTOMIZATION_SETTINGS)); + }); + } + + @Test + @SmallTest + @DisableFeatures(ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_ADD_TO_BOOKMARKS) + public void testAddToBookmarksOption_Disabled() { + // Set initial preference to add to bookmarks. + SharedPreferencesManager.getInstance().writeInt(ADAPTIVE_TOOLBAR_CUSTOMIZATION_SETTINGS, + AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS); + FragmentScenario<AdaptiveToolbarPreferenceFragment> scenario = + FragmentScenario.launchInContainer(AdaptiveToolbarPreferenceFragment.class, + Bundle.EMPTY, org.chromium.chrome.R.style.Theme_Chromium_Settings); + scenario.onFragment(fragment -> { + mRadioPreference = (RadioButtonGroupAdaptiveToolbarPreference) fragment.findPreference( + AdaptiveToolbarPreferenceFragment.PREF_ADAPTIVE_RADIO_GROUP); + + // Add to bookmarks option should be hidden, and we should have reverted back to "Auto". + Assert.assertEquals(R.id.adaptive_option_add_to_bookmarks, + getButton(AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS).getId()); + Assert.assertEquals(View.GONE, + getButton(AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS).getVisibility()); + assertButtonCheckedCorrectly("Based on your usage", AdaptiveToolbarButtonVariant.AUTO); + Assert.assertEquals(AdaptiveToolbarButtonVariant.AUTO, mRadioPreference.getSelection()); + Assert.assertEquals(AdaptiveToolbarButtonVariant.AUTO, + SharedPreferencesManager.getInstance().readInt( + ADAPTIVE_TOOLBAR_CUSTOMIZATION_SETTINGS)); + }); + } + private RadioButtonWithDescription getButton(@AdaptiveToolbarButtonVariant int type) { return (RadioButtonWithDescription) mRadioPreference.getButton(type); }
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/RadioButtonGroupAdaptiveToolbarPreference.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/RadioButtonGroupAdaptiveToolbarPreference.java index 9737a083..0defaae 100644 --- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/RadioButtonGroupAdaptiveToolbarPreference.java +++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/adaptive/settings/RadioButtonGroupAdaptiveToolbarPreference.java
@@ -35,10 +35,12 @@ private @NonNull RadioButtonWithDescription mShareButton; private @NonNull RadioButtonWithDescription mVoiceSearchButton; private @NonNull RadioButtonWithDescription mTranslateButton; + private @NonNull RadioButtonWithDescription mAddToBookmarksButton; private @AdaptiveToolbarButtonVariant int mSelected; private @Nullable AdaptiveToolbarStatePredictor mStatePredictor; private boolean mCanUseVoiceSearch = true; private boolean mCanUseTranslate; + private boolean mCanUseAddToBookmarks; public RadioButtonGroupAdaptiveToolbarPreference(Context context, AttributeSet attrs) { super(context, attrs); @@ -61,6 +63,8 @@ (RadioButtonWithDescription) holder.findViewById(R.id.adaptive_option_voice_search); mTranslateButton = (RadioButtonWithDescription) holder.findViewById(R.id.adaptive_option_translate); + mAddToBookmarksButton = (RadioButtonWithDescription) holder.findViewById( + R.id.adaptive_option_add_to_bookmarks); initializeRadioButtonSelection(); RecordUserAction.record("Mobile.AdaptiveToolbarButton.SettingsPage.Opened"); @@ -90,6 +94,7 @@ getButtonString(uiState.autoButtonCaption))); updateVoiceButtonVisibility(); updateTranslateButtonVisibility(); + updateAddToBookmarksButtonVisibility(); }); AdaptiveToolbarStats.recordRadioButtonStateAsync(mStatePredictor, /*onStartup=*/true); } @@ -108,6 +113,8 @@ mSelected = AdaptiveToolbarButtonVariant.VOICE; } else if (mTranslateButton.isChecked()) { mSelected = AdaptiveToolbarButtonVariant.TRANSLATE; + } else if (mAddToBookmarksButton.isChecked()) { + mSelected = AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS; } else { assert false : "No matching setting found."; } @@ -141,6 +148,8 @@ return mVoiceSearchButton; case AdaptiveToolbarButtonVariant.TRANSLATE: return mTranslateButton; + case AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS: + return mAddToBookmarksButton; } return null; } @@ -161,6 +170,9 @@ case AdaptiveToolbarButtonVariant.TRANSLATE: stringRes = R.string.adaptive_toolbar_button_preference_translate; break; + case AdaptiveToolbarButtonVariant.ADD_TO_BOOKMARKS: + stringRes = R.string.adaptive_toolbar_button_preference_add_to_bookmarks; + break; default: assert false : "Unknown variant " + variant; } @@ -177,6 +189,11 @@ updateTranslateButtonVisibility(); } + void setCanUseAddToBookmarks(boolean canUseAddToBookmarks) { + mCanUseAddToBookmarks = canUseAddToBookmarks; + updateAddToBookmarksButtonVisibility(); + } + private void updateVoiceButtonVisibility() { updateButtonVisibility(mVoiceSearchButton, mCanUseVoiceSearch); } @@ -185,6 +202,10 @@ updateButtonVisibility(mTranslateButton, mCanUseTranslate); } + private void updateAddToBookmarksButtonVisibility() { + updateButtonVisibility(mAddToBookmarksButton, mCanUseAddToBookmarks); + } + /** * Updates a button's visibility based on a boolean value. If the button is currently checked * and it needs to be hidden then we check the default "Auto" button.
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.cc b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.cc index 17199ee1..b983410 100644 --- a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.cc +++ b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.cc
@@ -9,8 +9,14 @@ #include <string> #include <vector> +#include "ash/glanceables/tasks/glanceables_tasks_client.h" +#include "ash/glanceables/tasks/glanceables_tasks_types.h" #include "base/check.h" +#include "base/containers/flat_map.h" +#include "base/functional/bind.h" #include "base/functional/callback_forward.h" +#include "base/types/expected.h" +#include "google_apis/common/api_error_codes.h" #include "google_apis/common/request_sender.h" #include "google_apis/gaia/gaia_constants.h" #include "google_apis/tasks/tasks_api_requests.h" @@ -20,8 +26,11 @@ namespace ash { namespace { +using ::google_apis::ApiErrorCode; using ::google_apis::tasks::ListTaskListsRequest; using ::google_apis::tasks::ListTasksRequest; +using ::google_apis::tasks::Task; +using ::google_apis::tasks::TaskList; using ::google_apis::tasks::TaskLists; using ::google_apis::tasks::Tasks; @@ -54,6 +63,64 @@ } )"); +std::vector<GlanceablesTaskList> ConvertTaskLists( + const std::vector<std::unique_ptr<TaskList>>& raw_items) { + std::vector<GlanceablesTaskList> converted_task_lists; + converted_task_lists.reserve(raw_items.size()); + for (const auto& item : raw_items) { + converted_task_lists.emplace_back(item->id(), item->title(), + item->updated()); + } + return converted_task_lists; +} + +GlanceablesTask ConvertTask( + const Task* const task, + base::flat_map<std::string, std::vector<const Task*>>& grouped_subtasks) { + const auto iter = grouped_subtasks.find(task->id()); + std::vector<GlanceablesTask> converted_subtasks; + if (iter != grouped_subtasks.end()) { + converted_subtasks.reserve(iter->second.size()); + for (const auto* const subtask : iter->second) { + converted_subtasks.push_back(ConvertTask(subtask, grouped_subtasks)); + } + grouped_subtasks.erase(iter); + } + + return GlanceablesTask(task->id(), task->title(), + task->status() == Task::Status::kCompleted, + converted_subtasks); +} + +std::vector<GlanceablesTask> ConvertTasks( + const std::vector<std::unique_ptr<Task>>& raw_items) { + // Find root level tasks and group all other subtasks by their parent id. + std::vector<const Task*> root_tasks; + base::flat_map<std::string, std::vector<const Task*>> grouped_subtasks; + for (const auto& item : raw_items) { + if (item->parent_id().empty()) { + root_tasks.push_back(item.get()); + continue; + } + + grouped_subtasks[item->parent_id()].push_back(item.get()); + } + + std::vector<GlanceablesTask> converted_tasks; + converted_tasks.reserve(root_tasks.size()); + for (const auto* const root_task : root_tasks) { + converted_tasks.push_back(ConvertTask(root_task, grouped_subtasks)); + } + + if (!grouped_subtasks.empty()) { + // At this moment `grouped_subtasks` should be empty. If not - something is + // wrong with the returned data (some tasks point to invalid `parent_id()`). + return std::vector<GlanceablesTask>(); + } + + return converted_tasks; +} + } // namespace GlanceablesTasksClientImpl::GlanceablesTasksClientImpl( @@ -64,21 +131,42 @@ GlanceablesTasksClientImpl::~GlanceablesTasksClientImpl() = default; base::OnceClosure GlanceablesTasksClientImpl::GetTaskLists( - ListTaskListsRequest::Callback callback) { + GlanceablesTasksClient::GetTaskListsCallback callback) { EnsureRequestSenderExists(); return request_sender_->StartRequestWithAuthRetry( - std::make_unique<ListTaskListsRequest>(request_sender_.get(), - std::move(callback))); + std::make_unique<ListTaskListsRequest>( + request_sender_.get(), + base::BindOnce(&GlanceablesTasksClientImpl::OnTaskListsFetched, + weak_factory_.GetWeakPtr(), std::move(callback)))); } base::OnceClosure GlanceablesTasksClientImpl::GetTasks( - ListTasksRequest::Callback callback, + GlanceablesTasksClient::GetTasksCallback callback, const std::string& task_list_id) { DCHECK(!task_list_id.empty()); EnsureRequestSenderExists(); return request_sender_->StartRequestWithAuthRetry( - std::make_unique<ListTasksRequest>(request_sender_.get(), - std::move(callback), task_list_id)); + std::make_unique<ListTasksRequest>( + request_sender_.get(), + base::BindOnce(&GlanceablesTasksClientImpl::OnTasksFetched, + weak_factory_.GetWeakPtr(), std::move(callback)), + task_list_id)); +} + +void GlanceablesTasksClientImpl::OnTaskListsFetched( + GlanceablesTasksClient::GetTaskListsCallback callback, + base::expected<std::unique_ptr<TaskLists>, ApiErrorCode> result) const { + std::move(callback).Run(result.has_value() + ? ConvertTaskLists(result.value()->items()) + : std::vector<GlanceablesTaskList>()); +} + +void GlanceablesTasksClientImpl::OnTasksFetched( + GlanceablesTasksClient::GetTasksCallback callback, + base::expected<std::unique_ptr<Tasks>, ApiErrorCode> result) const { + std::move(callback).Run(result.has_value() + ? ConvertTasks(result.value()->items()) + : std::vector<GlanceablesTask>()); } void GlanceablesTasksClientImpl::EnsureRequestSenderExists() {
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.h b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.h index 04d6c3d1..192d014 100644 --- a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.h +++ b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl.h
@@ -11,10 +11,16 @@ #include "ash/glanceables/tasks/glanceables_tasks_client.h" #include "base/functional/callback_forward.h" +#include "base/memory/weak_ptr.h" +#include "base/types/expected.h" #include "google_apis/tasks/tasks_api_requests.h" namespace google_apis { class RequestSender; +namespace tasks { +class TaskLists; +class Tasks; +} // namespace tasks } // namespace google_apis namespace net { @@ -42,12 +48,23 @@ // GlanceablesTasksClient: base::OnceClosure GetTaskLists( - google_apis::tasks::ListTaskListsRequest::Callback callback) override; - base::OnceClosure GetTasks( - google_apis::tasks::ListTasksRequest::Callback callback, - const std::string& task_list_id) override; + GlanceablesTasksClient::GetTaskListsCallback callback) override; + base::OnceClosure GetTasks(GlanceablesTasksClient::GetTasksCallback callback, + const std::string& task_list_id) override; private: + // Callback for `GetTaskLists()`. Transforms fetched items to ash-friendly + // types. + void OnTaskListsFetched( + GlanceablesTasksClient::GetTaskListsCallback callback, + base::expected<std::unique_ptr<google_apis::tasks::TaskLists>, + google_apis::ApiErrorCode> result) const; + + // Callback for `GetTasks()`. Transforms fetched items to ash-friendly types. + void OnTasksFetched(GlanceablesTasksClient::GetTasksCallback callback, + base::expected<std::unique_ptr<google_apis::tasks::Tasks>, + google_apis::ApiErrorCode> result) const; + // Creates `request_sender_` by calling `create_request_sender_callback_` on // demand. void EnsureRequestSenderExists(); @@ -58,6 +75,8 @@ // Helper class that sends requests, handles retries and authentication. std::unique_ptr<google_apis::RequestSender> request_sender_; + + base::WeakPtrFactory<GlanceablesTasksClientImpl> weak_factory_{this}; }; } // namespace ash
diff --git a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl_unittest.cc b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl_unittest.cc index 2ae47a5..806cef6 100644 --- a/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl_unittest.cc +++ b/chrome/browser/ui/ash/glanceables/glanceables_tasks_client_impl_unittest.cc
@@ -7,25 +7,26 @@ #include <algorithm> #include <memory> #include <string> +#include <vector> #include "ash/constants/ash_features.h" +#include "ash/glanceables/tasks/glanceables_tasks_types.h" #include "base/functional/bind.h" +#include "base/functional/callback_forward.h" #include "base/memory/scoped_refptr.h" #include "base/test/bind.h" #include "base/test/scoped_command_line.h" #include "base/test/scoped_feature_list.h" #include "base/test/task_environment.h" #include "base/test/test_future.h" -#include "base/types/expected.h" #include "content/public/test/browser_task_environment.h" #include "google_apis/common/api_error_codes.h" #include "google_apis/common/dummy_auth_service.h" #include "google_apis/common/request_sender.h" -#include "google_apis/common/test_util.h" +#include "google_apis/common/time_util.h" #include "google_apis/gaia/gaia_switches.h" #include "google_apis/gaia/gaia_urls.h" #include "google_apis/tasks/tasks_api_requests.h" -#include "google_apis/tasks/tasks_api_response_types.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" @@ -38,8 +39,9 @@ using ::base::test::TestFuture; using ::google_apis::ApiErrorCode; -using ::google_apis::tasks::TaskLists; -using ::google_apis::tasks::Tasks; +using ::google_apis::util::FormatTimeAsString; +using ::net::test_server::HttpRequest; +using ::net::test_server::HttpResponse; // Helper class to temporary override `GaiaUrls` singleton. class GaiaUrlsOverrider { @@ -51,10 +53,29 @@ GaiaUrls test_gaia_urls_; }; +std::unique_ptr<net::test_server::HttpResponse> CreateSuccessfulResponse( + const std::string& content) { + auto response = std::make_unique<net::test_server::BasicHttpResponse>(); + response->set_code(net::HTTP_OK); + response->set_content(content); + response->set_content_type("application/json"); + return response; +} + +std::unique_ptr<net::test_server::HttpResponse> CreateFailedResponse() { + auto response = std::make_unique<net::test_server::BasicHttpResponse>(); + response->set_code(net::HTTP_INTERNAL_SERVER_ERROR); + return response; +} + } // namespace class GlanceablesTasksClientImplTest : public testing::Test { public: + using GenerateResponseCallback = + base::RepeatingCallback<std::unique_ptr<HttpResponse>( + const HttpRequest& request)>; + void SetUp() override { auto create_request_sender_callback = base::BindLambdaForTesting( [&](const std::vector<std::string>& scopes, @@ -78,9 +99,8 @@ test_server_.base_url().spec()); } - // Relative to "google_apis/test/data/". - void set_file_path_for_response(const std::string& path) { - file_path_for_response_ = path; + void set_generate_response_callback(const GenerateResponseCallback& cb) { + generate_response_callback_ = cb; } GlanceablesTasksClientImpl* client() { return client_.get(); } @@ -88,8 +108,7 @@ private: std::unique_ptr<net::test_server::HttpResponse> HandleDataFileRequest( const net::test_server::HttpRequest& request) { - return google_apis::test_util::CreateHttpResponseFromFile( - google_apis::test_util::GetTestFilePath(file_path_for_response_)); + return std::move(generate_response_callback_).Run(request); } content::BrowserTaskEnvironment task_environment_{ @@ -102,33 +121,170 @@ /*network_service=*/nullptr, /*is_trusted=*/true); std::unique_ptr<GaiaUrlsOverrider> gaia_urls_overrider_; - std::string file_path_for_response_; + GenerateResponseCallback generate_response_callback_; std::unique_ptr<GlanceablesTasksClientImpl> client_; }; TEST_F(GlanceablesTasksClientImplTest, GetTaskLists) { - set_file_path_for_response("tasks/task_lists.json"); + set_generate_response_callback( + base::BindLambdaForTesting([](const HttpRequest& request) { + return CreateSuccessfulResponse(R"( + { + "kind": "tasks#taskLists", + "items": [ + { + "id": "qwerty", + "title": "My Tasks 1", + "updated": "2023-01-30T22:19:22.812Z" + }, + { + "id": "asdfgh", + "title": "My Tasks 2", + "updated": "2022-12-21T23:38:22.590Z" + } + ] + } + )"); + })); - TestFuture<base::expected<std::unique_ptr<TaskLists>, ApiErrorCode>> future; + TestFuture<const std::vector<GlanceablesTaskList>&> future; auto cancel_closure = client()->GetTaskLists(future.GetCallback()); ASSERT_TRUE(future.Wait()); EXPECT_FALSE(cancel_closure.is_null()); - EXPECT_TRUE(future.Get().has_value()); - EXPECT_EQ(future.Get().value()->items().size(), 2u); + + const auto& task_lists = future.Get(); + EXPECT_EQ(task_lists.size(), 2u); + + EXPECT_EQ(task_lists.at(0).id, "qwerty"); + EXPECT_EQ(task_lists.at(0).title, "My Tasks 1"); + EXPECT_EQ(FormatTimeAsString(task_lists.at(0).updated), + "2023-01-30T22:19:22.812Z"); + + EXPECT_EQ(task_lists.at(1).id, "asdfgh"); + EXPECT_EQ(task_lists.at(1).title, "My Tasks 2"); + EXPECT_EQ(FormatTimeAsString(task_lists.at(1).updated), + "2022-12-21T23:38:22.590Z"); +} + +TEST_F(GlanceablesTasksClientImplTest, + GetTaskListsReturnsEmptyVectorOnHttpError) { + set_generate_response_callback(base::BindLambdaForTesting( + [](const HttpRequest& request) { return CreateFailedResponse(); })); + + TestFuture<const std::vector<GlanceablesTaskList>&> future; + auto cancel_closure = client()->GetTaskLists(future.GetCallback()); + ASSERT_TRUE(future.Wait()); + + EXPECT_FALSE(cancel_closure.is_null()); + + const auto& task_lists = future.Get(); + EXPECT_EQ(task_lists.size(), 0u); } TEST_F(GlanceablesTasksClientImplTest, GetTasks) { - set_file_path_for_response("tasks/tasks.json"); + set_generate_response_callback( + base::BindLambdaForTesting([](const HttpRequest& request) { + return CreateSuccessfulResponse(R"( + { + "kind": "tasks#tasks", + "items": [ + { + "id": "asd", + "title": "Parent task, level 1", + "status": "needsAction" + }, + { + "id": "qwe", + "title": "Child task, level 2", + "parent": "asd", + "status": "needsAction" + }, + { + "id": "zxc", + "title": "Child task, level 3", + "parent": "qwe", + "status": "completed" + } + ] + } + )"); + })); - TestFuture<base::expected<std::unique_ptr<Tasks>, ApiErrorCode>> future; + TestFuture<const std::vector<GlanceablesTask>&> future; auto cancel_closure = client()->GetTasks(future.GetCallback(), "test-task-list-id"); ASSERT_TRUE(future.Wait()); EXPECT_FALSE(cancel_closure.is_null()); - EXPECT_TRUE(future.Get().has_value()); - EXPECT_EQ(future.Get().value()->items().size(), 2u); + + const auto& root_tasks = future.Get(); + EXPECT_EQ(root_tasks.size(), 1u); + EXPECT_EQ(root_tasks.at(0).id, "asd"); + EXPECT_EQ(root_tasks.at(0).title, "Parent task, level 1"); + EXPECT_EQ(root_tasks.at(0).completed, false); + + const auto& subtasks_level_2 = root_tasks.at(0).subtasks; + EXPECT_EQ(subtasks_level_2.size(), 1u); + EXPECT_EQ(subtasks_level_2.at(0).id, "qwe"); + EXPECT_EQ(subtasks_level_2.at(0).title, "Child task, level 2"); + EXPECT_EQ(subtasks_level_2.at(0).completed, false); + + const auto& subtasks_level_3 = subtasks_level_2.at(0).subtasks; + EXPECT_EQ(subtasks_level_3.size(), 1u); + EXPECT_EQ(subtasks_level_3.at(0).id, "zxc"); + EXPECT_EQ(subtasks_level_3.at(0).title, "Child task, level 3"); + EXPECT_EQ(subtasks_level_3.at(0).completed, true); +} + +TEST_F(GlanceablesTasksClientImplTest, GetTasksReturnsEmptyVectorOnHttpError) { + set_generate_response_callback(base::BindLambdaForTesting( + [](const HttpRequest& request) { return CreateFailedResponse(); })); + + TestFuture<const std::vector<GlanceablesTask>&> future; + auto cancel_closure = + client()->GetTasks(future.GetCallback(), "test-task-list-id"); + ASSERT_TRUE(future.Wait()); + + EXPECT_FALSE(cancel_closure.is_null()); + + const auto& root_tasks = future.Get(); + EXPECT_EQ(root_tasks.size(), 0u); +} + +TEST_F(GlanceablesTasksClientImplTest, + GetTasksReturnsEmptyVectorOnConversionError) { + set_generate_response_callback( + base::BindLambdaForTesting([](const HttpRequest& request) { + return CreateSuccessfulResponse(R"( + { + "kind": "tasks#tasks", + "items": [ + { + "id": "asd", + "title": "Parent task", + "status": "needsAction" + }, + { + "id": "qwe", + "title": "Child task", + "parent": "asd1", + "status": "needsAction" + } + ] + } + )"); + })); + + TestFuture<const std::vector<GlanceablesTask>&> future; + auto cancel_closure = + client()->GetTasks(future.GetCallback(), "test-task-list-id"); + ASSERT_TRUE(future.Wait()); + + EXPECT_FALSE(cancel_closure.is_null()); + + const auto& root_tasks = future.Get(); + EXPECT_EQ(root_tasks.size(), 0u); } } // namespace ash
diff --git a/chrome/browser/ui/ash/media_client_impl.cc b/chrome/browser/ui/ash/media_client_impl.cc index 3be68da..6a97d5f 100644 --- a/chrome/browser/ui/ash/media_client_impl.cc +++ b/chrome/browser/ui/ash/media_client_impl.cc
@@ -671,10 +671,6 @@ void MediaClientImpl::ShowCameraOffNotification(const std::string& device_id, const std::string& device_name, const bool resurface) { - if (ash::features::IsPrivacyIndicatorsEnabled() || - ash::features::IsVideoConferenceEnabled()) { - return; - } auto it = device_id_to_camera_privacy_switch_state_.find(device_id); if (it == device_id_to_camera_privacy_switch_state_.end() || it->second != cros::mojom::CameraPrivacySwitchState::ON ||
diff --git a/chrome/browser/ui/ash/network/network_portal_signin_controller.cc b/chrome/browser/ui/ash/network/network_portal_signin_controller.cc index 4a9e7b1..4040c47b 100644 --- a/chrome/browser/ui/ash/network/network_portal_signin_controller.cc +++ b/chrome/browser/ui/ash/network/network_portal_signin_controller.cc
@@ -24,6 +24,7 @@ #include "chromeos/ash/components/network/network_state_handler.h" #include "chromeos/ash/components/network/proxy/proxy_config_service_impl.h" #include "components/captive_portal/core/captive_portal_detector.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" #include "components/proxy_config/proxy_prefs.h" #include "components/user_manager/user_manager.h" @@ -145,7 +146,8 @@ IncognitoModePrefs::Availability availability; IncognitoModePrefs::IntToAvailability( - profile->GetPrefs()->GetInteger(prefs::kIncognitoModeAvailability), + profile->GetPrefs()->GetInteger( + policy::policy_prefs::kIncognitoModeAvailability), &availability); if (availability == IncognitoModePrefs::Availability::kDisabled) { // Use a dialog to prevent navigation and use an OTR profile due to
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc index 645f50d3..dc085f1 100644 --- a/chrome/browser/ui/browser_command_controller.cc +++ b/chrome/browser/ui/browser_command_controller.cc
@@ -58,6 +58,7 @@ #include "components/dom_distiller/core/dom_distiller_features.h" #include "components/lens/buildflags.h" #include "components/lens/lens_features.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" #include "components/services/screen_ai/buildflags/buildflags.h" #include "components/sessions/content/session_tab_helper.h" @@ -200,7 +201,7 @@ &BrowserCommandController::UpdateCommandsForBookmarkBar, base::Unretained(this))); profile_pref_registrar_.Add( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, base::BindRepeating( &BrowserCommandController::UpdateCommandsForIncognitoAvailability, base::Unretained(this)));
diff --git a/chrome/browser/ui/browser_finder.cc b/chrome/browser/ui/browser_finder.cc index 903ccdd7..32ea283d 100644 --- a/chrome/browser/ui/browser_finder.cc +++ b/chrome/browser/ui/browser_finder.cc
@@ -214,6 +214,17 @@ return browsers; } +std::vector<Browser*> FindAllBrowsersWithProfile(Profile* profile) { + std::vector<Browser*> browsers; + for (auto* browser : *BrowserList::GetInstance()) { + if (BrowserMatches(browser, profile, Browser::FEATURE_NONE, kMatchAny, + display::kInvalidDisplayId)) { + browsers.emplace_back(browser); + } + } + return browsers; +} + Browser* FindBrowserWithID(SessionID desired_id) { for (auto* browser : *BrowserList::GetInstance()) { if (browser->session_id() == desired_id)
diff --git a/chrome/browser/ui/browser_finder.h b/chrome/browser/ui/browser_finder.h index 514f380..818d24f9 100644 --- a/chrome/browser/ui/browser_finder.h +++ b/chrome/browser/ui/browser_finder.h
@@ -58,6 +58,10 @@ // if no such browser currently exists. std::vector<Browser*> FindAllTabbedBrowsersWithProfile(Profile* profile); +// Find all browsers of any type with the provided profile. Returns an empty +// vector if no such browser currently exists. +std::vector<Browser*> FindAllBrowsersWithProfile(Profile* profile); + // Find an existing browser with the provided ID. Returns NULL if no such // browser currently exists. Browser* FindBrowserWithID(SessionID desired_id);
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc index 7be0410e..f7754bf8 100644 --- a/chrome/browser/ui/browser_navigator_browsertest.cc +++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -28,13 +28,13 @@ #include "chrome/browser/ui/singleton_tabs.h" #include "chrome/browser/ui/tabs/tab_enums.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" -#include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/ui_test_utils.h" #include "components/captive_portal/core/buildflags.h" #include "components/omnibox/browser/omnibox_edit_model.h" #include "components/omnibox/browser/omnibox_view.h" #include "components/omnibox/browser/tab_matcher.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_service.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/notification_types.h" @@ -205,11 +205,11 @@ // Set kIncognitoModeAvailability to FORCED. PrefService* prefs1 = browser->profile()->GetPrefs(); prefs1->SetInteger( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, static_cast<int>(IncognitoModePrefs::Availability::kForced)); PrefService* prefs2 = browser->profile()->GetOriginalProfile()->GetPrefs(); prefs2->SetInteger( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, static_cast<int>(IncognitoModePrefs::Availability::kForced)); // Navigate to the page.
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_browsertest.mm b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_browsertest.mm index 3928eec..c43f089 100644 --- a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_browsertest.mm +++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_browsertest.mm
@@ -54,14 +54,14 @@ base::scoped_nsobject<WindowAppleScript> aWindow( [[WindowAppleScript alloc] init]); base::scoped_nsobject<NSString> var([[aWindow.get() uniqueID] copy]); - [aWindow.get() setValue:@YES forKey:@"isVisible"]; + [aWindow.get() setValue:@YES forKey:@"visible"]; [NSApp insertInAppleScriptWindows:aWindow.get()]; chrome::testing::NSRunLoopRunAllPending(); // Represents the window after it is added. WindowAppleScript* window = [NSApp appleScriptWindows][0]; - EXPECT_NSEQ(@YES, [aWindow.get() valueForKey:@"isVisible"]); + EXPECT_NSEQ(@YES, [aWindow.get() valueForKey:@"visible"]); EXPECT_EQ([window container], NSApp); EXPECT_NSEQ(AppleScript::kWindowsProperty, [window containerProperty]); EXPECT_NSEQ(var, [window uniqueID]);
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript_browsertest.mm b/chrome/browser/ui/cocoa/applescript/window_applescript_browsertest.mm index 92283dcd0..57f5042 100644 --- a/chrome/browser/ui/cocoa/applescript/window_applescript_browsertest.mm +++ b/chrome/browser/ui/cocoa/applescript/window_applescript_browsertest.mm
@@ -150,10 +150,10 @@ IN_PROC_BROWSER_TEST_F(WindowAppleScriptTest, NSWindowTest) { base::scoped_nsobject<WindowAppleScript> window( [[WindowAppleScript alloc] initWithBrowser:browser()]); - [window.get() setValue:@YES forKey:@"isMiniaturized"]; - EXPECT_TRUE([[window.get() valueForKey:@"isMiniaturized"] boolValue]); - [window.get() setValue:@NO forKey:@"isMiniaturized"]; - EXPECT_FALSE([[window.get() valueForKey:@"isMiniaturized"] boolValue]); + [window.get() setValue:@YES forKey:@"miniaturized"]; + EXPECT_TRUE([[window.get() valueForKey:@"miniaturized"] boolValue]); + [window.get() setValue:@NO forKey:@"miniaturized"]; + EXPECT_FALSE([[window.get() valueForKey:@"miniaturized"] boolValue]); } // Getting and setting the active tab.
diff --git a/chrome/browser/ui/color/new_tab_page_color_mixer.cc b/chrome/browser/ui/color/new_tab_page_color_mixer.cc index e305202..757c4be 100644 --- a/chrome/browser/ui/color/new_tab_page_color_mixer.cc +++ b/chrome/browser/ui/color/new_tab_page_color_mixer.cc
@@ -438,7 +438,7 @@ mixer[kColorNewTabPageIconButtonBackgroundActive] = { dark_mode ? gfx::kGoogleGrey300 : gfx::kGoogleGrey700}; mixer[kColorNewTabPageLink] = {dark_mode ? gfx::kGoogleBlue300 - : SkColorSetRGB(0x06, 0x37, 0x74)}; + : gfx::kGoogleBlue700}; mixer[kColorNewTabPageMicBorderColor] = {dark_mode ? gfx::kGoogleGrey100 : gfx::kGoogleGrey300}; mixer[kColorNewTabPageMicIconColor] = {dark_mode ? gfx::kGoogleGrey100
diff --git a/chrome/browser/ui/hats/hats_service_browsertest.cc b/chrome/browser/ui/hats/hats_service_browsertest.cc index d22e155..d4407bb 100644 --- a/chrome/browser/ui/hats/hats_service_browsertest.cc +++ b/chrome/browser/ui/hats/hats_service_browsertest.cc
@@ -20,11 +20,11 @@ #include "chrome/browser/ui/hats/hats_service_factory.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_features.h" -#include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "components/content_settings/core/common/pref_names.h" #include "components/metrics_services_manager/metrics_services_manager.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/version_info/version_info.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" @@ -260,7 +260,7 @@ // Disable incognito mode for this profile. PrefService* pref_service = browser()->profile()->GetPrefs(); pref_service->SetInteger( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, static_cast<int>(IncognitoModePrefs::Availability::kDisabled)); EXPECT_EQ(IncognitoModePrefs::Availability::kDisabled, IncognitoModePrefs::GetAvailability(pref_service));
diff --git a/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc b/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc index 6886d294..b97db8c 100644 --- a/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc +++ b/chrome/browser/ui/passwords/well_known_change_password_navigation_throttle.cc
@@ -69,6 +69,14 @@ std::unique_ptr<WellKnownChangePasswordNavigationThrottle> WellKnownChangePasswordNavigationThrottle::MaybeCreateThrottleFor( NavigationHandle* handle) { + auto* profile = Profile::FromBrowserContext( + handle->GetWebContents()->GetBrowserContext()); + // Create WellKnownChangePasswordNavigationThrottle only for regular or + // incognito profiles. + if (!profile->IsRegularProfile() && !profile->IsIncognitoProfile()) { + return nullptr; + } + // Don't handle navigations in subframes or main frames that are in a nested // frame tree (e.g. portals, fenced frames) if (handle->IsInOutermostMainFrame() && @@ -95,6 +103,7 @@ affiliation_service_ = AffiliationServiceFactory::GetForProfile(Profile::FromBrowserContext( handle->GetWebContents()->GetBrowserContext())); + CHECK(affiliation_service_); if (affiliation_service_->GetChangePasswordURL(request_url_).is_empty()) { well_known_change_password_state_.PrefetchChangePasswordURLs( affiliation_service_, {request_url_});
diff --git a/chrome/browser/ui/profile_picker.h b/chrome/browser/ui/profile_picker.h index 6bcefbf..181078b 100644 --- a/chrome/browser/ui/profile_picker.h +++ b/chrome/browser/ui/profile_picker.h
@@ -43,9 +43,15 @@ // (closed the browser app). kQuitAtEnd = 2, + // The user opens the first run again while it's still running. + kAbortTask = 3, + + // The user does something that bypasses the FRE (opens new window etc..). + kAbandonedFlow = 4, + // Add any new values above this one, and update kMaxValue to the highest // enumerator value. - kMaxValue = kQuitAtEnd + kMaxValue = kAbandonedFlow }; using FirstRunExitedCallback = base::OnceCallback<void(FirstRunExitStatus status)>;
diff --git a/chrome/browser/ui/startup/first_run_service.cc b/chrome/browser/ui/startup/first_run_service.cc index 3f8b5c0..c7a06442 100644 --- a/chrome/browser/ui/startup/first_run_service.cc +++ b/chrome/browser/ui/startup/first_run_service.cc
@@ -193,37 +193,6 @@ const PrefService* const local_state = g_browser_process->local_state(); return local_state && local_state->GetBoolean(prefs::kFirstRunFinished); } - -// Processes the outcome from the FRE and resumes the user's interrupted task. -// `original_intent_callback` should be run to allow the caller to resume what -// 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. -void OnFirstRunHasExited(ResumeTaskCallback original_intent_callback, - ProfilePicker::FirstRunExitStatus status) { - bool should_mark_fre_finished = -#if BUILDFLAG(IS_CHROMEOS_LACROS) - status != ProfilePicker::FirstRunExitStatus::kQuitEarly; -#else - true; -#endif - if (should_mark_fre_finished) { - // The user got to the last step, we can mark the FRE as finished, whether - // we eventually proceed with the original intent or not. - SetFirstRunFinished(FinishedReason::kFinishedFlow); - } - - base::UmaHistogramEnumeration("ProfilePicker.FirstRun.ExitStatus", status); - - bool proceed = status == ProfilePicker::FirstRunExitStatus::kCompleted; -#if BUILDFLAG(ENABLE_DICE_SUPPORT) - proceed |= kForYouFreCloseShouldProceed.Get(); -#endif - - std::move(original_intent_callback).Run(proceed); -} - } // namespace // FirstRunService ------------------------------------------------------------- @@ -322,22 +291,70 @@ } #endif -void FirstRunService::OpenFirstRunIfNeeded(EntryPoint entry_point, - ResumeTaskCallback callback) { - TryMarkFirstRunAlreadyFinished(base::BindOnce( - &FirstRunService::OpenFirstRunInternal, weak_ptr_factory_.GetWeakPtr(), - entry_point, std::move(callback))); +// `resume_task_callback_` should be run to allow the caller to resume what +// they were trying to do before they stopped to show the FRE. +// If the FRE's `status` is not `ProfilePicker::FirstRunExitStatus::kCompleted`, +// that `resume_task_callback_` will be called with `proceed` set to false, +// otherwise it will be called with true. +void FirstRunService::OnFirstRunHasExited( + ProfilePicker::FirstRunExitStatus status) { + if (!resume_task_callback_) { + return; + } + + bool proceed = false; + bool should_mark_fre_finished = false; + switch (status) { + case ProfilePicker::FirstRunExitStatus::kCompleted: + proceed = true; + should_mark_fre_finished = true; + break; +#if BUILDFLAG(IS_CHROMEOS_LACROS) + case ProfilePicker::FirstRunExitStatus::kQuitEarly: +#endif + case ProfilePicker::FirstRunExitStatus::kAbortTask: + proceed = false; + should_mark_fre_finished = false; + break; + case ProfilePicker::FirstRunExitStatus::kQuitAtEnd: +#if BUILDFLAG(ENABLE_DICE_SUPPORT) + proceed = kForYouFreCloseShouldProceed.Get(); +#endif + should_mark_fre_finished = true; + break; + case ProfilePicker::FirstRunExitStatus::kAbandonedFlow: + proceed = false; + should_mark_fre_finished = true; + break; + } + + if (should_mark_fre_finished) { + // The user got to the last step, we can mark the FRE as finished, whether + // we eventually proceed with the original intent or not. + SetFirstRunFinished(FinishedReason::kFinishedFlow); + } + + base::UmaHistogramEnumeration("ProfilePicker.FirstRun.ExitStatus", status); + std::move(resume_task_callback_).Run(proceed); } -void FirstRunService::OpenFirstRunInternal(EntryPoint entry_point, +void FirstRunService::OpenFirstRunIfNeeded(EntryPoint entry_point, ResumeTaskCallback callback) { + OnFirstRunHasExited(ProfilePicker::FirstRunExitStatus::kAbortTask); + resume_task_callback_ = std::move(callback); + TryMarkFirstRunAlreadyFinished( + base::BindOnce(&FirstRunService::OpenFirstRunInternal, + weak_ptr_factory_.GetWeakPtr(), entry_point)); +} + +void FirstRunService::OpenFirstRunInternal(EntryPoint entry_point) { if (IsFirstRunMarkedFinishedInPrefs()) { // Opening the First Run is not needed. For example it might have been // marked finished silently, or is suppressed by policy. // // Note that this assumes that the prefs state is the the only part of // `ShouldOpenFirstRun()` that can change during the service's lifetime. - std::move(callback).Run(/*proceed=*/true); + std::move(resume_task_callback_).Run(/*proceed=*/true); return; } @@ -349,8 +366,18 @@ // Note: we call `Show()` even if the FRE might be already open and rely on // the ProfilePicker to decide what it wants to do with `callback`. ProfilePicker::Show(ProfilePicker::Params::ForFirstRun( - profile_->GetPath(), - base::BindOnce(&OnFirstRunHasExited, std::move(callback)))); + profile_->GetPath(), base::BindOnce(&FirstRunService::OnFirstRunHasExited, + weak_ptr_factory_.GetWeakPtr()))); +} + +void FirstRunService::FinishFirstRunWithoutResumeTask() { + if (!resume_task_callback_) { + return; + } + + DCHECK(ProfilePicker::IsFirstRunOpen()); + OnFirstRunHasExited(ProfilePicker::FirstRunExitStatus::kAbandonedFlow); + ProfilePicker::Hide(); } // FirstRunServiceFactory ------------------------------------------------------
diff --git a/chrome/browser/ui/startup/first_run_service.h b/chrome/browser/ui/startup/first_run_service.h index c5cdb40c..81516c1 100644 --- a/chrome/browser/ui/startup/first_run_service.h +++ b/chrome/browser/ui/startup/first_run_service.h
@@ -13,6 +13,7 @@ #include "build/build_config.h" #include "build/chromeos_buildflags.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" +#include "chrome/browser/ui/profile_picker.h" #include "components/keyed_service/core/keyed_service.h" #include "components/signin/public/base/signin_buildflags.h" @@ -100,6 +101,9 @@ void OpenFirstRunIfNeeded(EntryPoint entry_point, ResumeTaskCallback callback); + // Terminates the first run without re-opening a browser window. + void FinishFirstRunWithoutResumeTask(); + private: friend class FirstRunServiceFactory; FRIEND_TEST_ALL_PREFIXES(FirstRunFieldTrialCreatorTest, SetUpFromClientSide); @@ -138,8 +142,10 @@ // The finished state can be checked by calling `ShouldOpenFirstRun()`. void TryMarkFirstRunAlreadyFinished(base::OnceClosure callback); - void OpenFirstRunInternal(EntryPoint entry_point, - ResumeTaskCallback callback); + void OpenFirstRunInternal(EntryPoint entry_point); + + // Processes the outcome from the FRE and resumes the user's interrupted task. + void OnFirstRunHasExited(ProfilePicker::FirstRunExitStatus status); #if BUILDFLAG(IS_CHROMEOS_LACROS) void StartSilentSync(base::OnceClosure callback); @@ -153,6 +159,7 @@ std::unique_ptr<SilentSyncEnabler> silent_sync_enabler_; #endif + ResumeTaskCallback resume_task_callback_; base::WeakPtrFactory<FirstRunService> weak_ptr_factory_{this}; };
diff --git a/chrome/browser/ui/startup/first_run_service_browsertest.cc b/chrome/browser/ui/startup/first_run_service_browsertest.cc index f937c63..8341243 100644 --- a/chrome/browser/ui/startup/first_run_service_browsertest.cc +++ b/chrome/browser/ui/startup/first_run_service_browsertest.cc
@@ -248,6 +248,40 @@ #endif } +IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest, + OpenFirstRunIfNeededCalledTwice) { + // When `OpenFirstRunIfNeeded` is called twice, the callback passed to it the + // first time should be aborted (called with false) and replaced by the + // callback passed to it the second time, which will be later called with + // true on DICE and false on Lacros because it will quit early in the process. + base::RunLoop first_run_loop; + base::RunLoop second_run_loop; + base::HistogramTester histogram_tester; + + ASSERT_TRUE(fre_service()->ShouldOpenFirstRun()); + fre_service()->OpenFirstRunIfNeeded( + FirstRunService::EntryPoint::kOther, + ExpectProceed(false).Then(first_run_loop.QuitClosure())); + profiles::testing::WaitForPickerWidgetCreated(); + + bool second_proceed = true; +#if BUILDFLAG(IS_CHROMEOS_LACROS) + second_proceed = false; +#endif + fre_service()->OpenFirstRunIfNeeded( + FirstRunService::EntryPoint::kOther, + ExpectProceed(second_proceed).Then(second_run_loop.QuitClosure())); + first_run_loop.Run(); + + histogram_tester.ExpectBucketCount( + "ProfilePicker.FirstRun.ExitStatus", + ProfilePicker::FirstRunExitStatus::kAbortTask, 1); + + ProfilePicker::Hide(); + profiles::testing::WaitForPickerClosed(); + second_run_loop.Run(); +} + #if BUILDFLAG(IS_CHROMEOS_LACROS) IN_PROC_BROWSER_TEST_F(FirstRunServiceBrowserTest, FinishedSilentlyAlreadySyncing) {
diff --git a/chrome/browser/ui/views/autofill/payments/manage_saved_iban_bubble_view.cc b/chrome/browser/ui/views/autofill/payments/manage_saved_iban_bubble_view.cc index 6d5e06bc..84e9f8d 100644 --- a/chrome/browser/ui/views/autofill/payments/manage_saved_iban_bubble_view.cc +++ b/chrome/browser/ui/views/autofill/payments/manage_saved_iban_bubble_view.cc
@@ -111,7 +111,7 @@ views::TableLayout::kFixedSize, provider->GetDistanceMetric(views::DISTANCE_RELATED_LABEL_HORIZONTAL)) .AddColumn(views::LayoutAlignment::kStretch, - views::LayoutAlignment::kCenter, 1.0, + views::LayoutAlignment::kStretch, 1.0, views::TableLayout::ColumnSize::kFixed, 0, 0) // Add a row for IBAN label and the value of IBAN. It might happen that // the revealed IBAN value is too long to fit in a single line while the
diff --git a/chrome/browser/ui/views/profiles/first_run_flow_sequence_diagram.png b/chrome/browser/ui/views/profiles/first_run_flow_sequence_diagram.png index f52e8d0..9fdaf3d 100644 --- a/chrome/browser/ui/views/profiles/first_run_flow_sequence_diagram.png +++ b/chrome/browser/ui/views/profiles/first_run_flow_sequence_diagram.png Binary files differ
diff --git a/chrome/browser/ui/views/profiles/profile_management.md b/chrome/browser/ui/views/profiles/profile_management.md index feb7a79..affdc7c 100644 --- a/chrome/browser/ui/views/profiles/profile_management.md +++ b/chrome/browser/ui/views/profiles/profile_management.md
@@ -27,14 +27,15 @@ activate FRS Caller->>FRS: OpenIfNeeded()<br/>with a ResumeTaskCallback<br/>aka void(bool success) callback deactivate Caller - note right of FRS: wraps ResumeTaskCallback as<br/>first_run_exited_callback having the<br/>signature void(FirstRunExitStatus) + note right of FRS: stores the ResumeTaskCallback and sends<br/> a first_run_exited_callback which is bound to <br/>OnFirstRunHasExited having the signature<br/>void(FirstRunExitStatus) FRS->>+PPV: ProfilePicker::Show()<br/>with first_run_exited_callback PPV->>+FC: Init() Note right of FC: FRE displayed,<br/>user advances through the flow. alt flow completed User->>FC: completes the flow - FC->>FRS: in PreFinishWithBrowser: run resume_task_callback with a<br/>success boolean based on the status + FC->>FRS: in PreFinishWithBrowser: run first_run_exited_callback with a<br/>success boolean based on the status + Note right of FRS: Handles the exit based on <br/>the status that is passed FRS->>+Caller: run ResumeTaskCallback<br/>with success=true Caller->>+Browser: launch browser deactivate Caller @@ -52,6 +53,14 @@ deactivate PPV FRS->>+Caller: run ResumeTaskCallback<br/>with success=false deactivate Caller + else chrome opened while first run is running + User->>+Caller: Open Chrome while the first run is still running + Caller->>FRS: OpenIfNeeded()<br/>with a ResumeTaskCallback<br/>aka void(bool success) callback + deactivate Caller + FRS->>+Caller: The first_run_exited_callback<br/>that was passed in the previous call to<br/>OpenIfNeeded() runs ResumeTaskCallback<br/> with success=false + deactivate Caller + FRS->>PPV: ProfilePicker::Show()<br/>with first_run_exited_callback + Note right of PPV: Opens the profile picker<br/> that has the first run already running. end deactivate FRS
diff --git a/chrome/browser/ui/views/side_panel/search_companion/search_companion_side_panel_coordinator.cc b/chrome/browser/ui/views/side_panel/search_companion/search_companion_side_panel_coordinator.cc index 815af2a..2397446 100644 --- a/chrome/browser/ui/views/side_panel/search_companion/search_companion_side_panel_coordinator.cc +++ b/chrome/browser/ui/views/side_panel/search_companion/search_companion_side_panel_coordinator.cc
@@ -29,6 +29,11 @@ SearchCompanionSidePanelCoordinator::~SearchCompanionSidePanelCoordinator() = default; +// static +bool SearchCompanionSidePanelCoordinator::IsSupported(Profile* profile) { + return !profile->IsIncognitoProfile() && !profile->IsGuestSession(); +} + void SearchCompanionSidePanelCoordinator:: CreateAndRegisterEntriesForExistingWebContents( TabStripModel* tab_strip_model) {
diff --git a/chrome/browser/ui/views/side_panel/search_companion/search_companion_side_panel_coordinator.h b/chrome/browser/ui/views/side_panel/search_companion/search_companion_side_panel_coordinator.h index cc988d3..9b8454df 100644 --- a/chrome/browser/ui/views/side_panel/search_companion/search_companion_side_panel_coordinator.h +++ b/chrome/browser/ui/views/side_panel/search_companion/search_companion_side_panel_coordinator.h
@@ -14,6 +14,7 @@ #include "chrome/browser/ui/views/side_panel/side_panel_entry.h" class Browser; +class Profile; namespace views { class View; @@ -32,6 +33,8 @@ const SearchCompanionSidePanelCoordinator&) = delete; ~SearchCompanionSidePanelCoordinator() override; + static bool IsSupported(Profile* profile); + void CreateAndRegisterEntriesForExistingWebContents( TabStripModel* tab_strip_model);
diff --git a/chrome/browser/ui/views/side_panel/side_panel_toolbar_container.cc b/chrome/browser/ui/views/side_panel/side_panel_toolbar_container.cc index b428b87..de192c3 100644 --- a/chrome/browser/ui/views/side_panel/side_panel_toolbar_container.cc +++ b/chrome/browser/ui/views/side_panel/side_panel_toolbar_container.cc
@@ -99,11 +99,16 @@ void SidePanelToolbarContainer::CreatePinnedEntryButtons() { DCHECK(pinned_entry_buttons_.empty()); - // The only pinned entry is the search companion. Add it here directly. - // If we support pinning side panel entries more broadly using this container - // then we can fetch the name and icon from the entry itself and update pinned - // entry toolbar buttons as the coordinator becomes aware of them. This sort - // of observation is unnecessary for now when there is only one pinned entry. + // The only pinned entry is the search companion. Add it here directly if + // supported. If we support pinning side panel entries more broadly using this + // container then we can fetch the name and icon from the entry itself and + // update pinned entry toolbar buttons as the coordinator becomes aware of + // them. This sort of observation is unnecessary for now when there is only + // one pinned entry. + if (!SearchCompanionSidePanelCoordinator::IsSupported( + browser_view_->GetProfile())) { + return; + } auto* search_companion_coordinator = SearchCompanionSidePanelCoordinator::GetOrCreateForBrowser( browser_view_->browser());
diff --git a/chrome/browser/ui/views/side_panel/side_panel_util.cc b/chrome/browser/ui/views/side_panel/side_panel_util.cc index fdae3203..f0fc94be 100644 --- a/chrome/browser/ui/views/side_panel/side_panel_util.cc +++ b/chrome/browser/ui/views/side_panel/side_panel_util.cc
@@ -92,7 +92,8 @@ } // Create Search Companion coordinator. - if (base::FeatureList::IsEnabled(features::kSidePanelCompanion)) { + if (base::FeatureList::IsEnabled(features::kSidePanelCompanion) && + SearchCompanionSidePanelCoordinator::IsSupported(browser->profile())) { SearchCompanionSidePanelCoordinator::GetOrCreateForBrowser(browser) ->CreateAndRegisterEntriesForExistingWebContents( browser->tab_strip_model());
diff --git a/chrome/browser/ui/webui/bookmarks/bookmarks_message_handler.cc b/chrome/browser/ui/webui/bookmarks/bookmarks_message_handler.cc index 5e774f36..b4af685 100644 --- a/chrome/browser/ui/webui/bookmarks/bookmarks_message_handler.cc +++ b/chrome/browser/ui/webui/bookmarks/bookmarks_message_handler.cc
@@ -7,8 +7,8 @@ #include "base/functional/bind.h" #include "base/values.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/common/pref_names.h" #include "components/bookmarks/common/bookmark_pref_names.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" @@ -32,7 +32,7 @@ PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); pref_change_registrar_.Init(prefs); pref_change_registrar_.Add( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, base::BindRepeating(&BookmarksMessageHandler::UpdateIncognitoAvailability, base::Unretained(this))); pref_change_registrar_.Add( @@ -47,7 +47,7 @@ int BookmarksMessageHandler::GetIncognitoAvailability() { PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs(); - return prefs->GetInteger(prefs::kIncognitoModeAvailability); + return prefs->GetInteger(policy::policy_prefs::kIncognitoModeAvailability); } void BookmarksMessageHandler::HandleGetIncognitoAvailability(
diff --git a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc index 93854b1..c932b5f 100644 --- a/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc +++ b/chrome/browser/ui/webui/new_tab_page/new_tab_page_ui.cc
@@ -200,6 +200,9 @@ base::FeatureList::IsEnabled(ntp_features::kNtpOneGoogleBar)); source->AddBoolean("shortcutsEnabled", base::FeatureList::IsEnabled(ntp_features::kNtpShortcuts)); + source->AddBoolean( + "singleRowShortcutsEnabled", + base::FeatureList::IsEnabled(ntp_features::kNtpSingleRowShortcuts)); source->AddBoolean("logoEnabled", base::FeatureList::IsEnabled(ntp_features::kNtpLogo)); source->AddBoolean(
diff --git a/chrome/browser/vr/chrome_xr_integration_client.cc b/chrome/browser/vr/chrome_xr_integration_client.cc index 26b69d19..903cd1de 100644 --- a/chrome/browser/vr/chrome_xr_integration_client.cc +++ b/chrome/browser/vr/chrome_xr_integration_client.cc
@@ -35,7 +35,7 @@ #include "components/webxr/android/arcore_install_helper.h" #endif // BUILDFLAG(ENABLE_ARCORE) #if BUILDFLAG(ENABLE_CARDBOARD) -#include "device/vr/android/cardboard/cardboard_device_provider.h" +#include "components/webxr/android/cardboard_device_provider.h" #endif #endif // BUILDFLAG(IS_WIN) @@ -120,7 +120,7 @@ // If the cardboard runtime is enabled we want to use it rather than the GVR // runtime. if (base::FeatureList::IsEnabled(device::features::kEnableCardboard)) { - providers.emplace_back(std::make_unique<device::CardboardDeviceProvider>()); + providers.emplace_back(std::make_unique<webxr::CardboardDeviceProvider>()); add_gvr_device_provider = false; } #endif // ENABLE_CARDBOARD
diff --git a/chrome/browser/web_applications/web_app.cc b/chrome/browser/web_applications/web_app.cc index a3cdc83e..fb6fc8e 100644 --- a/chrome/browser/web_applications/web_app.cc +++ b/chrome/browser/web_applications/web_app.cc
@@ -952,6 +952,10 @@ } json_decl.Set("feature", feature_name->second); base::Value::List allowlist_json; + // TODO(crbug.com/1418009): Consolidate code and filter opaque origins. + if (decl.self_if_matches) { + allowlist_json.Append(decl.self_if_matches->Serialize()); + } for (const auto& origin_with_possible_wildcards : decl.allowed_origins) { allowlist_json.Append(origin_with_possible_wildcards.Serialize()); }
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc index 96a01d6e..1953b679 100644 --- a/chrome/browser/web_applications/web_app_database.cc +++ b/chrome/browser/web_applications/web_app_database.cc
@@ -719,6 +719,10 @@ continue; const std::string feature_string(feature_name->second); proto_policy.set_feature(feature_string); + // TODO(crbug.com/1418009): Consolidate code and filter opaque origins. + if (decl.self_if_matches) { + proto_policy.add_allowed_origins(decl.self_if_matches->Serialize()); + } for (const auto& origin_with_possible_wildcards : decl.allowed_origins) { proto_policy.add_allowed_origins( origin_with_possible_wildcards.Serialize()); @@ -1376,9 +1380,15 @@ decl.feature = feature_enum->second; for (const std::string& origin : decl_proto.allowed_origins()) { - decl.allowed_origins.emplace_back( - blink::OriginWithPossibleWildcards::Parse( - origin, blink::OriginWithPossibleWildcards::NodeType::kHeader)); + absl::optional<blink::OriginWithPossibleWildcards> + maybe_origin_with_possible_wildcards = + blink::OriginWithPossibleWildcards::Parse( + origin, + blink::OriginWithPossibleWildcards::NodeType::kHeader); + if (maybe_origin_with_possible_wildcards.has_value()) { + decl.allowed_origins.emplace_back( + *maybe_origin_with_possible_wildcards); + } } decl.matches_all_origins = decl_proto.matches_all_origins(); decl.matches_opaque_src = decl_proto.matches_opaque_src();
diff --git a/chrome/browser/web_applications/web_app_database_unittest.cc b/chrome/browser/web_applications/web_app_database_unittest.cc index 3023556da..83b670bc 100644 --- a/chrome/browser/web_applications/web_app_database_unittest.cc +++ b/chrome/browser/web_applications/web_app_database_unittest.cc
@@ -706,11 +706,13 @@ TEST_F(WebAppDatabaseProtoDataTest, PermissionsPolicyRoundTrip) { const blink::ParsedPermissionsPolicy policy = { {blink::mojom::PermissionsPolicyFeature::kGyroscope, - {}, + /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/true}, {blink::mojom::PermissionsPolicyFeature::kGeolocation, - {}, + /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/true, /*matches_opaque_src=*/false}, {blink::mojom::PermissionsPolicyFeature::kGamepad, @@ -720,6 +722,7 @@ /*has_subdomain_wildcard=*/true}, {url::Origin::Create(GURL("https://*.example.net")), /*has_subdomain_wildcard=*/false}}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false}, }; @@ -733,11 +736,13 @@ TEST_F(WebAppDatabaseProtoDataTest, PermissionsPolicyProto) { const blink::ParsedPermissionsPolicy policy = { {blink::mojom::PermissionsPolicyFeature::kGyroscope, - {}, + /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/true}, {blink::mojom::PermissionsPolicyFeature::kGeolocation, - {}, + /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/true, /*matches_opaque_src=*/false}, {blink::mojom::PermissionsPolicyFeature::kGamepad, @@ -747,6 +752,7 @@ /*has_subdomain_wildcard=*/true}, {url::Origin::Create(GURL("https://*.example.net")), /*has_subdomain_wildcard=*/false}}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false}, };
diff --git a/chrome/browser/web_applications/web_app_install_utils.cc b/chrome/browser/web_applications/web_app_install_utils.cc index 94426248..7c7a922 100644 --- a/chrome/browser/web_applications/web_app_install_utils.cc +++ b/chrome/browser/web_applications/web_app_install_utils.cc
@@ -721,6 +721,7 @@ for (const auto& decl : manifest.permissions_policy) { blink::ParsedPermissionsPolicyDeclaration copy; copy.feature = decl.feature; + copy.self_if_matches = decl.self_if_matches; for (const auto& origin : decl.allowed_origins) copy.allowed_origins.push_back(origin); copy.matches_all_origins = decl.matches_all_origins;
diff --git a/chrome/browser/web_applications/web_app_unittest.cc b/chrome/browser/web_applications/web_app_unittest.cc index 7e315b632..044c4c1 100644 --- a/chrome/browser/web_applications/web_app_unittest.cc +++ b/chrome/browser/web_applications/web_app_unittest.cc
@@ -358,11 +358,13 @@ GURL("https://example.com"))}; app.SetPermissionsPolicy({ {blink::mojom::PermissionsPolicyFeature::kGyroscope, - {}, + /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/true}, {blink::mojom::PermissionsPolicyFeature::kGeolocation, - {}, + /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/true, /*matches_opaque_src=*/false}, {blink::mojom::PermissionsPolicyFeature::kGamepad, @@ -372,6 +374,7 @@ /*has_subdomain_wildcard=*/true}, {url::Origin::Create(GURL("https://*.example.net")), /*has_subdomain_wildcard=*/false}}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false}, });
diff --git a/chrome/browser/win/jumplist.cc b/chrome/browser/win/jumplist.cc index 6bb953f..399f4c3 100644 --- a/chrome/browser/win/jumplist.cc +++ b/chrome/browser/win/jumplist.cc
@@ -41,12 +41,12 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_icon_resources_win.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/pref_names.h" #include "chrome/grit/generated_resources.h" #include "chrome/install_static/install_util.h" #include "components/favicon/core/favicon_service.h" #include "components/history/core/browser/history_service.h" #include "components/history/core/browser/top_sites.h" +#include "components/policy/core/common/policy_pref_names.h" #include "components/prefs/pref_change_registrar.h" #include "components/sessions/core/session_types.h" #include "components/strings/grit/components_strings.h" @@ -269,7 +269,7 @@ // base::Unretained is safe since |this| is guaranteed to outlive // pref_change_registrar_. pref_change_registrar_->Add( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, base::BindRepeating(&JumpList::OnIncognitoAvailabilityChanged, base::Unretained(this))); }
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index 3c3f593..91bf43d 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-main-1679464574-855c77eb8be957c014ab9dd537a1dbe5271fb69e.profdata +chrome-linux-main-1679507993-1765debab62d0f8031bc4ec09e550bffdefe51c8.profdata
diff --git a/chrome/build/mac-arm.pgo.txt b/chrome/build/mac-arm.pgo.txt index 9e9e16d..4c1e6c4 100644 --- a/chrome/build/mac-arm.pgo.txt +++ b/chrome/build/mac-arm.pgo.txt
@@ -1 +1 @@ -chrome-mac-arm-main-1679500768-c62459bacc77b58e7c44c1bae05ccd7e939b6f74.profdata +chrome-mac-arm-main-1679507993-53772962ffb7f7587e0b7eae4acc0e20545d39a1.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index f2d64f5..ac08877 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-main-1679464574-4e3a85e8c457958c9d32e2e0fd5b2f0d93dd1e37.profdata +chrome-mac-main-1679507993-5ce6247e25bb4d58baed3029cf49e476eb4c399b.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index f3dd548..f2d43e0 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-main-1679475448-c4fd918cb966b8e797a63f1b533537af538f0796.profdata +chrome-win32-main-1679497124-36b8ab8885de68b05f317bec92a6a9f9c4a007e8.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index 7dc6921f..b47e9a8 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-main-1679497124-07b0619406614bb3158c4c387597025b38728e0f.profdata +chrome-win64-main-1679507993-848d6670ef5c4e4105bd1796882f08193c258730.profdata
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 3ff57c503..fe35de5 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc
@@ -330,12 +330,6 @@ const char kSSLErrorOverrideAllowedForOrigins[] = "ssl.error_override_allowed_for_origins"; -// Enum that specifies whether Incognito mode is: -// 0 - Enabled. Default behaviour. Default mode is available on demand. -// 1 - Disabled. User cannot browse pages in Incognito mode. -// 2 - Forced. All pages/sessions are forced into Incognito. -const char kIncognitoModeAvailability[] = "incognito.mode_availability"; - // Boolean that is true when Suggest support is enabled. const char kSearchSuggestEnabled[] = "search.suggest_enabled";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 6aa5392..26a664c 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h
@@ -159,7 +159,6 @@ #endif extern const char kSSLErrorOverrideAllowed[]; extern const char kSSLErrorOverrideAllowedForOrigins[]; -extern const char kIncognitoModeAvailability[]; extern const char kSearchSuggestEnabled[]; #if BUILDFLAG(IS_ANDROID) extern const char kContextualSearchEnabled[];
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index dd1c470..2a859f1f 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -66,6 +66,7 @@ # into the build. group("test") { testonly = true + deps = [ "fuzzing:test" ] } if (is_android) {
diff --git a/chrome/test/base/browser_tests_main_chromeos.cc b/chrome/test/base/browser_tests_main_chromeos.cc index 3b0c6fb..ecc7734 100644 --- a/chrome/test/base/browser_tests_main_chromeos.cc +++ b/chrome/test/base/browser_tests_main_chromeos.cc
@@ -7,6 +7,7 @@ #include "base/test/launcher/test_launcher.h" #include "chrome/test/base/chrome_test_launcher.h" #include "chrome/test/base/chrome_test_suite.h" +#include "content/public/common/content_switches.h" #include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h" #include "ui/base/test/ui_controls.h" @@ -52,5 +53,9 @@ // custom system tracing service. tracing::PerfettoTracedProcess::SetSystemProducerEnabledForTesting(false); + // Temporarily force the CPU backend to use AAA. (https://crbug.com/1421297) + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kForceSkiaAnalyticAntialiasing); + return LaunchChromeTests(parallel_jobs, &delegate, argc, argv); }
diff --git a/chrome/test/data/extensions/declarative_net_request/interest_group/fenced_frame.html b/chrome/test/data/extensions/declarative_net_request/interest_group/fenced_frame.html index 1f365a7..959d2704 100644 --- a/chrome/test/data/extensions/declarative_net_request/interest_group/fenced_frame.html +++ b/chrome/test/data/extensions/declarative_net_request/interest_group/fenced_frame.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> <html> <body> - <fencedframe mode=opaque-ads></fencedframe> + <fencedframe></fencedframe> </body> </html>
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index bde3d70..b79423f 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -90,10 +90,10 @@ "async_gen.js", "bookmarks/bookmarks_browsertest.js", "chrome_timeticks_browsertest.js", - "color_provider_css_colors_browsertest.js", "commander/commander_browsertest.js", "cr_components/cr_components_browsertest.js", "cr_elements/cr_elements_browsertest.js", + "css/css_browsertest.js", "histograms/histograms_internals_ui_browsertest.js", "history/history_browsertest.js", "invalidations/about_invalidations_browsertest.js", @@ -112,7 +112,6 @@ "settings/cr_settings_browsertest.js", "settings/privacy_sandbox_browsertest.js", "settings/settings_idle_load_browsertest.js", - "text_defaults_browsertest.js", "whats_new/whats_new_browsertest.js", ] @@ -381,8 +380,6 @@ in_files = [ "chai_assert.ts", "chrome_timeticks_test.ts", - "color_provider_css_colors_test_chromeos.ts", - "color_provider_css_colors_test.ts", "fake_chrome_event.ts", "invalidations/invalidations_test.ts", "metrics_test_support.ts", @@ -397,7 +394,6 @@ "test_plural_string_proxy.ts", "test_store_ts.ts", "test_util.ts", - "text_defaults_test.ts", "trusted_html.ts", # TODO(dpapad): Migrate the files below to TypeScript and remove allowJs @@ -448,6 +444,7 @@ "commander:build_grdp", "cr_components:build_grdp", "cr_elements:build_grdp", + "css:build_grdp", "discards:build_grdp", "downloads:build_grdp", "history:build_grdp", @@ -475,6 +472,7 @@ "$target_gen_dir/commander/resources.grdp", "$target_gen_dir/cr_components/resources.grdp", "$target_gen_dir/cr_elements/resources.grdp", + "$target_gen_dir/css/resources.grdp", "$target_gen_dir/discards/resources.grdp", "$target_gen_dir/downloads/resources.grdp", "$target_gen_dir/history/resources.grdp",
diff --git a/chrome/test/data/webui/build_webui_tests.gni b/chrome/test/data/webui/build_webui_tests.gni index bf0fa8c4..dd00f0ac 100644 --- a/chrome/test/data/webui/build_webui_tests.gni +++ b/chrome/test/data/webui/build_webui_tests.gni
@@ -10,11 +10,7 @@ template("build_webui_tests") { not_needed([ "target_name" ]) - forward_variables_from(invoker, - [ - "files", - "ts_deps", - ]) + forward_variables_from(invoker, [ "files" ]) preprocess_dir = "${target_gen_dir}/preprocessed" tsc_dir = "${target_gen_dir}/tsc" @@ -85,7 +81,10 @@ if (defined(invoker.ts_definitions)) { definitions = invoker.ts_definitions } - deps = [ "//chrome/test/data/webui:build_ts" ] + ts_deps + deps = [ "//chrome/test/data/webui:build_ts" ] + if (defined(invoker.ts_deps)) { + deps += invoker.ts_deps + } extra_deps = [ ":preprocess" ] if (defined(invoker.mojo_files)) {
diff --git a/chrome/test/data/webui/color_provider_css_colors_browsertest.js b/chrome/test/data/webui/color_provider_css_colors_browsertest.js deleted file mode 100644 index 291f5a8e..0000000 --- a/chrome/test/data/webui/color_provider_css_colors_browsertest.js +++ /dev/null
@@ -1,51 +0,0 @@ -// Copyright 2022 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -GEN('#include "build/chromeos_buildflags.h"'); -GEN('#include "content/public/test/browser_test.h"'); - -var ColorProviderCSSColorsTest = class extends testing.Test { - /** @override */ - get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=color_provider_css_colors_test.js'; - } - - /** @override */ - get isAsync() { - return true; - } - - /** @override */ - get extraLibraries() { - return [ - '//third_party/mocha/mocha.js', - '//chrome/test/data/webui/mocha_adapter.js', - ]; - } - - /** @override */ - get webuiHost() { - return 'dummyurl'; - } -}; - -TEST_F('ColorProviderCSSColorsTest', 'All', function() { - mocha.run(); -}); - -var ColorProviderCSSColorsTestChromeOS = - class extends ColorProviderCSSColorsTest { - /** @override */ - get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=color_provider_css_colors_test_chromeos.js'; - } -}; - -GEN('#if BUILDFLAG(IS_CHROMEOS_ASH)'); - -TEST_F('ColorProviderCSSColorsTestChromeOS', 'All', function() { - mocha.run(); -}); - -GEN('#endif // BUILDFLAG(IS_CHROMEOS_ASH)');
diff --git a/chrome/test/data/webui/cr_components/cr_components_mojo_browsertest.js b/chrome/test/data/webui/cr_components/cr_components_mojo_browsertest.js index d8e02df..d92b665 100644 --- a/chrome/test/data/webui/cr_components/cr_components_mojo_browsertest.js +++ b/chrome/test/data/webui/cr_components/cr_components_mojo_browsertest.js
@@ -86,6 +86,14 @@ runMochaSuite('General'); }); +TEST_F('CrComponentsMostVisitedTest', 'Layouts', function() { + runMochaSuite('Layouts'); +}); + +TEST_F('CrComponentsMostVisitedTest', 'LoggingAndUpdates', function() { + runMochaSuite('LoggingAndUpdates'); +}); + // crbug.com/1226996 GEN('#if BUILDFLAG(IS_LINUX) && !defined(NDEBUG)'); GEN('#define MAYBE_Modification DISABLED_Modification'); @@ -96,6 +104,10 @@ runMochaSuite('Modification'); }); +TEST_F('CrComponentsMostVisitedTest', 'DragAndDrop', function() { + runMochaSuite('DragAndDrop'); +}); + TEST_F('CrComponentsMostVisitedTest', 'Theming', function() { runMochaSuite('Theming'); });
diff --git a/chrome/test/data/webui/cr_components/most_visited_test.ts b/chrome/test/data/webui/cr_components/most_visited_test.ts index 39eabed..e9910236 100644 --- a/chrome/test/data/webui/cr_components/most_visited_test.ts +++ b/chrome/test/data/webui/cr_components/most_visited_test.ts
@@ -26,9 +26,7 @@ let handler: TestMock<MostVisitedPageHandlerRemote>& MostVisitedPageHandlerRemote; let callbackRouterRemote: MostVisitedPageRemote; -let mediaListenerWideWidth: FakeMediaQueryList; -let mediaListenerMediumWidth: FakeMediaQueryList; -let mediaListener: Function; +const mediaListenerLists: Map<number, FakeMediaQueryList> = new Map(); function queryAll<E extends Element = Element>(q: string): E[] { return Array.from(mostVisited.shadowRoot!.querySelectorAll<E>(q)); @@ -106,10 +104,7 @@ this.media = query; } - addListener(listener: () => void) { - mediaListener = listener; - } - + addListener() {} removeListener() {} onchange() {} } @@ -117,25 +112,25 @@ function createWindowProxy() { windowProxy = TestMock.fromClass(MostVisitedWindowProxy); windowProxy.setResultMapperFor('matchMedia', (query: string) => { + const result = query.match(/\(min-width: (\d+)px\)/); + assertTrue(!!result); const mediaListenerList = new FakeMediaQueryList(query); - if (query === '(min-width: 672px)') { - mediaListenerWideWidth = mediaListenerList; - } else if (query === '(min-width: 560px)') { - mediaListenerMediumWidth = mediaListenerList; - } else { - assertTrue(false); - } + mediaListenerLists.set(parseInt(result![1]!), mediaListenerList); return mediaListenerList; }); MostVisitedWindowProxy.setInstance(windowProxy); } function updateScreenWidth(isWide: boolean, isMedium: boolean) { + mediaListenerLists.forEach(list => list.matches = false); + const mediaListenerWideWidth = + mediaListenerLists.get(Math.max(...mediaListenerLists.keys())); + const mediaListenerMediumWidth = mediaListenerLists.get(560); assertTrue(!!mediaListenerWideWidth); assertTrue(!!mediaListenerMediumWidth); - mediaListenerWideWidth.matches = isWide; - mediaListenerMediumWidth.matches = isMedium; - mediaListener(); + mediaListenerWideWidth!.matches = isWide; + mediaListenerMediumWidth!.matches = isMedium; + mediaListenerMediumWidth!.dispatchEvent(new Event('change')); } function wide() { @@ -146,18 +141,22 @@ $$(mostVisited, '#dialogInputUrl').dispatchEvent(new Event('blur')); } +function setUpTest(singleRow: boolean) { + document.body.innerHTML = window.trustedTypes!.emptyHTML; + + createBrowserProxy(); + createWindowProxy(); + + mostVisited = new MostVisitedElement(); + mostVisited.singleRow = singleRow; + document.body.appendChild(mostVisited); + assertEquals(1, handler.getCallCount('updateMostVisitedInfo')); + wide(); +} + suite('General', () => { setup(() => { - document.body.innerHTML = window.trustedTypes!.emptyHTML; - - createBrowserProxy(); - createWindowProxy(); - - mostVisited = new MostVisitedElement(); - document.body.appendChild(mostVisited); - assertEquals(1, handler.getCallCount('updateMostVisitedInfo')); - assertEquals(2, windowProxy.getCallCount('matchMedia')); - wide(); + setUpTest(/*singleRow=*/ false); }); test('empty shows add shortcut only', async () => { @@ -189,6 +188,12 @@ new KeyboardEvent('keyup', {key: ' '})); assertTrue(mostVisited.$.dialog.open); }); +}); + +function createLayoutsSuite(singleRow: boolean) { + setup(() => { + setUpTest(singleRow); + }); test('four tiles fit on one line with addShortcut', async () => { await addTiles(4); @@ -202,7 +207,7 @@ }); }); - test('five tiles are displayed on two rows with addShortcut', async () => { + test('five tiles are displayed with addShortcut', async () => { await addTiles(5); assertEquals(5, queryTiles().length); assertAddShortcutShown(); @@ -211,7 +216,11 @@ assertEquals(6, tops.length); const firstRowTop = tops[0]; const secondRowTop = tops[3]; - assertNotEquals(firstRowTop, secondRowTop); + if (singleRow) { + assertEquals(firstRowTop, secondRowTop); + } else { + assertNotEquals(firstRowTop, secondRowTop); + } tops.slice(0, 3).forEach(top => { assertEquals(firstRowTop, top); }); @@ -220,7 +229,7 @@ }); }); - test('nine tiles are displayed on two rows with addShortcut', async () => { + test('nine tiles are displayed with addShortcut', async () => { await addTiles(9); assertEquals(9, queryTiles().length); assertAddShortcutShown(); @@ -229,7 +238,11 @@ assertEquals(10, tops.length); const firstRowTop = tops[0]; const secondRowTop = tops[5]; - assertNotEquals(firstRowTop, secondRowTop); + if (singleRow) { + assertEquals(firstRowTop, secondRowTop); + } else { + assertNotEquals(firstRowTop, secondRowTop); + } tops.slice(0, 5).forEach(top => { assertEquals(firstRowTop, top); }); @@ -238,7 +251,7 @@ }); }); - test('ten tiles are displayed on two rows without addShortcut', async () => { + test('ten tiles are displayed without addShortcut', async () => { await addTiles(10); assertEquals(10, queryTiles().length); assertAddShortcutHidden(); @@ -246,7 +259,11 @@ assertEquals(10, tops.length); const firstRowTop = tops[0]; const secondRowTop = tops[5]; - assertNotEquals(firstRowTop, secondRowTop); + if (singleRow) { + assertEquals(firstRowTop, secondRowTop); + } else { + assertNotEquals(firstRowTop, secondRowTop); + } tops.slice(0, 5).forEach(top => { assertEquals(firstRowTop, top); }); @@ -311,56 +328,64 @@ updateScreenWidth(false, false); } - test('six is max for narrow', async () => { + test('six / three is max for narrow', async () => { await addTiles(7); medium(); assertTileLength(7); - assertHiddenTileLength(0); + assertHiddenTileLength(singleRow ? 3 : 0); narrow(); assertTileLength(7); - assertHiddenTileLength(1); + assertHiddenTileLength(singleRow ? 4 : 1); medium(); assertTileLength(7); - assertHiddenTileLength(0); + assertHiddenTileLength(singleRow ? 3 : 0); }); - test('eight is max for medium', async () => { + test('eight / four is max for medium', async () => { await addTiles(8); narrow(); assertTileLength(8); - assertHiddenTileLength(2); + assertHiddenTileLength(singleRow ? 5 : 2); medium(); assertTileLength(8); - assertHiddenTileLength(0); + assertHiddenTileLength(singleRow ? 4 : 0); narrow(); assertTileLength(8); - assertHiddenTileLength(2); + assertHiddenTileLength(singleRow ? 5 : 2); }); test('eight is max for wide', async () => { await addTiles(8); narrow(); assertTileLength(8); - assertHiddenTileLength(2); + assertHiddenTileLength(singleRow ? 5 : 2); wide(); assertTileLength(8); assertHiddenTileLength(0); narrow(); assertTileLength(8); - assertHiddenTileLength(2); + assertHiddenTileLength(singleRow ? 5 : 2); }); - test('hide add shortcut if on third row (narrow)', async () => { + test('hide add shortcut (narrow)', async () => { await addTiles(6); medium(); - assertAddShortcutShown(); + if (singleRow) { + assertAddShortcutHidden(); + } else { + assertAddShortcutShown(); + } narrow(); assertAddShortcutHidden(); medium(); - assertAddShortcutShown(); + if (singleRow) { + assertAddShortcutHidden(); + } else { + assertAddShortcutShown(); + } }); - test('hide add shortcut if on third row (medium)', async () => { + test('hide add shortcut with 8 tiles (medium)', async () => { await addTiles(8); wide(); assertAddShortcutShown(); @@ -370,13 +395,43 @@ assertAddShortcutShown(); }); - test('hide add shortcut if on third row (medium)', async () => { + test('hide add shortcut with 9 tiles (medium)', async () => { await addTiles(9); wide(); assertAddShortcutShown(); await addTiles(10); assertAddShortcutHidden(); }); + + if (singleRow) { + test('shows correct number of tiles for all widths', async () => { + await addTiles(12); + mediaListenerLists.forEach(list => list.matches = false); + [...mediaListenerLists.keys()] + .sort((a, b) => a - b) + .forEach((width, i) => { + const list = mediaListenerLists.get(width)!; + list.matches = true; + list.dispatchEvent(new Event('change')); + assertHiddenTileLength(6 - i); + }); + }); + } + }); +} + +suite('Layouts', () => { + suite('double row', () => { + createLayoutsSuite(false); + }); + suite('single row', () => { + createLayoutsSuite(true); + }); +}); + +suite('LoggingAndUpdates', () => { + setup(() => { + setUpTest(/*singleRow=*/ false); }); test('rendering tiles logs event', async () => { @@ -458,16 +513,7 @@ }); setup(() => { - document.body.innerHTML = window.trustedTypes!.emptyHTML; - - createBrowserProxy(); - createWindowProxy(); - - mostVisited = new MostVisitedElement(); - document.body.appendChild(mostVisited); - assertEquals(1, handler.getCallCount('updateMostVisitedInfo')); - assertEquals(2, windowProxy.getCallCount('matchMedia')); - wide(); + setUpTest(/*singleRow=*/ false); }); suite('add dialog', () => { @@ -918,6 +964,13 @@ await wait; assertFalse(toast.open); }); +}); + + +function createDragAndDropSuite(singleRow: boolean) { + setup(() => { + setUpTest(singleRow); + }); test('drag first tile to second position', async () => { await addTiles(2); @@ -1002,20 +1055,20 @@ assertEquals('https://a/', newFirst!.href); assertEquals('https://b/', newSecond!.href); }); +} + +suite('DragAndDrop', () => { + suite('double row', () => { + createDragAndDropSuite(false); + }); + suite('single row', () => { + createDragAndDropSuite(true); + }); }); suite('Theming', () => { setup(() => { - document.body.innerHTML = window.trustedTypes!.emptyHTML; - - createBrowserProxy(); - createWindowProxy(); - - mostVisited = new MostVisitedElement(); - document.body.appendChild(mostVisited); - assertEquals(1, handler.getCallCount('updateMostVisitedInfo')); - assertEquals(2, windowProxy.getCallCount('matchMedia')); - wide(); + setUpTest(/*singleRow=*/ false); }); test('RIGHT_TO_LEFT tile title text direction', async () => {
diff --git a/chrome/test/data/webui/css/BUILD.gn b/chrome/test/data/webui/css/BUILD.gn new file mode 100644 index 0000000..028513e0 --- /dev/null +++ b/chrome/test/data/webui/css/BUILD.gn
@@ -0,0 +1,17 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("../build_webui_tests.gni") + +build_webui_tests("build") { + resource_path_prefix = "css" + + files = [ + "color_provider_css_colors_test.ts", + "text_defaults_test.ts", + ] + if (is_chromeos_ash) { + files += [ "color_provider_css_colors_test_chromeos.ts" ] + } +}
diff --git a/chrome/test/data/webui/color_provider_css_colors_test.ts b/chrome/test/data/webui/css/color_provider_css_colors_test.ts similarity index 95% rename from chrome/test/data/webui/color_provider_css_colors_test.ts rename to chrome/test/data/webui/css/color_provider_css_colors_test.ts index 20a609e..4ac7d77 100644 --- a/chrome/test/data/webui/color_provider_css_colors_test.ts +++ b/chrome/test/data/webui/css/color_provider_css_colors_test.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {assertEquals, assertNotEquals} from './chai_assert.js'; +import {assertEquals, assertNotEquals} from 'chrome://webui-test/chai_assert.js'; suite('ColorProviderCSSColorsTest', function() { let link: HTMLLinkElement;
diff --git a/chrome/test/data/webui/color_provider_css_colors_test_chromeos.ts b/chrome/test/data/webui/css/color_provider_css_colors_test_chromeos.ts similarity index 94% rename from chrome/test/data/webui/color_provider_css_colors_test_chromeos.ts rename to chrome/test/data/webui/css/color_provider_css_colors_test_chromeos.ts index f8c5347..b65c45a 100644 --- a/chrome/test/data/webui/color_provider_css_colors_test_chromeos.ts +++ b/chrome/test/data/webui/css/color_provider_css_colors_test_chromeos.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {assertNotEquals} from './chai_assert.js'; +import {assertNotEquals} from 'chrome://webui-test/chai_assert.js'; suite('ColorProviderCSSColorsTest', function() { let link: HTMLLinkElement;
diff --git a/chrome/test/data/webui/css/css_browsertest.js b/chrome/test/data/webui/css/css_browsertest.js new file mode 100644 index 0000000..ec5454f --- /dev/null +++ b/chrome/test/data/webui/css/css_browsertest.js
@@ -0,0 +1,61 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +GEN('#include "build/chromeos_buildflags.h"'); +GEN('#include "content/public/test/browser_test.h"'); + +var CssTest = class extends testing.Test { + /** @override */ + get browsePreload() { + throw new Error('Should be overriden by subclasses'); + } + + /** @override */ + get isAsync() { + return true; + } + + /** @override */ + get webuiHost() { + return 'dummyurl'; + } +}; + +var TextDefaultsTest = class extends CssTest { + /** @override */ + get browsePreload() { + return 'chrome://webui-test/test_loader.html?module=css/text_defaults_test.js'; + } +}; + +TEST_F('TextDefaultsTest', 'All', function() { + mocha.run(); +}); + +var ColorProviderCSSColorsTest = class extends CssTest { + /** @override */ + get browsePreload() { + return 'chrome://webui-test/test_loader.html?module=css/color_provider_css_colors_test.js'; + } +}; + +TEST_F('ColorProviderCSSColorsTest', 'All', function() { + mocha.run(); +}); + +GEN('#if BUILDFLAG(IS_CHROMEOS_ASH)'); + +var ColorProviderCSSColorsTestChromeOS = + class extends ColorProviderCSSColorsTest { + /** @override */ + get browsePreload() { + return 'chrome://webui-test/test_loader.html?module=css/color_provider_css_colors_test_chromeos.js'; + } +}; + +TEST_F('ColorProviderCSSColorsTestChromeOS', 'All', function() { + mocha.run(); +}); + +GEN('#endif // BUILDFLAG(IS_CHROMEOS_ASH)');
diff --git a/chrome/test/data/webui/text_defaults_test.ts b/chrome/test/data/webui/css/text_defaults_test.ts similarity index 93% rename from chrome/test/data/webui/text_defaults_test.ts rename to chrome/test/data/webui/css/text_defaults_test.ts index 2fdc524..a2cb0dc 100644 --- a/chrome/test/data/webui/text_defaults_test.ts +++ b/chrome/test/data/webui/css/text_defaults_test.ts
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import {assertNotEquals, assertTrue} from './chai_assert.js'; +import {assertNotEquals, assertTrue} from 'chrome://webui-test/chai_assert.js'; suite('TextDefaults', function() { setup(function() {
diff --git a/chrome/test/data/webui/settings/chromeos/chromevox_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/chromevox_subpage_tests.js index d0f804b..27aa027 100644 --- a/chrome/test/data/webui/settings/chromeos/chromevox_subpage_tests.js +++ b/chrome/test/data/webui/settings/chromeos/chromevox_subpage_tests.js
@@ -127,6 +127,35 @@ }); }); + test('event stream filter toggles sync to prefs', async () => { + // Enable event stream logging to allow enabling filter toggles. + const loggingToggle = + page.shadowRoot.querySelector('#enableEventStreamLoggingToggle'); + loggingToggle.click(); + await waitAfterNextRender(loggingToggle); + + // Get all event stream filter prefs. + let pref = page.getPref('settings.a11y.chromevox.event_stream_filters'); + + // Toggle each filter, verify each pref is set. + page.eventStreamFilters_.forEach(filter => { + const toggle = page.shadowRoot.querySelector('#' + filter); + + // Make sure toggle exists. + assertTrue(!!toggle); + + // Make sure pref filter state is false or undefined (key is not present). + assertTrue([false, undefined].includes(pref.value[filter])); + + // Enable event stream filter toggle. + toggle.click(); + + // Make sure event stream filter pref state is true. + pref = page.getPref('settings.a11y.chromevox.event_stream_filters'); + assertTrue(pref.value[filter]); + }); + }); + test('voices are ordered', async function() { // Make sure voices are ordered with the system default voice first, then // Google voices, then eSpeak, then local, then remote.
diff --git a/chrome/test/data/webui/text_defaults_browsertest.js b/chrome/test/data/webui/text_defaults_browsertest.js deleted file mode 100644 index f27d4a56..0000000 --- a/chrome/test/data/webui/text_defaults_browsertest.js +++ /dev/null
@@ -1,40 +0,0 @@ -// Copyright 2016 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -GEN('#include "content/public/test/browser_test.h"'); - -/** - * Test fixture for testing async methods of cr.js. - */ -var TextDefaultsTest = class extends testing.Test { - /** - * @override - */ - get browsePreload() { - return 'chrome://webui-test/test_loader.html?module=text_defaults_test.js'; - } - - /** @override */ - get isAsync() { - return true; - } - - /** @override */ - get extraLibraries() { - return [ - '//third_party/mocha/mocha.js', - '//chrome/test/data/webui/mocha_adapter.js', - ]; - } - - /** @override */ - get webuiHost() { - return 'dummyurl'; - } -}; - - -TEST_F('TextDefaultsTest', 'All', function() { - mocha.run(); -});
diff --git a/chrome/test/fuzzing/BUILD.gn b/chrome/test/fuzzing/BUILD.gn new file mode 100644 index 0000000..a118478 --- /dev/null +++ b/chrome/test/fuzzing/BUILD.gn
@@ -0,0 +1,38 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/buildflag_header.gni") +import("//chrome/test/fuzzing/in_process_fuzz_test.gni") + +# This target exists to reference other test executables to bring these files +# into the build. +group("test") { + testonly = true +} + +if (fuzzing_engine_supports_custom_main) { + static_library("in_process_fuzz_test_runner") { + testonly = true + sources = [ + "in_process_fuzz_test.cc", + "in_process_fuzz_test.h", + ] + deps = [ + ":in_process_fuzzing_buildflags", + "//testing/libfuzzer:fuzzing_engine_no_main", + ] + public_deps = [ "//chrome/test:test_support" ] + } + + buildflag_header("in_process_fuzzing_buildflags") { + header = "in_process_fuzzing_buildflags.h" + flags = [ "AVOID_SINGLE_PROCESS_MODE=$use_libfuzzer" ] + } +} + +if (!is_android) { + in_process_fuzz_test("html_in_process_fuzz_tests") { + sources = [ "html_in_process_fuzz_test.cc" ] + } +}
diff --git a/chrome/test/fuzzing/OWNERS b/chrome/test/fuzzing/OWNERS new file mode 100644 index 0000000..2f8c6f2 --- /dev/null +++ b/chrome/test/fuzzing/OWNERS
@@ -0,0 +1 @@ +file://testing/libfuzzer/OWNERS
diff --git a/chrome/test/fuzzing/html_in_process_fuzz_test.cc b/chrome/test/fuzzing/html_in_process_fuzz_test.cc new file mode 100644 index 0000000..17105aa --- /dev/null +++ b/chrome/test/fuzzing/html_in_process_fuzz_test.cc
@@ -0,0 +1,56 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/test/base/ui_test_utils.h" +#include "chrome/test/fuzzing/in_process_fuzz_test.h" +#include "content/public/browser/browser_task_traits.h" +#include "net/dns/mock_host_resolver.h" +#include "net/test/embedded_test_server/embedded_test_server.h" + +// This is an example use of the InProcessFuzzTest framework. +// It fetches arbitrary HTML from an HTTPS server. It's not really +// intended to be an effective fuzzer, but just to show an example +// of how this framework can be used. + +class HtmlInProcessFuzzTest : virtual public InProcessFuzzTest { + public: + HtmlInProcessFuzzTest() + : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {} + + void SetUpOnMainThread() override { + InProcessFuzzTest::SetUpOnMainThread(); + host_resolver()->AddRule("*", "127.0.0.1"); + https_test_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_OK); + https_test_server_.RegisterRequestHandler(base::BindRepeating( + &HtmlInProcessFuzzTest::HandleHTTPRequest, base::Unretained(this))); + ASSERT_TRUE(https_test_server_.Start()); + } + int Fuzz(const uint8_t* data, size_t size) override; + std::unique_ptr<net::test_server::HttpResponse> HandleHTTPRequest( + const net::test_server::HttpRequest& request) const; + + net::EmbeddedTestServer https_test_server_; + std::string current_fuzz_case_; +}; + +REGISTER_IN_PROCESS_FUZZER(HtmlInProcessFuzzTest) + +std::unique_ptr<net::test_server::HttpResponse> +HtmlInProcessFuzzTest::HandleHTTPRequest( + const net::test_server::HttpRequest& request) const { + std::unique_ptr<net::test_server::BasicHttpResponse> response; + response = std::make_unique<net::test_server::BasicHttpResponse>(); + response->set_content_type("text/html"); + response->set_content(current_fuzz_case_); + response->set_code(net::HTTP_OK); + return response; +} + +int HtmlInProcessFuzzTest::Fuzz(const uint8_t* data, size_t size) { + std::string html_string(reinterpret_cast<const char*>(data), size); + current_fuzz_case_ = html_string; + GURL test_url = https_test_server_.GetURL("/test.html"); + base::IgnoreResult(ui_test_utils::NavigateToURL(browser(), test_url)); + return 0; +}
diff --git a/chrome/test/fuzzing/in_process_fuzz_test.cc b/chrome/test/fuzzing/in_process_fuzz_test.cc new file mode 100644 index 0000000..76abbab --- /dev/null +++ b/chrome/test/fuzzing/in_process_fuzz_test.cc
@@ -0,0 +1,181 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <vector> + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/functional/callback_forward.h" +#include "base/test/bind.h" +#include "chrome/test/base/chrome_test_launcher.h" +#include "chrome/test/fuzzing/in_process_fuzz_test.h" +#include "chrome/test/fuzzing/in_process_fuzzing_buildflags.h" +#include "content/public/app/content_main.h" +#include "content/public/test/test_launcher.h" + +// This is provided within libfuzzer, and documented, but is not its headers. +extern "C" int LLVMFuzzerRunDriver(int* argc, + char*** argv, + int (*UserCb)(const uint8_t* Data, + size_t Size)); + +InProcessFuzzTestFactoryBase* g_in_process_fuzz_test_factory; + +InProcessFuzzTest::InProcessFuzzTest() = default; + +InProcessFuzzTest::~InProcessFuzzTest() = default; + +base::CommandLine::StringVector +InProcessFuzzTest::GetChromiumCommandLineArguments() { + base::CommandLine::StringVector empty; + return empty; +} + +void InProcessFuzzTest::Run( + const std::vector<std::string>& libfuzzer_command_line) { + libfuzzer_command_line_ = libfuzzer_command_line; + SetUp(); + TearDown(); +} + +void InProcessFuzzTest::SetUpOnMainThread() { + InProcessBrowserTest::SetUpOnMainThread(); +} + +InProcessFuzzTest* g_test; + +class FuzzTestLauncherDelegate : public content::TestLauncherDelegate { + public: + FuzzTestLauncherDelegate(std::unique_ptr<InProcessFuzzTest>&& fuzz_test, + std::vector<std::string>&& libfuzzer_arguments) + : fuzz_test_(std::move(fuzz_test)), + libfuzzer_arguments_(std::move(libfuzzer_arguments)) { + content_main_delegate_ = + std::make_unique<ChromeTestChromeMainDelegate>(base::TimeTicks::Now()); + } + + int RunTestSuite(int argc, char** argv) override { + fuzz_test_->Run(libfuzzer_arguments_); + return 0; + } +#if !BUILDFLAG(IS_ANDROID) + // Android browser tests set the ContentMainDelegate itself for the test + // harness to use, and do not go through ContentMain() in TestLauncher. + content::ContentMainDelegate* CreateContentMainDelegate() override { + return &*content_main_delegate_; + } +#endif + + private: + std::unique_ptr<InProcessFuzzTest> fuzz_test_; + std::unique_ptr<content::ContentMainDelegate> + content_main_delegate_; // TODO remove unique_ptr + std::vector<std::string> libfuzzer_arguments_; +}; + +int fuzz_callback(const uint8_t* data, size_t size) { + return g_test->FuzzCallback(data, size); +} + +int InProcessFuzzTest::FuzzCallback(const uint8_t* data, size_t size) { + int result; + base::RunLoop run_loop; + + base::RepeatingCallback<void()> run_fuzz_case_lambda = + base::BindLambdaForTesting([&]() { + result = Fuzz(data, size); + run_loop.QuitClosure().Run(); + }); + base::SequencedTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, run_fuzz_case_lambda); + run_loop.Run(); + return result; +} + +void InProcessFuzzTest::FuzzCaseFinished( + int* result_storage, + const base::RepeatingClosure& quit_closure, + int result) { + *result_storage = result; + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE, + quit_closure); +} + +void InProcessFuzzTest::RunTestOnMainThread() { + std::vector<char*> argv; + for (const auto& arg : libfuzzer_command_line_) { + argv.push_back((char*)arg.data()); + } + argv.push_back(nullptr); + int argc = argv.size() - 1; + char** argv2 = argv.data(); + g_test = this; + base::IgnoreResult(LLVMFuzzerRunDriver(&argc, &argv2, fuzz_callback)); + g_test = nullptr; +} + +// Main function for running in process fuzz tests. +// This aims to replicate //chrome browser tests as much as possible; we want +// the whole browser environment to be available for this sort of test in as +// realistic a fashion as possible. +int main(int argc, char** argv) { + base::AtExitManager atexit_manager; + base::CommandLine::Init(argc, argv); + + std::unique_ptr<InProcessFuzzTest> fuzzer = + g_in_process_fuzz_test_factory->CreateInProcessFuzzer(); + + // Oh dear, you've got to the part of the code relating to command lines. + // I'm sorry. + // Here are our constraints: + // * Both libfuzzer/centipede and Chromium expect a full command line + // * We set the format of neither command line + // * Chromium will launch other Chromium processes, giving them a command + // line. + // * The centipede runner will launch our fuzzer, giving it a command line. + // So, at this point, we have to figure out heuristics for what's up. + // Are we the original fuzzer process, in which case we pass the CLI to + // libfuzzer/centipede, and ask for a suitable Chromium command line from + // our fuzz test? Or, are we a child Chromium process which has been + // launched from a previous Chromium process? Well, dear reader, there are + // no telltail arguments guaranteed to be on either, so we're going to + // use a heuristic. If the first argument starts with --, we're assuming + // we're a Chromium child. + + bool we_are_probably_a_chromium_child_process = false; + if (base::CommandLine::ForCurrentProcess()->argv().size() > 1) { + if (base::CommandLine::ForCurrentProcess()->argv()[1].starts_with("--")) { + we_are_probably_a_chromium_child_process = true; + } + } + std::vector<std::string> libfuzzer_arguments; + if (we_are_probably_a_chromium_child_process) { + // If we're a Chromium child, we don't alter the command-line, + // and in fact the libfuzzer code will never run, so we don't need to + // pass any arguments through to libfuzzer. + } else { + libfuzzer_arguments = base::CommandLine::ForCurrentProcess()->argv(); + std::string executable_name = libfuzzer_arguments.at(0); + base::CommandLine::StringVector chromium_arguments = + fuzzer->GetChromiumCommandLineArguments(); + chromium_arguments.insert(chromium_arguments.begin(), executable_name); + chromium_arguments.push_back("--single-process-tests"); +#if !BUILDFLAG(AVOID_SINGLE_PROCESS_MODE) + // TODO(1038952): make libfuzzer compatible with single-process mode. + // As it stands, single-process mode works with centipede (and is probably + // desirable both in terms of fuzzing speed and correctly gathering + // coverage information) but not yet with libfuzzer. + chromium_arguments.push_back("--single-process"); +#endif // BUILDFLAG(AVOID_SINGLE_PROCESS_MODE) + chromium_arguments.push_back("--no-sandbox"); + chromium_arguments.push_back("--no-zygote"); + chromium_arguments.push_back("--disable-gpu"); + base::CommandLine::ForCurrentProcess()->InitFromArgv(chromium_arguments); + } + + FuzzTestLauncherDelegate* fuzz_test_launcher_delegate = + new FuzzTestLauncherDelegate(std::move(fuzzer), + std::move(libfuzzer_arguments)); + return content::LaunchTests(fuzz_test_launcher_delegate, 1, argc, argv); +}
diff --git a/chrome/test/fuzzing/in_process_fuzz_test.gni b/chrome/test/fuzzing/in_process_fuzz_test.gni new file mode 100644 index 0000000..81b0de62 --- /dev/null +++ b/chrome/test/fuzzing/in_process_fuzz_test.gni
@@ -0,0 +1,35 @@ +# Copyright 2023 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//testing/libfuzzer/fuzzer_test.gni") + +# This template allows creation of a fuzzer which has access to all the +# functionality of a browser_test, including a full GUI instance of Chromium. +# See in_process_fuzz_test.h. +# +# It accepts all the same arguments as //testing/libfuzzer/fuzzer_test.gni's +# fuzzer_test template. +template("in_process_fuzz_test") { + if (fuzzing_engine_supports_custom_main) { + fuzzer_test(target_name) { + deps = [ "//chrome/test/fuzzing:in_process_fuzz_test_runner" ] + if (defined(invoker.deps)) { + deps += invoker.deps + } + forward_variables_from(invoker, + "*", + [ + "deps", + "exclude_main", + ]) + exclude_main = true + } + } else { + # noop if the fuzzer harness always provides its own main + not_needed(invoker, "*") + + group(target_name) { + } + } +}
diff --git a/chrome/test/fuzzing/in_process_fuzz_test.h b/chrome/test/fuzzing/in_process_fuzz_test.h new file mode 100644 index 0000000..20adb85 --- /dev/null +++ b/chrome/test/fuzzing/in_process_fuzz_test.h
@@ -0,0 +1,89 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_TEST_FUZZING_IN_PROCESS_FUZZ_TEST_H_ +#define CHROME_TEST_FUZZING_IN_PROCESS_FUZZ_TEST_H_ + +#include <optional> + +#include "chrome/test/base/in_process_browser_test.h" + +// In-process fuzz test. +// +// This is equivalent to a browser test, in that the entire browser +// environment is available for your use, and you can do rich things that +// require the whole browser infrastructure. +// +// The 'Fuzz' method will be called repeatedly, and you just have to +// implement something sensible there to explore parts of Chrome's +// attack surface. +// +// Register your subclass with REGISTER_IN_PROCESS_FUZZER. There can only +// be one per executable. +class InProcessFuzzTest : virtual public InProcessBrowserTest { + public: + // Called by the main function to create this class. + // This is called prior to all the normal browser test setup, + // so don't do anything important in your constructor. + // Furthermore, this will be re-run even for child Chromium processes. + InProcessFuzzTest(); + ~InProcessFuzzTest() override; + + // Called by the main function to run this fuzzer, after the browser_test + // equivalent infrastructure has been set up. + void Run(const std::vector<std::string>& libfuzzer_command_line); + + // If you override this, it's essential you call the superclass method. + void SetUpOnMainThread() override; + void RunTestOnMainThread() override; + void TestBody() override {} + + friend int fuzz_callback(const uint8_t* data, size_t size); + + // Override if you want to pass particular command line arguments to + // Chromium for its startup. This is called before any fuzz test case + // is actually run, so unfortunately you can't generate these through + // fuzzing. In addition, the browser test framework itself does all + // sorts of fiddling with the arguments (e.g. a user data dir). + // It's generally OK to leave this at the default unless you specifically + // need to enable a feature or similar. + // Do not include the executable name in your return value - that's + // prepended automatically. + virtual base::CommandLine::StringVector GetChromiumCommandLineArguments(); + + protected: + // Callback to actually do your fuzzing. This is called from the UI thread, + // so you should take care not to block the thread too long. If you need + // to run your fuzz case across multiple threads, consider a nested RunLoop. + virtual int Fuzz(const uint8_t* data, size_t size) = 0; + + private: + int FuzzCallback(const uint8_t* data, size_t size); + void FuzzCaseFinished(int* result_storage, + const base::RepeatingClosure& quit_closure, + int result); + std::vector<std::string> libfuzzer_command_line_; +}; + +class InProcessFuzzTestFactoryBase { + public: + virtual std::unique_ptr<InProcessFuzzTest> CreateInProcessFuzzer() = 0; +}; + +extern InProcessFuzzTestFactoryBase* g_in_process_fuzz_test_factory; + +// Class used to register a single in-process fuzzer in each executable. +template <typename T> +class InProcessFuzzTestFactory : public InProcessFuzzTestFactoryBase { + public: + InProcessFuzzTestFactory() { g_in_process_fuzz_test_factory = this; } + std::unique_ptr<InProcessFuzzTest> CreateInProcessFuzzer() override { + return std::make_unique<T>(); + } +}; + +#define REGISTER_IN_PROCESS_FUZZER(fuzzer_class) \ + InProcessFuzzTestFactory<fuzzer_class> fuzzer_instance; + +#endif // CHROME_TEST_FUZZING_IN_PROCESS_FUZZ_TEST_H_
diff --git a/chrome/updater/BUILD.gn b/chrome/updater/BUILD.gn index 55e59cd..0d1ee727 100644 --- a/chrome/updater/BUILD.gn +++ b/chrome/updater/BUILD.gn
@@ -62,6 +62,8 @@ "app/app_server.h", "app/app_uninstall.cc", "app/app_uninstall.h", + "app/app_uninstall_self.cc", + "app/app_uninstall_self.h", "app/app_update.cc", "app/app_update.h", "app/app_utils.cc",
diff --git a/chrome/updater/app/app_uninstall.cc b/chrome/updater/app/app_uninstall.cc index 1c2328b..2e85b41 100644 --- a/chrome/updater/app/app_uninstall.cc +++ b/chrome/updater/app/app_uninstall.cc
@@ -92,9 +92,6 @@ // Inter-process lock taken by AppInstall, AppUninstall, and AppUpdate. std::unique_ptr<ScopedLock> setup_lock_; - // Conditionally set, if prefs must be acquired for some uninstall scenarios. - // Creating the prefs instance may result in deadlocks. Therefore, the prefs - // lock can't be taken in all cases. scoped_refptr<GlobalPrefs> global_prefs_; }; @@ -102,10 +99,7 @@ setup_lock_ = ScopedLock::Create(kSetupMutex, updater_scope(), kWaitForSetupLock); - const base::CommandLine* command_line = - base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(kUninstallIfUnusedSwitch)) - global_prefs_ = CreateGlobalPrefs(updater_scope()); + global_prefs_ = CreateGlobalPrefs(updater_scope()); } void AppUninstall::Uninitialize() { @@ -137,30 +131,21 @@ return; } + if (!global_prefs_) { + VLOG(0) << "Failed to acquire global prefs; shutting down."; + Shutdown(kErrorFailedToLockPrefsMutex); + return; + } + const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(kUninstallSwitch)) { - CHECK(!global_prefs_); UninstallAll(); return; } - if (command_line->HasSwitch(kUninstallSelfSwitch)) { - CHECK(!global_prefs_); - base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, {base::MayBlock()}, - base::BindOnce(&UninstallCandidate, updater_scope()), - base::BindOnce(&AppUninstall::Shutdown, this)); - return; - } - if (command_line->HasSwitch(kUninstallIfUnusedSwitch)) { - if (!global_prefs_) { - VLOG(0) << "Failed to acquire global prefs; shutting down."; - Shutdown(kErrorFailedToLockPrefsMutex); - return; - } auto persisted_data = base::MakeRefCounted<PersistedData>( updater_scope(), global_prefs_->GetPrefService()); const bool should_uninstall = ShouldUninstall(
diff --git a/chrome/updater/app/app_uninstall_self.cc b/chrome/updater/app/app_uninstall_self.cc new file mode 100644 index 0000000..ada9d558 --- /dev/null +++ b/chrome/updater/app/app_uninstall_self.cc
@@ -0,0 +1,73 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/updater/app/app_uninstall_self.h" + +#include "base/functional/bind.h" +#include "base/logging.h" +#include "base/memory/scoped_refptr.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "build/build_config.h" +#include "chrome/updater/app/app.h" +#include "chrome/updater/constants.h" +#include "chrome/updater/lock.h" +#include "chrome/updater/util/util.h" + +#if BUILDFLAG(IS_WIN) +#include "chrome/updater/win/setup/uninstall.h" +#elif BUILDFLAG(IS_POSIX) +#include "chrome/updater/posix/setup.h" +#endif + +namespace updater { + +// AppUninstallSelf uninstalls this instance of the updater. +class AppUninstallSelf : public App { + public: + AppUninstallSelf() = default; + + private: + ~AppUninstallSelf() override = default; + void Initialize() override; + void Uninitialize() override; + void FirstTaskRun() override; + + void UninstallAll(); + + // Inter-process lock taken by AppInstall, AppUninstall, and AppUpdate. + std::unique_ptr<ScopedLock> setup_lock_; +}; + +void AppUninstallSelf::Initialize() { + setup_lock_ = + ScopedLock::Create(kSetupMutex, updater_scope(), kWaitForSetupLock); +} + +void AppUninstallSelf::Uninitialize() {} + +void AppUninstallSelf::FirstTaskRun() { + if (WrongUser(updater_scope())) { + VLOG(0) << "The current user is not compatible with the current scope."; + Shutdown(kErrorWrongUser); + return; + } + + if (!setup_lock_) { + VLOG(0) << "Failed to acquire setup mutex; shutting down."; + Shutdown(kErrorFailedToLockSetupMutex); + return; + } + + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, {base::MayBlock()}, + base::BindOnce(&UninstallCandidate, updater_scope()), + base::BindOnce(&AppUninstallSelf::Shutdown, this)); +} + +scoped_refptr<App> MakeAppUninstallSelf() { + return base::MakeRefCounted<AppUninstallSelf>(); +} + +} // namespace updater
diff --git a/chrome/updater/app/app_uninstall_self.h b/chrome/updater/app/app_uninstall_self.h new file mode 100644 index 0000000..408eea3 --- /dev/null +++ b/chrome/updater/app/app_uninstall_self.h
@@ -0,0 +1,18 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_UPDATER_APP_APP_UNINSTALL_SELF_H_ +#define CHROME_UPDATER_APP_APP_UNINSTALL_SELF_H_ + +#include "base/memory/scoped_refptr.h" + +namespace updater { + +class App; + +scoped_refptr<App> MakeAppUninstallSelf(); + +} // namespace updater + +#endif // CHROME_UPDATER_APP_APP_UNINSTALL_SELF_H_
diff --git a/chrome/updater/updater.cc b/chrome/updater/updater.cc index 6079f561..b6538a50 100644 --- a/chrome/updater/updater.cc +++ b/chrome/updater/updater.cc
@@ -24,6 +24,7 @@ #include "chrome/updater/app/app_install.h" #include "chrome/updater/app/app_recover.h" #include "chrome/updater/app/app_uninstall.h" +#include "chrome/updater/app/app_uninstall_self.h" #include "chrome/updater/app/app_update.h" #include "chrome/updater/app/app_wake.h" #include "chrome/updater/app/app_wakeall.h" @@ -173,11 +174,14 @@ } if (command_line->HasSwitch(kUninstallSwitch) || - command_line->HasSwitch(kUninstallSelfSwitch) || command_line->HasSwitch(kUninstallIfUnusedSwitch)) { return MakeAppUninstall()->Run(); } + if (command_line->HasSwitch(kUninstallSelfSwitch)) { + return MakeAppUninstallSelf()->Run(); + } + if (command_line->HasSwitch(kRecoverSwitch) || command_line->HasSwitch(kBrowserVersionSwitch)) { return MakeAppRecover()->Run();
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 8c125ef0..a71c63f0 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -15390.0.0 \ No newline at end of file +15392.0.0 \ No newline at end of file
diff --git a/chromeos/ash/components/phonehub/fake_phone_hub_manager.cc b/chromeos/ash/components/phonehub/fake_phone_hub_manager.cc index 9721199..2348770 100644 --- a/chromeos/ash/components/phonehub/fake_phone_hub_manager.cc +++ b/chromeos/ash/components/phonehub/fake_phone_hub_manager.cc
@@ -103,5 +103,15 @@ return &app_stream_manager_; } +eche_app::EcheConnectionStatusHandler* +FakePhoneHubManager::GetEcheConnectionStatusHandler() { + return eche_connection_status_handler_; +} + +void FakePhoneHubManager::SetEcheConnectionStatusHandler( + eche_app::EcheConnectionStatusHandler* eche_connection_status_handler) { + eche_connection_status_handler_ = eche_connection_status_handler; +} + } // namespace phonehub } // namespace ash
diff --git a/chromeos/ash/components/phonehub/fake_phone_hub_manager.h b/chromeos/ash/components/phonehub/fake_phone_hub_manager.h index 75e8517..82e2c82 100644 --- a/chromeos/ash/components/phonehub/fake_phone_hub_manager.h +++ b/chromeos/ash/components/phonehub/fake_phone_hub_manager.h
@@ -105,6 +105,11 @@ host_last_seen_timestamp_ = timestamp; } + void set_eche_connection_hander( + eche_app::EcheConnectionStatusHandler* handler) { + eche_connection_status_handler_ = handler; + } + private: // PhoneHubManager: BrowserTabsModelProvider* GetBrowserTabsModelProvider() override; @@ -129,6 +134,11 @@ base::OnceCallback<void(absl::optional<base::Time>)> callback) override; IconDecoder* GetIconDecoder() override; AppStreamManager* GetAppStreamManager() override; + eche_app::EcheConnectionStatusHandler* GetEcheConnectionStatusHandler() + override; + void SetEcheConnectionStatusHandler( + eche_app::EcheConnectionStatusHandler* eche_connection_status_handler) + override; FakeDoNotDisturbController fake_do_not_disturb_controller_; FakeFeatureStatusProvider fake_feature_status_provider_; @@ -149,6 +159,8 @@ FakePingManager fake_ping_manager_; FakeIconDecoder fake_icon_decoder_; AppStreamManager app_stream_manager_; + eche_app::EcheConnectionStatusHandler* eche_connection_status_handler_ = + nullptr; absl::optional<base::Time> host_last_seen_timestamp_ = absl::nullopt; };
diff --git a/chromeos/ash/components/phonehub/phone_hub_manager.h b/chromeos/ash/components/phonehub/phone_hub_manager.h index 1d41f23..a12487c 100644 --- a/chromeos/ash/components/phonehub/phone_hub_manager.h +++ b/chromeos/ash/components/phonehub/phone_hub_manager.h
@@ -12,6 +12,11 @@ #include "third_party/abseil-cpp/absl/types/optional.h" namespace ash { + +namespace eche_app { +class EcheConnectionStatusHandler; +} + namespace phonehub { class BrowserTabsModelProvider; @@ -64,6 +69,11 @@ virtual UserActionRecorder* GetUserActionRecorder() = 0; virtual IconDecoder* GetIconDecoder() = 0; virtual AppStreamManager* GetAppStreamManager() = 0; + virtual eche_app::EcheConnectionStatusHandler* + GetEcheConnectionStatusHandler() = 0; + virtual void SetEcheConnectionStatusHandler( + eche_app::EcheConnectionStatusHandler* + eche_connection_status_handler) = 0; // Retrieves the timestamp of the last successful discovery for active host, // or nullopt if it hasn't been seen in the current Chrome session.
diff --git a/chromeos/ash/components/phonehub/phone_hub_manager_impl.cc b/chromeos/ash/components/phonehub/phone_hub_manager_impl.cc index 93b57452..f0ffc2d 100644 --- a/chromeos/ash/components/phonehub/phone_hub_manager_impl.cc +++ b/chromeos/ash/components/phonehub/phone_hub_manager_impl.cc
@@ -279,6 +279,18 @@ connection_manager_->GetHostLastSeenTimestamp(std::move(callback)); } +eche_app::EcheConnectionStatusHandler* +PhoneHubManagerImpl::GetEcheConnectionStatusHandler() { + return eche_connection_status_handler_; +} + +void PhoneHubManagerImpl::SetEcheConnectionStatusHandler( + eche_app::EcheConnectionStatusHandler* eche_connection_status_handler) { + eche_connection_status_handler_ = eche_connection_status_handler; + recent_apps_interaction_handler_->SetConnectionStatusHandler( + eche_connection_status_handler_); +} + // NOTE: These should be destroyed in the opposite order of how these objects // are initialized in the constructor. void PhoneHubManagerImpl::Shutdown() {
diff --git a/chromeos/ash/components/phonehub/phone_hub_manager_impl.h b/chromeos/ash/components/phonehub/phone_hub_manager_impl.h index f2685486..01dbdac 100644 --- a/chromeos/ash/components/phonehub/phone_hub_manager_impl.h +++ b/chromeos/ash/components/phonehub/phone_hub_manager_impl.h
@@ -91,6 +91,12 @@ void GetHostLastSeenTimestamp( base::OnceCallback<void(absl::optional<base::Time>)> callback) override; + eche_app::EcheConnectionStatusHandler* GetEcheConnectionStatusHandler() + override; + void SetEcheConnectionStatusHandler( + eche_app::EcheConnectionStatusHandler* eche_connection_status_handler) + override; + private: // KeyedService: void Shutdown() override; @@ -130,6 +136,8 @@ std::unique_ptr<FeatureSetupResponseProcessor> feature_setup_response_processor_; std::unique_ptr<PingManager> ping_manager_; + eche_app::EcheConnectionStatusHandler* eche_connection_status_handler_ = + nullptr; }; } // namespace phonehub
diff --git a/components/access_code_cast/common/access_code_cast_metrics.cc b/components/access_code_cast/common/access_code_cast_metrics.cc index 4ac3ed6..3f57492 100644 --- a/components/access_code_cast/common/access_code_cast_metrics.cc +++ b/components/access_code_cast/common/access_code_cast_metrics.cc
@@ -5,6 +5,7 @@ #include "components/access_code_cast/common/access_code_cast_metrics.h" #include "base/metrics/histogram_functions.h" +#include "base/notreached.h" AccessCodeCastMetrics::AccessCodeCastMetrics() = default; AccessCodeCastMetrics::~AccessCodeCastMetrics() = default; @@ -28,6 +29,8 @@ "AccessCodeCast.Ui.DialogOpenLocation"; const char AccessCodeCastMetrics::kHistogramRememberedDevicesCount[] = "AccessCodeCast.Discovery.RememberedDevicesCount"; +const char AccessCodeCastMetrics::kHistogramRouteDiscoveryTypeAndSource[] = + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource"; const char AccessCodeCastMetrics::kHistogramRouteDuration[] = "AccessCodeCast.Session.RouteDuration"; const char AccessCodeCastMetrics::kHistogramUiTabSwitcherUsageType[] = @@ -54,11 +57,62 @@ // static void AccessCodeCastMetrics::RecordAccessCodeRouteStarted( - base::TimeDelta duration) { + base::TimeDelta duration, + bool is_saved, + AccessCodeCastCastMode mode) { int64_t duration_seconds = duration.InSeconds(); // Duration can take one of five values, ranging from zero (0 sec), up to // a year (31536000 sec). So, recording as a sparse histogram is best. base::UmaHistogramSparse(kHistogramDeviceDurationOnRoute, duration_seconds); + + AccessCodeCastDiscoveryTypeAndSource discovery_type_and_source = + AccessCodeCastDiscoveryTypeAndSource::kUnknown; + if (is_saved) { + switch (mode) { + case AccessCodeCastCastMode::kPresentation: + discovery_type_and_source = + AccessCodeCastDiscoveryTypeAndSource::kSavedDevicePresentation; + break; + case AccessCodeCastCastMode::kTabMirror: + discovery_type_and_source = + AccessCodeCastDiscoveryTypeAndSource::kSavedDeviceTabMirror; + break; + case AccessCodeCastCastMode::kDesktopMirror: + discovery_type_and_source = + AccessCodeCastDiscoveryTypeAndSource::kSavedDeviceDesktopMirror; + break; + case AccessCodeCastCastMode::kRemotePlayback: + discovery_type_and_source = + AccessCodeCastDiscoveryTypeAndSource::kSavedDeviceRemotePlayback; + break; + default: + NOTREACHED_NORETURN(); + } + } else { /* is_saved == false (A new device just added by access code) */ + switch (mode) { + case AccessCodeCastCastMode::kPresentation: + discovery_type_and_source = + AccessCodeCastDiscoveryTypeAndSource::kNewDevicePresentation; + break; + case AccessCodeCastCastMode::kTabMirror: + discovery_type_and_source = + AccessCodeCastDiscoveryTypeAndSource::kNewDeviceTabMirror; + break; + case AccessCodeCastCastMode::kDesktopMirror: + discovery_type_and_source = + AccessCodeCastDiscoveryTypeAndSource::kNewDeviceDesktopMirror; + break; + case AccessCodeCastCastMode::kRemotePlayback: + discovery_type_and_source = + AccessCodeCastDiscoveryTypeAndSource::kNewDeviceRemotePlayback; + break; + default: + NOTREACHED_NORETURN(); + } + } + + base::UmaHistogramEnumeration(kHistogramRouteDiscoveryTypeAndSource, + discovery_type_and_source); } // static
diff --git a/components/access_code_cast/common/access_code_cast_metrics.h b/components/access_code_cast/common/access_code_cast_metrics.h index 2c67001..1a353e6 100644 --- a/components/access_code_cast/common/access_code_cast_metrics.h +++ b/components/access_code_cast/common/access_code_cast_metrics.h
@@ -74,6 +74,24 @@ // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. +enum class AccessCodeCastDiscoveryTypeAndSource { + kUnknown = 0, + kSavedDevicePresentation = 1, + kSavedDeviceTabMirror = 2, + kSavedDeviceDesktopMirror = 3, + kSavedDeviceRemotePlayback = 4, + kNewDevicePresentation = 5, + kNewDeviceTabMirror = 6, + kNewDeviceDesktopMirror = 7, + kNewDeviceRemotePlayback = 8, + + // NOTE: Do not reorder existing entries, and add entries only immediately + // above this line. + kMaxValue = kNewDeviceRemotePlayback +}; + +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. enum class AccessCodeCastUiTabSwitcherUsage { kTabSwitcherUiShownAndNotUsed = 0, kTabSwitcherUiShownAndUsedToSwitchTabs = 1, @@ -98,6 +116,7 @@ static const char kHistogramDialogLoadTime[]; static const char kHistogramDialogOpenLocation[]; static const char kHistogramRememberedDevicesCount[]; + static const char kHistogramRouteDiscoveryTypeAndSource[]; static const char kHistogramRouteDuration[]; static const char kHistogramUiTabSwitcherUsageType[]; static const char kHistogramUiTabSwitchingCount[]; @@ -111,8 +130,10 @@ static void RecordAccessCodeNotFoundCount(int count); // Records the value of the device duration pref on successful creation of - // an access code route. - static void RecordAccessCodeRouteStarted(base::TimeDelta duration); + // an access code route. Also records the discovery type and cast source. + static void RecordAccessCodeRouteStarted(base::TimeDelta duration, + bool is_saved, + AccessCodeCastCastMode mode); // Records the result of adding an access code sink. static void RecordAddSinkResult(bool is_remembered,
diff --git a/components/access_code_cast/common/access_code_cast_metrics_unittest.cc b/components/access_code_cast/common/access_code_cast_metrics_unittest.cc index 54d54ba..b25347ab 100644 --- a/components/access_code_cast/common/access_code_cast_metrics_unittest.cc +++ b/components/access_code_cast/common/access_code_cast_metrics_unittest.cc
@@ -122,17 +122,20 @@ TEST(AccessCodeCastMetricsTest, RecordAccessCodeRouteStarted) { base::HistogramTester histogram_tester; - AccessCodeCastMetrics::RecordAccessCodeRouteStarted(base::Seconds(0)); + AccessCodeCastCastMode cast_mode = AccessCodeCastCastMode::kPresentation; + + AccessCodeCastMetrics::RecordAccessCodeRouteStarted(base::Seconds(0), false, + cast_mode); histogram_tester.ExpectBucketCount( "AccessCodeCast.Discovery.DeviceDurationOnRoute", 0, 1); // Ensure the functions properly converts duration to seconds - AccessCodeCastMetrics::RecordAccessCodeRouteStarted( - base::Milliseconds(10000)); + AccessCodeCastMetrics::RecordAccessCodeRouteStarted(base::Milliseconds(10000), + false, cast_mode); histogram_tester.ExpectBucketCount( "AccessCodeCast.Discovery.DeviceDurationOnRoute", 10, 1); - AccessCodeCastMetrics::RecordAccessCodeRouteStarted( - base::Milliseconds(20000)); + AccessCodeCastMetrics::RecordAccessCodeRouteStarted(base::Milliseconds(20000), + false, cast_mode); histogram_tester.ExpectBucketCount( "AccessCodeCast.Discovery.DeviceDurationOnRoute", 20, 1); @@ -140,6 +143,53 @@ "AccessCodeCast.Discovery.DeviceDurationOnRoute", 3); } +TEST(AccessCodeCastMetricsTest, RecordAccessCodeRouteStartedRouteInfo) { + base::HistogramTester histogram_tester; + + AccessCodeCastMetrics::RecordAccessCodeRouteStarted( + base::Seconds(0), true, AccessCodeCastCastMode::kPresentation); + histogram_tester.ExpectBucketCount( + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource", 1, 1); + + AccessCodeCastMetrics::RecordAccessCodeRouteStarted( + base::Seconds(0), true, AccessCodeCastCastMode::kTabMirror); + histogram_tester.ExpectBucketCount( + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource", 2, 1); + + AccessCodeCastMetrics::RecordAccessCodeRouteStarted( + base::Seconds(0), true, AccessCodeCastCastMode::kDesktopMirror); + histogram_tester.ExpectBucketCount( + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource", 3, 1); + + AccessCodeCastMetrics::RecordAccessCodeRouteStarted( + base::Seconds(0), true, AccessCodeCastCastMode::kRemotePlayback); + histogram_tester.ExpectBucketCount( + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource", 4, 1); + + AccessCodeCastMetrics::RecordAccessCodeRouteStarted( + base::Seconds(0), false, AccessCodeCastCastMode::kPresentation); + histogram_tester.ExpectBucketCount( + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource", 5, 1); + + AccessCodeCastMetrics::RecordAccessCodeRouteStarted( + base::Seconds(0), false, AccessCodeCastCastMode::kTabMirror); + histogram_tester.ExpectBucketCount( + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource", 6, 1); + + AccessCodeCastMetrics::RecordAccessCodeRouteStarted( + base::Seconds(0), false, AccessCodeCastCastMode::kDesktopMirror); + histogram_tester.ExpectBucketCount( + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource", 7, 1); + + AccessCodeCastMetrics::RecordAccessCodeRouteStarted( + base::Seconds(0), false, AccessCodeCastCastMode::kRemotePlayback); + histogram_tester.ExpectBucketCount( + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource", 8, 1); + + histogram_tester.ExpectTotalCount( + "AccessCodeCast.Session.RouteDiscoveryTypeAndSource", 8); +} + TEST(AccessCodeCastMetricsTest, RecordDialogLoadTime) { base::HistogramTester histogram_tester; @@ -255,4 +305,14 @@ << "'AccessCodeCastDialogOpenLocation' enum was changed in " "access_code_cast_metrics.h. Please update the entry in " "enums.xml to match."; + + // DiscoveryTypeAndSource + absl::optional<base::HistogramEnumEntryMap> discovery_types_and_sources = + base::ReadEnumFromEnumsXml("AccessCodeCastDiscoveryTypeAndSource"); + EXPECT_TRUE( + discovery_types_and_sources->size() == + static_cast<int>(AccessCodeCastDiscoveryTypeAndSource::kMaxValue) + 1) + << "'AccessCodeCastDicoveryTypeAndSource' enum was changed in " + "access_code_cast_metrics.h. Please update the entry in " + "enums.xml to match."; }
diff --git a/components/autofill/content/browser/form_forest_unittest.cc b/components/autofill/content/browser/form_forest_unittest.cc index 62a20c0..c6d178e7 100644 --- a/components/autofill/content/browser/form_forest_unittest.cc +++ b/components/autofill/content/browser/form_forest_unittest.cc
@@ -384,14 +384,18 @@ blink::mojom::PermissionsPolicyFeature::kSharedAutofill, {blink::OriginWithPossibleWildcards(origin, /*has_subdomain_wildcard=*/false)}, - false, false)}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false)}; } // Explicitly disallows shared-autofill on all origins. static blink::ParsedPermissionsPolicy DisallowSharedAutofill() { return {blink::ParsedPermissionsPolicyDeclaration( - blink::mojom::PermissionsPolicyFeature::kSharedAutofill, {}, false, - false)}; + blink::mojom::PermissionsPolicyFeature::kSharedAutofill, + /*allowed_origins=*/{}, /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false)}; } MockContentAutofillDriver* NavigateFrame(content::RenderFrameHost* rfh,
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc index 5efd6ef5b..5e2fa6d2 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.cc
@@ -23,12 +23,16 @@ AutofillSaveUpdateAddressProfileDelegateIOS( const AutofillProfile& profile, const AutofillProfile* original_profile, + absl::optional<std::u16string> syncing_user_email, const std::string& locale, + AutofillClient::SaveAddressProfilePromptOptions options, AutofillClient::AddressProfileSavePromptCallback callback) : locale_(locale), profile_(profile), original_profile_(base::OptionalFromPtr(original_profile)), - address_profile_save_prompt_callback_(std::move(callback)) {} + address_profile_save_prompt_callback_(std::move(callback)), + is_migration_to_account_(options.is_migration_to_account), + syncing_user_email_(syncing_user_email) {} AutofillSaveUpdateAddressProfileDelegateIOS:: ~AutofillSaveUpdateAddressProfileDelegateIOS() { @@ -74,6 +78,13 @@ std::u16string AutofillSaveUpdateAddressProfileDelegateIOS::GetDescription() const { + if (is_migration_to_account_) { + DCHECK(profile_.source() != autofill::AutofillProfile::Source::kAccount); + DCHECK(syncing_user_email_); + return l10n_util::GetStringFUTF16( + IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_SUBTITLE, + *syncing_user_email_); + } return GetProfileDescription( original_profile_ ? *original_profile_ : profile_, locale_, /*include_address_and_contacts=*/true); @@ -184,6 +195,10 @@ std::u16string AutofillSaveUpdateAddressProfileDelegateIOS::GetMessageText() const { + if (is_migration_to_account_) { + return l10n_util::GetStringUTF16( + IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_TITLE); + } return l10n_util::GetStringUTF16( original_profile_ ? IDS_IOS_AUTOFILL_UPDATE_ADDRESS_MESSAGE_TITLE : IDS_IOS_AUTOFILL_SAVE_ADDRESS_MESSAGE_TITLE);
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h index 3539a821..4ab3476 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios.h
@@ -23,7 +23,9 @@ AutofillSaveUpdateAddressProfileDelegateIOS( const AutofillProfile& profile, const AutofillProfile* original_profile, + absl::optional<std::u16string> syncing_user_email, const std::string& locale, + AutofillClient::SaveAddressProfilePromptOptions options, AutofillClient::AddressProfileSavePromptCallback callback); AutofillSaveUpdateAddressProfileDelegateIOS( const AutofillSaveUpdateAddressProfileDelegateIOS&) = delete; @@ -88,6 +90,8 @@ bool Cancel() override; bool EqualsDelegate(infobars::InfoBarDelegate* delegate) const override; + bool IsMigrationToAccount() const { return is_migration_to_account_; } + #if defined(UNIT_TEST) // Getter for |user_decision_|. Used for the testing purposes. AutofillClient::SaveAddressProfileOfferUserDecision user_decision() const { @@ -121,6 +125,12 @@ // True if the either of banner or modal is visible currently. bool is_infobar_visible_ = false; + // Denotes if an account migration prompt should be shown. + bool is_migration_to_account_; + + // Denotes the email address of the syncing account. + absl::optional<std::u16string> syncing_user_email_; + // Records the last user decision based on the interactions with the // banner/modal to be sent with |address_profile_save_prompt_callback_|. AutofillClient::SaveAddressProfileOfferUserDecision user_decision_ =
diff --git a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc index 2a422f7..126650b 100644 --- a/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc +++ b/components/autofill/core/browser/autofill_save_update_address_profile_delegate_ios_unittest.cc
@@ -15,30 +15,49 @@ namespace autofill { -TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, - HandleUserAction_Accepted) { - AutofillProfile profile = test::GetFullProfile(); - base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; - auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>( - profile, /*original_profile=*/nullptr, /*locale=*/"en-US", - callback.Get()); +class AutofillSaveUpdateAddressProfileDelegateIOSTest : public testing::Test { + protected: + AutofillSaveUpdateAddressProfileDelegateIOSTest() = default; + ~AutofillSaveUpdateAddressProfileDelegateIOSTest() override {} + void SetUp() override { profile_ = test::GetFullProfile(); } + + std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS> + CreateAutofillSaveUpdateAddressProfileDelegate( + AutofillProfile* original_profile = nullptr, + absl::optional<std::u16string> email = absl::nullopt, + bool is_migration_to_account = false) { + return std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>( + profile_, original_profile, email, + /*locale=*/"en-US", + AutofillClient::SaveAddressProfilePromptOptions{ + .is_migration_to_account = is_migration_to_account}, + callback_.Get()); + } + + AutofillProfile profile_; + base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> + callback_; +}; + +// Tests that the callback is run with kAccepted on Accepted. +TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest, + HandleUserAction_Accepted) { + std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS> delegate = + CreateAutofillSaveUpdateAddressProfileDelegate(); EXPECT_CALL( - callback, + callback_, Run(AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted, - profile)); + profile_)); delegate->Accept(); } // Tests that the delegate returns Save Address profile strings when the // original_profile is supplied as nullptr to the delegate. -TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, TestSaveAddressStrings) { - AutofillProfile profile = test::GetFullProfile(); - base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; - auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>( - profile, /*original_profile=*/nullptr, /*locale=*/"en-US", - callback.Get()); - +TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest, + TestSaveAddressStrings) { + std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS> delegate = + CreateAutofillSaveUpdateAddressProfileDelegate(); EXPECT_EQ(delegate->GetMessageActionText(), l10n_util::GetStringUTF16( IDS_IOS_AUTOFILL_SAVE_ADDRESS_MESSAGE_PRIMARY_ACTION)); @@ -49,16 +68,29 @@ std::u16string(u"John H. Doe, 666 Erebus St.")); } +// Tests the message UI strings when the profile is saved in the Google Account. +TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest, + TestSaveAddressInAccountStrings) { + std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS> delegate = + CreateAutofillSaveUpdateAddressProfileDelegate(nullptr, u"test@gmail.com", + true); + EXPECT_EQ(delegate->GetDescription(), + l10n_util::GetStringFUTF16( + IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_SUBTITLE, + u"test@gmail.com")); + EXPECT_EQ(delegate->GetMessageText(), + l10n_util::GetStringUTF16( + IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_TITLE)); +} + // Tests that the delegate returns Update Address profile strings when the // original_profile is supplied to the delegate. -TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, - TestUpdateAddressStrings) { - AutofillProfile profile = test::GetFullProfile(); +TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest, + TestUpdateAddressStrings) { AutofillProfile original_profile = test::GetFullProfile(); original_profile.SetInfo(NAME_FULL, u"John Doe", "en-US"); - base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; - auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>( - profile, &original_profile, /*locale=*/"en-US", callback.Get()); + std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS> delegate = + CreateAutofillSaveUpdateAddressProfileDelegate(&original_profile); EXPECT_EQ(delegate->GetMessageActionText(), l10n_util::GetStringUTF16( @@ -71,17 +103,14 @@ } // Tests that the callback is run with kDeclined on destruction. -TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, - TestCallbackOnDestruction) { - AutofillProfile profile = test::GetFullProfile(); - base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; - auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>( - profile, /*original_profile=*/nullptr, /*locale=*/"en-US", - callback.Get()); +TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest, + TestCallbackOnDestruction) { + std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS> delegate = + CreateAutofillSaveUpdateAddressProfileDelegate(); delegate->Cancel(); EXPECT_CALL( - callback, + callback_, Run(AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined, testing::_)); // The callback should run in the destructor. @@ -89,30 +118,26 @@ } // Tests that the callback is run with kAccepted on Accept. -TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, TestCallbackOnSave) { - AutofillProfile profile = test::GetFullProfile(); - base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; +TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest, TestCallbackOnSave) { + std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS> delegate = + CreateAutofillSaveUpdateAddressProfileDelegate(); EXPECT_CALL( - callback, + callback_, Run(AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted, testing::_)); - AutofillSaveUpdateAddressProfileDelegateIOS( - profile, /*original_profile=*/nullptr, /*locale=*/"en-US", callback.Get()) - .Accept(); + delegate->Accept(); } // Tests that the callback is run with kEditAccepted on EditAccepted. -TEST(AutofillSaveUpdateAddressProfileDelegateIOSTest, - TestCallbackOnEditAccepted) { - AutofillProfile profile = test::GetFullProfile(); - base::MockCallback<AutofillClient::AddressProfileSavePromptCallback> callback; +TEST_F(AutofillSaveUpdateAddressProfileDelegateIOSTest, + TestCallbackOnEditAccepted) { + std::unique_ptr<AutofillSaveUpdateAddressProfileDelegateIOS> delegate = + CreateAutofillSaveUpdateAddressProfileDelegate(); EXPECT_CALL( - callback, + callback_, Run(AutofillClient::SaveAddressProfileOfferUserDecision::kEditAccepted, testing::_)); - AutofillSaveUpdateAddressProfileDelegateIOS( - profile, /*original_profile=*/nullptr, /*locale=*/"en-US", callback.Get()) - .EditAccepted(); + delegate->EditAccepted(); } } // namespace autofill
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp index 8da5d1d..a84c0fb 100644 --- a/components/autofill_strings.grdp +++ b/components/autofill_strings.grdp
@@ -384,6 +384,9 @@ <message name="IDS_IOS_AUTOFILL_SAVE_ADDRESS_MESSAGE_TITLE" desc="In Title Case: Title shown in the message that offers the user to proceed with saving a new address." meaning="In Title Case for iOS"> Save Address? </message> + <message name="IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_TITLE" desc="In Title Case: Title shown in the message that offers the user to proceed with saving a new address in the google account" meaning="In Title Case for iOS"> + Save in Account? + </message> <message name="IDS_IOS_AUTOFILL_SAVE_ADDRESS_MESSAGE_PRIMARY_ACTION" desc="Label of the primary action button in the message that offers the user to proceed with saving a new address."> Save… </message> @@ -399,6 +402,9 @@ <message name="IDS_IOS_AUTOFILL_UPDATE_ADDRESS_PROMPT_TITLE" desc="In Title Case: Title shown at the top of modal dialog that offers the user to update an existing address." meaning="In Title Case for iOS"> Update Address </message> + <message name="IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_SUBTITLE" desc="Subtitle shown in the messages UI view when a new profile is asked to be saved in the Google Account"> + In your Google Account, <ph name="USER_EMAIL">$1<ex>janedoe@google.com</ex></ph> + </message> </if> <!-- Used on Desktop: --> <if expr="not is_android and not is_ios">
diff --git a/components/autofill_strings_grdp/IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_SUBTITLE.png.sha1 b/components/autofill_strings_grdp/IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_SUBTITLE.png.sha1 new file mode 100644 index 0000000..3dcd351 --- /dev/null +++ b/components/autofill_strings_grdp/IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_SUBTITLE.png.sha1
@@ -0,0 +1 @@ +b4214a2043e947761426d150be7989ddd7910283 \ No newline at end of file
diff --git a/components/autofill_strings_grdp/IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_TITLE.png.sha1 b/components/autofill_strings_grdp/IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_TITLE.png.sha1 new file mode 100644 index 0000000..e501015 --- /dev/null +++ b/components/autofill_strings_grdp/IDS_IOS_AUTOFILL_SAVE_ADDRESS_IN_ACCOUNT_MESSAGE_TITLE.png.sha1
@@ -0,0 +1 @@ +0d6ac3728d07d0edd746e3ca4d2c12f55f7b9a38 \ No newline at end of file
diff --git a/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareHelper.java b/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareHelper.java index c64aeb2..ca5c3bcd 100644 --- a/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareHelper.java +++ b/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareHelper.java
@@ -338,6 +338,13 @@ } } else { intent.setType("text/plain"); + // For text sharing, only set the preview title when preview image is provided. This + // is meant to avoid confusion about the content being shared. + if (params.getPreviewImageUri() != null) { + intent.putExtra(Intent.EXTRA_TITLE, params.getTitle()); + intent.setClipData(ClipData.newRawUri("", params.getPreviewImageUri())); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } } }
diff --git a/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareParams.java b/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareParams.java index 709381d..5504fd7b 100644 --- a/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareParams.java +++ b/components/browser_ui/share/android/java/src/org/chromium/components/browser_ui/share/ShareParams.java
@@ -54,6 +54,9 @@ */ private final Uri mSingleImageUri; + /** The Uri of the preview image (e.g. a favicon) of the text being shared. */ + private Uri mPreviewImageUri; + /** The boolean result of link to text generation. */ private final Boolean mLinkToTextSuccessful; @@ -72,8 +75,9 @@ private ShareParams(WindowAndroid window, String title, String text, String textFormat, String url, @Nullable String fileContentType, @Nullable ArrayList<Uri> fileUris, @Nullable String imageAltText, @Nullable Uri offlineUri, @Nullable Uri singleImageUri, - @Nullable TargetChosenCallback callback, @Nullable Boolean linkToTextSuccessful, - @Nullable String previewText, String previewTextFormat) { + @Nullable Uri previewImageUri, @Nullable TargetChosenCallback callback, + @Nullable Boolean linkToTextSuccessful, @Nullable String previewText, + String previewTextFormat) { mWindow = window; mTitle = title; mText = text; @@ -84,6 +88,7 @@ mImageAltText = imageAltText; mOfflineUri = offlineUri; mSingleImageUri = singleImageUri; + mPreviewImageUri = previewImageUri; mCallback = callback; mLinkToTextSuccessful = linkToTextSuccessful; mPreviewText = previewText; @@ -189,6 +194,19 @@ return mSingleImageUri; } + /** @return The Uri of the preview image (e.g. a favicon) of the text being shared. */ + @Nullable + public Uri getPreviewImageUri() { + return mPreviewImageUri; + } + + /** + * @param uri The Uri of the preview image (e.g. a favicon) of the text being shared. + */ + public void setPreviewImageUri(Uri uri) { + mPreviewImageUri = uri; + } + /** * @return The callback to be called when user makes a choice. */ @@ -249,6 +267,7 @@ private String mImageAltText; private Uri mOfflineUri; private Uri mSingleImageUri; + private Uri mPreviewImageUri; private TargetChosenCallback mCallback; private Boolean mLinkToTextSuccessful; private String mPreviewText; @@ -329,6 +348,14 @@ } /** + * Sets the Uri of the preview image of the text being shared. + */ + public Builder setPreviewImageUri(@Nullable Uri previewImageUri) { + mPreviewImageUri = previewImageUri; + return this; + } + + /** * Sets the callback to be called when user makes a choice. */ public Builder setCallback(@Nullable TargetChosenCallback callback) { @@ -359,8 +386,8 @@ mUrl = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(mUrl); } return new ShareParams(mWindow, mTitle, mText, mTextFormat, mUrl, mFileContentType, - mFileUris, mImageAltText, mOfflineUri, mSingleImageUri, mCallback, - mLinkToTextSuccessful, mPreviewText, mPreviewTextFormat); + mFileUris, mImageAltText, mOfflineUri, mSingleImageUri, mPreviewImageUri, + mCallback, mLinkToTextSuccessful, mPreviewText, mPreviewTextFormat); } }
diff --git a/components/browsing_topics/browsing_topics_page_load_data_tracker_unittest.cc b/components/browsing_topics/browsing_topics_page_load_data_tracker_unittest.cc index 89b9943..fab6f74 100644 --- a/components/browsing_topics/browsing_topics_page_load_data_tracker_unittest.cc +++ b/components/browsing_topics/browsing_topics_page_load_data_tracker_unittest.cc
@@ -95,6 +95,7 @@ policy.emplace_back( blink::mojom::PermissionsPolicyFeature::kBrowsingTopics, /*allowed_origins=*/std::vector<blink::OriginWithPossibleWildcards>(), + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false); } @@ -104,6 +105,7 @@ blink::mojom::PermissionsPolicyFeature:: kBrowsingTopicsBackwardCompatible, /*allowed_origins=*/std::vector<blink::OriginWithPossibleWildcards>(), + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false); }
diff --git a/components/exo/wayland/OWNERS b/components/exo/wayland/OWNERS new file mode 100644 index 0000000..460d074f --- /dev/null +++ b/components/exo/wayland/OWNERS
@@ -0,0 +1 @@ +per-file zcr_ui_controls*=max@igalia.com
diff --git a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java index 5efa74a..1bee101 100644 --- a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java +++ b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/EventConstants.java
@@ -265,6 +265,10 @@ public static final String ADAPTIVE_TOOLBAR_CUSTOMIZATION_TRANSLATE_OPENED = "adaptive_toolbar_customization_translate_opened"; + /** AdaptiveButtonInTopToolbarCustomization add to bookmarks events. */ + public static final String ADAPTIVE_TOOLBAR_CUSTOMIZATION_ADD_TO_BOOKMARKS_OPENED = + "adaptive_toolbar_customization_add_to_bookmarks_opened"; + /** Open new incognito tab from app menu. */ public static final String APP_MENU_NEW_INCOGNITO_TAB_CLICKED = "app_menu_new_incognito_tab_clicked";
diff --git a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java index 623a67c..10a1317 100644 --- a/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java +++ b/components/feature_engagement/public/android/java/src/org/chromium/components/feature_engagement/FeatureConstants.java
@@ -17,6 +17,7 @@ FeatureConstants.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_SHARE_FEATURE, FeatureConstants.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_VOICE_SEARCH_FEATURE, FeatureConstants.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_TRANSLATE_FEATURE, + FeatureConstants.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_ADD_TO_BOOKMARKS_FEATURE, FeatureConstants.ADD_TO_HOMESCREEN_MESSAGE_FEATURE, FeatureConstants.AUTO_DARK_OPT_OUT_FEATURE, FeatureConstants.AUTO_DARK_USER_EDUCATION_MESSAGE_FEATURE, @@ -93,6 +94,8 @@ "IPH_AdaptiveButtonInTopToolbarCustomization_VoiceSearch"; String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_TRANSLATE_FEATURE = "IPH_AdaptiveButtonInTopToolbarCustomization_Translate"; + String ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_ADD_TO_BOOKMARKS_FEATURE = + "IPH_AdaptiveButtonInTopToolbarCustomization_AddToBookmarks"; String ADD_TO_HOMESCREEN_MESSAGE_FEATURE = "IPH_AddToHomescreenMessage"; String AUTO_DARK_OPT_OUT_FEATURE = "IPH_AutoDarkOptOut"; String AUTO_DARK_USER_EDUCATION_MESSAGE_FEATURE = "IPH_AutoDarkUserEducationMessage";
diff --git a/components/feature_engagement/public/feature_constants.cc b/components/feature_engagement/public/feature_constants.cc index 5f8b47f..b7b8227 100644 --- a/components/feature_engagement/public/feature_constants.cc +++ b/components/feature_engagement/public/feature_constants.cc
@@ -138,6 +138,9 @@ BASE_FEATURE(kIPHAdaptiveButtonInTopToolbarCustomizationTranslateFeature, "IPH_AdaptiveButtonInTopToolbarCustomization_Translate", base::FEATURE_DISABLED_BY_DEFAULT); +BASE_FEATURE(kIPHAdaptiveButtonInTopToolbarCustomizationAddToBookmarksFeature, + "IPH_AdaptiveButtonInTopToolbarCustomization_AddToBookmarks", + base::FEATURE_DISABLED_BY_DEFAULT); BASE_FEATURE(kIPHAddToHomescreenMessageFeature, "IPH_AddToHomescreenMessage", base::FEATURE_ENABLED_BY_DEFAULT);
diff --git a/components/feature_engagement/public/feature_constants.h b/components/feature_engagement/public/feature_constants.h index 67a3e46..66d82bb 100644 --- a/components/feature_engagement/public/feature_constants.h +++ b/components/feature_engagement/public/feature_constants.h
@@ -70,6 +70,8 @@ kIPHAdaptiveButtonInTopToolbarCustomizationVoiceSearchFeature); BASE_DECLARE_FEATURE( kIPHAdaptiveButtonInTopToolbarCustomizationTranslateFeature); +BASE_DECLARE_FEATURE( + kIPHAdaptiveButtonInTopToolbarCustomizationAddToBookmarksFeature); BASE_DECLARE_FEATURE(kIPHAddToHomescreenMessageFeature); BASE_DECLARE_FEATURE(kIPHAutoDarkOptOutFeature); BASE_DECLARE_FEATURE(kIPHAutoDarkUserEducationMessageFeature);
diff --git a/components/feature_engagement/public/feature_list.cc b/components/feature_engagement/public/feature_list.cc index 49ca66d5..35e8306 100644 --- a/components/feature_engagement/public/feature_list.cc +++ b/components/feature_engagement/public/feature_list.cc
@@ -19,6 +19,7 @@ &kIPHAdaptiveButtonInTopToolbarCustomizationNewTabFeature, &kIPHAdaptiveButtonInTopToolbarCustomizationShareFeature, &kIPHAdaptiveButtonInTopToolbarCustomizationVoiceSearchFeature, + &kIPHAdaptiveButtonInTopToolbarCustomizationAddToBookmarksFeature, &kIPHAdaptiveButtonInTopToolbarCustomizationTranslateFeature, &kIPHAddToHomescreenMessageFeature, &kIPHAutoDarkOptOutFeature,
diff --git a/components/feature_engagement/public/feature_list.h b/components/feature_engagement/public/feature_list.h index 367e1a06..259379b 100644 --- a/components/feature_engagement/public/feature_list.h +++ b/components/feature_engagement/public/feature_list.h
@@ -55,6 +55,9 @@ DEFINE_VARIATION_PARAM( kIPHAdaptiveButtonInTopToolbarCustomizationTranslateFeature, "IPH_AdaptiveButtonInTopToolbarCustomization_Translate"); +DEFINE_VARIATION_PARAM( + kIPHAdaptiveButtonInTopToolbarCustomizationAddToBookmarksFeature, + "IPH_AdaptiveButtonInTopToolbarCustomization_AddToBookmarks"); DEFINE_VARIATION_PARAM(kIPHAddToHomescreenMessageFeature, "IPH_AddToHomescreenMessage"); DEFINE_VARIATION_PARAM(kIPHAutoDarkOptOutFeature, "IPH_AutoDarkOptOut"); @@ -327,6 +330,8 @@ kIPHAdaptiveButtonInTopToolbarCustomizationVoiceSearchFeature), VARIATION_ENTRY( kIPHAdaptiveButtonInTopToolbarCustomizationTranslateFeature), + VARIATION_ENTRY( + kIPHAdaptiveButtonInTopToolbarCustomizationAddToBookmarksFeature), VARIATION_ENTRY(kIPHAddToHomescreenMessageFeature), VARIATION_ENTRY(kIPHAutoDarkOptOutFeature), VARIATION_ENTRY(kIPHAutoDarkUserEducationMessageFeature),
diff --git a/components/image_service/image_service.cc b/components/image_service/image_service.cc index 59cbdab..1d837c06 100644 --- a/components/image_service/image_service.cc +++ b/components/image_service/image_service.cc
@@ -149,10 +149,10 @@ optimization_guide::NewOptimizationGuideDecider* opt_guide, syncer::SyncService* sync_service) : autocomplete_provider_client_(std::move(autocomplete_provider_client)), - personalized_data_collection_consent_helper_( + history_consent_throttle_( unified_consent::UrlKeyedDataCollectionConsentHelper:: NewPersonalizedDataCollectionConsentHelper(sync_service)), - bookmarks_data_collection_consent_helper_( + bookmarks_consent_throttle_( unified_consent::UrlKeyedDataCollectionConsentHelper:: NewPersonalizedBookmarksDataCollectionConsentHelper( sync_service)) { @@ -171,23 +171,6 @@ return weak_factory_.GetWeakPtr(); } -bool ImageService::HasPermissionToFetchImage(mojom::ClientId client_id) const { - switch (client_id) { - case mojom::ClientId::Journeys: - case mojom::ClientId::JourneysSidePanel: - case mojom::ClientId::NtpQuests: { - return personalized_data_collection_consent_helper_ && - personalized_data_collection_consent_helper_->IsEnabled(); - } - case mojom::ClientId::NtpRealbox: - // TODO(b/244507194): Figure out consent story for NTP realbox case. - return false; - case mojom::ClientId::Bookmarks: - return bookmarks_data_collection_consent_helper_ && - bookmarks_data_collection_consent_helper_->IsEnabled(); - } -} - void ImageService::FetchImageFor(mojom::ClientId client_id, const GURL& page_url, const mojom::Options& options, @@ -198,7 +181,36 @@ return std::move(callback).Run(GURL()); } - if (!HasPermissionToFetchImage(client_id)) { + GetConsentToFetchImage( + client_id, + base::BindOnce(&ImageService::OnConsentResult, weak_factory_.GetWeakPtr(), + client_id, page_url, options, std::move(callback))); +} + +void ImageService::GetConsentToFetchImage( + mojom::ClientId client_id, + base::OnceCallback<void(bool)> callback) { + switch (client_id) { + case mojom::ClientId::Journeys: + case mojom::ClientId::JourneysSidePanel: + case mojom::ClientId::NtpQuests: { + return history_consent_throttle_.EnqueueRequest(std::move(callback)); + } + case mojom::ClientId::NtpRealbox: + // TODO(b/244507194): Figure out consent story for NTP realbox case. + return std::move(callback).Run(false); + case mojom::ClientId::Bookmarks: { + return bookmarks_consent_throttle_.EnqueueRequest(std::move(callback)); + } + } +} + +void ImageService::OnConsentResult(mojom::ClientId client_id, + const GURL& page_url, + const mojom::Options& options, + ResultCallback callback, + bool consent_is_enabled) { + if (!consent_is_enabled) { return std::move(callback).Run(GURL()); }
diff --git a/components/image_service/image_service.h b/components/image_service/image_service.h index 588d4bb4..8b096cd 100644 --- a/components/image_service/image_service.h +++ b/components/image_service/image_service.h
@@ -15,7 +15,7 @@ #include "components/omnibox/browser/autocomplete_provider_client.h" #include "components/optimization_guide/core/optimization_guide_decision.h" #include "components/sync/driver/sync_service.h" -#include "components/unified_consent/url_keyed_data_collection_consent_helper.h" +#include "components/unified_consent/consent_throttle.h" namespace optimization_guide { class NewOptimizationGuideDecider; @@ -42,9 +42,6 @@ // object whose lifetime might exceed the service. base::WeakPtr<ImageService> GetWeakPtr(); - // Returns true if `client_id` has permission to fetch images. - bool HasPermissionToFetchImage(mojom::ClientId client_id) const; - // Fetches an image appropriate for `page_url`, returning the result // asynchronously to `callback`. The callback is always invoked. If there are // no images available, it is invoked with an empty GURL result. @@ -53,9 +50,22 @@ const mojom::Options& options, ResultCallback callback); + // Asynchronously returns whether `client_id` has consent to fetch an image. + // Public for testing purposes only. + void GetConsentToFetchImage(mojom::ClientId client_id, + base::OnceCallback<void(bool)> callback); + private: class SuggestEntityImageURLFetcher; + // Callback to `GetConsentToFetchImage`, proceeds to call the appropriate + // backend. + void OnConsentResult(mojom::ClientId client_id, + const GURL& page_url, + const mojom::Options& options, + ResultCallback callback, + bool consent_is_enabled); + // Fetches an image from Suggest appropriate for `search_query` and // `entity_id`, returning the result asynchronously to `callback`. void FetchSuggestImage(const std::u16string& search_query, @@ -90,13 +100,11 @@ // Will be left as nullptr if the OptimizationGuide feature is disabled. raw_ptr<optimization_guide::NewOptimizationGuideDecider> opt_guide_ = nullptr; - // The History consent filter, used for most clients. - std::unique_ptr<unified_consent::UrlKeyedDataCollectionConsentHelper> - personalized_data_collection_consent_helper_; + // The History consent throttle, used for most clients. + unified_consent::ConsentThrottle history_consent_throttle_; - // The Bookmarks consent filter. - std::unique_ptr<unified_consent::UrlKeyedDataCollectionConsentHelper> - bookmarks_data_collection_consent_helper_; + // The Bookmarks consent throttle. + unified_consent::ConsentThrottle bookmarks_consent_throttle_; base::WeakPtrFactory<ImageService> weak_factory_{this}; };
diff --git a/components/image_service/image_service_unittest.cc b/components/image_service/image_service_unittest.cc index 2ed4abb..2afc22a 100644 --- a/components/image_service/image_service_unittest.cc +++ b/components/image_service/image_service_unittest.cc
@@ -3,10 +3,14 @@ // found in the LICENSE file. #include "components/image_service/image_service.h" + #include <memory> +#include "base/run_loop.h" +#include "base/test/bind.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_feature_list.h" +#include "base/test/task_environment.h" #include "build/build_config.h" #include "components/image_service/features.h" #include "components/image_service/metrics_util.h" @@ -33,6 +37,8 @@ const base::flat_set<proto::OptimizationType>& optimization_types, proto::RequestContext request_context, OnDemandOptimizationGuideDecisionRepeatingCallback callback) override { + requests_received_++; + // For this test, we just want to store the parameters which were used in // the call, and the test will manually send a response to `callback`. on_demand_call_urls_ = urls; @@ -41,6 +47,8 @@ on_demand_call_callback_ = std::move(callback); } + size_t requests_received_ = 0; + std::vector<GURL> on_demand_call_urls_; base::flat_set<proto::OptimizationType> on_demand_call_optimization_types_; proto::RequestContext on_demand_call_request_context_; @@ -69,11 +77,25 @@ nullptr, test_opt_guide_.get(), test_sync_service_.get()); } + bool GetConsentToFetchImageAwaitResult(mojom::ClientId client_id) { + bool out_consent = false; + base::RunLoop loop; + image_service_->GetConsentToFetchImage( + client_id, base::BindLambdaForTesting([&](bool result) { + out_consent = result; + loop.Quit(); + })); + loop.Run(); + return out_consent; + } + ImageServiceTest(const ImageServiceTest&) = delete; ImageServiceTest& operator=(const ImageServiceTest&) = delete; protected: base::test::ScopedFeatureList scoped_feature_list_; + base::test::SingleThreadTaskEnvironment task_environment{ + base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME}; std::unique_ptr<optimization_guide::ImageServiceTestOptGuide> test_opt_guide_; std::unique_ptr<syncer::TestSyncService> test_sync_service_; @@ -88,28 +110,29 @@ *out_image_url = image_url; } +void AppendResponse(std::vector<GURL>* responses, const GURL& image_url) { + DCHECK(responses); + responses->push_back(image_url); +} + TEST_F(ImageServiceTest, RegisteredSalientImageType) { ASSERT_EQ(test_opt_guide_->registered_optimization_types().size(), 1U); EXPECT_EQ(test_opt_guide_->registered_optimization_types()[0], optimization_guide::proto::SALIENT_IMAGE); } -TEST_F(ImageServiceTest, HasPermissionToFetchImage) { +TEST_F(ImageServiceTest, GetConsentToFetchImage) { test_sync_service_->GetUserSettings()->SetSelectedTypes( /*sync_everything=*/false, /*types=*/syncer::UserSelectableTypeSet()); test_sync_service_->FireStateChanged(); + EXPECT_FALSE(GetConsentToFetchImageAwaitResult(mojom::ClientId::Journeys)); EXPECT_FALSE( - image_service_->HasPermissionToFetchImage(mojom::ClientId::Journeys)); - EXPECT_FALSE(image_service_->HasPermissionToFetchImage( - mojom::ClientId::JourneysSidePanel)); - EXPECT_FALSE( - image_service_->HasPermissionToFetchImage(mojom::ClientId::NtpRealbox)); - EXPECT_FALSE( - image_service_->HasPermissionToFetchImage(mojom::ClientId::NtpQuests)); - EXPECT_FALSE( - image_service_->HasPermissionToFetchImage(mojom::ClientId::Bookmarks)); + GetConsentToFetchImageAwaitResult(mojom::ClientId::JourneysSidePanel)); + EXPECT_FALSE(GetConsentToFetchImageAwaitResult(mojom::ClientId::NtpRealbox)); + EXPECT_FALSE(GetConsentToFetchImageAwaitResult(mojom::ClientId::NtpQuests)); + EXPECT_FALSE(GetConsentToFetchImageAwaitResult(mojom::ClientId::Bookmarks)); test_sync_service_->GetUserSettings()->SetSelectedTypes( /*sync_everything=*/false, @@ -117,16 +140,62 @@ syncer::UserSelectableType::kHistory)); test_sync_service_->FireStateChanged(); + EXPECT_TRUE(GetConsentToFetchImageAwaitResult(mojom::ClientId::Journeys)); EXPECT_TRUE( - image_service_->HasPermissionToFetchImage(mojom::ClientId::Journeys)); - EXPECT_TRUE(image_service_->HasPermissionToFetchImage( - mojom::ClientId::JourneysSidePanel)); - EXPECT_FALSE( - image_service_->HasPermissionToFetchImage(mojom::ClientId::NtpRealbox)); - EXPECT_TRUE( - image_service_->HasPermissionToFetchImage(mojom::ClientId::NtpQuests)); - EXPECT_FALSE( - image_service_->HasPermissionToFetchImage(mojom::ClientId::Bookmarks)); + GetConsentToFetchImageAwaitResult(mojom::ClientId::JourneysSidePanel)); + EXPECT_FALSE(GetConsentToFetchImageAwaitResult(mojom::ClientId::NtpRealbox)); + EXPECT_TRUE(GetConsentToFetchImageAwaitResult(mojom::ClientId::NtpQuests)); + EXPECT_FALSE(GetConsentToFetchImageAwaitResult(mojom::ClientId::Bookmarks)); +} + +TEST_F(ImageServiceTest, SyncInitialization) { + // Put Sync into the initializing state. + test_sync_service_->SetTransportState( + syncer::SyncService::TransportState::INITIALIZING); + test_sync_service_->GetUserSettings()->SetSelectedTypes( + /*sync_everything=*/false, + /*types=*/syncer::UserSelectableTypeSet( + syncer::UserSelectableType::kHistory)); + test_sync_service_->FireStateChanged(); + + mojom::Options options; + options.suggest_images = false; + options.optimization_guide_images = true; + + std::vector<GURL> responses; + image_service_->FetchImageFor(mojom::ClientId::Journeys, + GURL("https://page-url.com"), options, + base::BindOnce(&AppendResponse, &responses)); + EXPECT_EQ(test_opt_guide_->requests_received_, 0U) + << "Expect no immediate requests, because the consent should be " + "throttling it."; + EXPECT_TRUE(responses.empty()); + + task_environment.FastForwardBy(base::Seconds(10)); + EXPECT_EQ(test_opt_guide_->requests_received_, 0U) + << "After 10 seconds, the throttle should have killed the request, never " + "passing it to the backend."; + ASSERT_EQ(responses.size(), 1U); + EXPECT_EQ(responses[0], GURL()); + + // Now send another request. + image_service_->FetchImageFor(mojom::ClientId::Journeys, + GURL("https://page-url.com"), options, + base::BindOnce(&AppendResponse, &responses)); + task_environment.FastForwardBy(base::Seconds(3)); + EXPECT_EQ(test_opt_guide_->requests_received_, 0U) << "Still throttled."; + + // Now set the test sync service to active. + test_sync_service_->SetTransportState( + syncer::SyncService::TransportState::ACTIVE); + test_sync_service_->FireStateChanged(); + EXPECT_EQ(test_opt_guide_->requests_received_, 1U) + << "The test backend should immediately get the request after Sync " + "activates, and the consent throttle unthrottles."; + + // This test only covers sync unthrottling, so we don't care about fulfilling + // the actual request. That's covered by + // OptimizationGuideSalientImagesEndToEnd. } TEST_F(ImageServiceTest, OptimizationGuideSalientImagesEndToEnd) {
diff --git a/components/omnibox/browser/autocomplete_controller.cc b/components/omnibox/browser/autocomplete_controller.cc index 5e6c6abc..c298c4310 100644 --- a/components/omnibox/browser/autocomplete_controller.cc +++ b/components/omnibox/browser/autocomplete_controller.cc
@@ -474,6 +474,11 @@ expire_timer_.Stop(); stop_timer_.Stop(); + // Cancel any pending requests to the scoring model and invalidate the WeakPtr + // to prevent its callbacks from being called. + scoring_model_task_tracker_.TryCancelAll(); + scoring_model_weak_ptr_ = nullptr; + // Start the new query. sync_pass_done_ = false; // Use `start_time` rather than `metrics.start_time_` for @@ -1367,6 +1372,11 @@ provider->Stop(clear_result, due_to_user_inactivity); } + // Cancel any pending requests to the scoring model and invalidate the WeakPtr + // to prevent its callbacks from being called. + scoring_model_task_tracker_.TryCancelAll(); + scoring_model_weak_ptr_ = nullptr; + expire_timer_.Stop(); stop_timer_.Stop(); done_ = true; @@ -1522,11 +1532,14 @@ return false; } + // Needed because the model is not owned and `this` may not longer be alive. + scoring_model_weak_ptr_ = weak_ptr_factory_.GetWeakPtr(); + auto barrier_callback = base::BarrierCallback<AutocompleteMatch>( result_.size(), base::BindOnce( &AutocompleteController::OnUrlScoringModelDoneForAllMatches, - weak_ptr_factory_.GetWeakPtr(), input_, last_default_match, + scoring_model_weak_ptr_, input_, last_default_match, last_default_associated_keyword, force_notify_default_match_changed)); for (const auto& match : result_.matches_) { @@ -1540,10 +1553,9 @@ } scoring_model_service->ScoreAutocompleteUrlMatch( - match.scoring_signals, + &scoring_model_task_tracker_, match.scoring_signals, base::BindOnce(&AutocompleteController::OnUrlScoringModelDone, - weak_ptr_factory_.GetWeakPtr(), barrier_callback, - match)); + scoring_model_weak_ptr_, barrier_callback, match)); } return true;
diff --git a/components/omnibox/browser/autocomplete_controller.h b/components/omnibox/browser/autocomplete_controller.h index 4ec2c4a..9a80064 100644 --- a/components/omnibox/browser/autocomplete_controller.h +++ b/components/omnibox/browser/autocomplete_controller.h
@@ -15,6 +15,7 @@ #include "base/memory/ref_counted.h" #include "base/observer_list.h" #include "base/observer_list_types.h" +#include "base/task/cancelable_task_tracker.h" #include "base/time/time.h" #include "base/timer/timer.h" #include "base/trace_event/memory_dump_provider.h" @@ -506,6 +507,13 @@ raw_ptr<TemplateURLService> template_url_service_; + // Combined, used to cancel model execution requests sent to + // `AutocompleteScoringModelService` and to prevent its callbacks from being + // called `base::CancelableTaskTracker` alone is insufficient because it + // cannot cancel tasks that have already started. + base::CancelableTaskTracker scoring_model_task_tracker_; + base::WeakPtr<AutocompleteController> scoring_model_weak_ptr_; + base::WeakPtrFactory<AutocompleteController> weak_ptr_factory_{this}; };
diff --git a/components/omnibox/browser/autocomplete_scoring_model_service.cc b/components/omnibox/browser/autocomplete_scoring_model_service.cc index 61aa167..5451337 100644 --- a/components/omnibox/browser/autocomplete_scoring_model_service.cc +++ b/components/omnibox/browser/autocomplete_scoring_model_service.cc
@@ -35,6 +35,7 @@ AutocompleteScoringModelService::~AutocompleteScoringModelService() = default; void AutocompleteScoringModelService::ScoreAutocompleteUrlMatch( + base::CancelableTaskTracker* tracker, const metrics::OmniboxEventProto::Suggestion::ScoringSignals& scoring_signals, ResultCallback result_callback) { @@ -51,6 +52,7 @@ } url_scoring_model_handler_->ExecuteModelWithInput( + tracker, base::BindOnce(&AutocompleteScoringModelService::ProcessModelOutput, base::Unretained(this), std::move(result_callback)), *input_signals);
diff --git a/components/omnibox/browser/autocomplete_scoring_model_service.h b/components/omnibox/browser/autocomplete_scoring_model_service.h index c71dd1b..8ea722a 100644 --- a/components/omnibox/browser/autocomplete_scoring_model_service.h +++ b/components/omnibox/browser/autocomplete_scoring_model_service.h
@@ -9,6 +9,7 @@ #include "base/functional/callback.h" #include "base/memory/scoped_refptr.h" +#include "base/task/cancelable_task_tracker.h" #include "base/task/sequenced_task_runner.h" #include "components/keyed_service/core/keyed_service.h" #include "components/omnibox/browser/autocomplete_scoring_model_executor.h" @@ -36,6 +37,7 @@ // Invokes the model to score the given `scoring_signals` and calls // `result_callback` with an optional relevance score generated by the model. void ScoreAutocompleteUrlMatch( + base::CancelableTaskTracker* tracker, const metrics::OmniboxEventProto::Suggestion::ScoringSignals& scoring_signals, ResultCallback result_callback);
diff --git a/components/password_manager/content/browser/password_change_success_tracker_factory.cc b/components/password_manager/content/browser/password_change_success_tracker_factory.cc index e7f909b6..3960f15 100644 --- a/components/password_manager/content/browser/password_change_success_tracker_factory.cc +++ b/components/password_manager/content/browser/password_change_success_tracker_factory.cc
@@ -46,4 +46,10 @@ return tracker; } +content::BrowserContext* +PasswordChangeSuccessTrackerFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return context; +} + } // namespace password_manager
diff --git a/components/password_manager/content/browser/password_change_success_tracker_factory.h b/components/password_manager/content/browser/password_change_success_tracker_factory.h index cb49ab3f..f2f35693 100644 --- a/components/password_manager/content/browser/password_change_success_tracker_factory.h +++ b/components/password_manager/content/browser/password_change_success_tracker_factory.h
@@ -28,6 +28,8 @@ private: KeyedService* BuildServiceInstanceFor( content::BrowserContext* browser_context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; }; } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc index f8c711a1..e267cdd 100644 --- a/components/password_manager/core/browser/password_manager.cc +++ b/components/password_manager/core/browser/password_manager.cc
@@ -343,6 +343,8 @@ registry->RegisterBooleanPref(prefs::kPasswordsGroupingInfoRequested, false); #if BUILDFLAG(IS_IOS) registry->RegisterBooleanPref(prefs::kAccountStorageNoticeShown, false); + registry->RegisterIntegerPref(prefs::kAccountStorageNewFeatureIconImpressions, + 0); #endif #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // Desktop registry->RegisterListPref(prefs::kPasswordManagerPromoCardsList);
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h index 1582334..691db73 100644 --- a/components/password_manager/core/common/password_manager_features.h +++ b/components/password_manager/core/common/password_manager_features.h
@@ -30,7 +30,13 @@ #endif BASE_DECLARE_FEATURE(kBiometricTouchToFill); BASE_DECLARE_FEATURE(kEnableOverwritingPlaceholderUsernames); + BASE_DECLARE_FEATURE(kEnablePasswordsAccountStorage); +inline constexpr base::FeatureParam<int> + kMaxAccountStorageNewFeatureIconImpressions = { + &kEnablePasswordsAccountStorage, + "max_account_storage_new_feature_icon_impressions", 5}; + BASE_DECLARE_FEATURE(kEnablePasswordGenerationForClearTextFields); BASE_DECLARE_FEATURE(kEnablePasswordManagerWithinFencedFrame); BASE_DECLARE_FEATURE(kFillingAcrossAffiliatedWebsites);
diff --git a/components/password_manager/core/common/password_manager_pref_names.cc b/components/password_manager/core/common/password_manager_pref_names.cc index b6bf7f42..c502f34a 100644 --- a/components/password_manager/core/common/password_manager_pref_names.cc +++ b/components/password_manager/core/common/password_manager_pref_names.cc
@@ -127,6 +127,9 @@ #if BUILDFLAG(IS_IOS) const char kAccountStorageNoticeShown[] = "password_manager.account_storage_notice_shown"; + +const char kAccountStorageNewFeatureIconImpressions[] = + "password_manager.account_storage_new_feature_icon_impressions"; #endif // BUILDFLAG(IS_IOS) #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // Desktop
diff --git a/components/password_manager/core/common/password_manager_pref_names.h b/components/password_manager/core/common/password_manager_pref_names.h index 35b80f2c..3713e4f 100644 --- a/components/password_manager/core/common/password_manager_pref_names.h +++ b/components/password_manager/core/common/password_manager_pref_names.h
@@ -232,6 +232,10 @@ // Boolean pref indicating if the one-time notice for account storage was shown. // The notice informs passwords will start being saved to the signed-in account. extern const char kAccountStorageNoticeShown[]; + +// Integer value indicating the number of times the "new feature icon" was +// displayed with the account storage opt-out toggle. +extern const char kAccountStorageNewFeatureIconImpressions[]; #endif // BUILDFLAG(IS_IOS) #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // Desktop
diff --git a/components/permissions/permission_manager_unittest.cc b/components/permissions/permission_manager_unittest.cc index e830876a..ca6cea1c 100644 --- a/components/permissions/permission_manager_unittest.cc +++ b/components/permissions/permission_manager_unittest.cc
@@ -255,7 +255,9 @@ parsed_origins.emplace_back(url::Origin::Create(GURL(origin)), /*has_subdomain_wildcard=*/false); navigation->SetPermissionsPolicyHeader( - {{feature, parsed_origins, false, false}}); + {{feature, parsed_origins, /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}); navigation->Commit(); *rfh = navigation->GetFinalRenderFrameHost(); } @@ -271,7 +273,9 @@ blink::OriginWithPossibleWildcards( url::Origin::Create(origin), /*has_subdomain_wildcard=*/false)}, - false, false}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}); } content::RenderFrameHost* result = content::RenderFrameHostTester::For(parent)->AppendChildWithPolicy(
diff --git a/components/permissions/permission_uma_util_unittest.cc b/components/permissions/permission_uma_util_unittest.cc index bfd4063..aaeb7cc7 100644 --- a/components/permissions/permission_uma_util_unittest.cc +++ b/components/permissions/permission_uma_util_unittest.cc
@@ -50,7 +50,8 @@ allow_origins.emplace_back(url::Origin::Create(GURL(origin)), /*has_subdomain_wildcard=*/false); } - return {{feature, allow_origins, matches_all_origins, + return {{feature, allow_origins, /*self_if_matches=*/absl::nullopt, + matches_all_origins, /*matches_opaque_src*/ false}}; }
diff --git a/components/policy/core/common/policy_pref_names.cc b/components/policy/core/common/policy_pref_names.cc index c7c6f64..998e9237 100644 --- a/components/policy/core/common/policy_pref_names.cc +++ b/components/policy/core/common/policy_pref_names.cc
@@ -148,5 +148,11 @@ // from the New Tab Page and app launcher. const char kHideWebStoreIcon[] = "hide_web_store_icon"; +// Enum that specifies whether Incognito mode is: +// 0 - Enabled. Default behaviour. Default mode is available on demand. +// 1 - Disabled. User cannot browse pages in Incognito mode. +// 2 - Forced. All pages/sessions are forced into Incognito. +const char kIncognitoModeAvailability[] = "incognito.mode_availability"; + } // namespace policy_prefs } // namespace policy
diff --git a/components/policy/core/common/policy_pref_names.h b/components/policy/core/common/policy_pref_names.h index af3c6339..47c3ed2 100644 --- a/components/policy/core/common/policy_pref_names.h +++ b/components/policy/core/common/policy_pref_names.h
@@ -52,6 +52,7 @@ extern const char kForceGoogleSafeSearch[]; extern const char kForceYouTubeRestrict[]; extern const char kHideWebStoreIcon[]; +extern const char kIncognitoModeAvailability[]; } // namespace policy_prefs } // namespace policy
diff --git a/components/reading_list/core/dual_reading_list_model.cc b/components/reading_list/core/dual_reading_list_model.cc index d055e57c..f46bbf60 100644 --- a/components/reading_list/core/dual_reading_list_model.cc +++ b/components/reading_list/core/dual_reading_list_model.cc
@@ -126,8 +126,34 @@ void DualReadingListModel::MarkAllSeen() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // TODO(crbug.com/1402196): Implement. - NOTIMPLEMENTED(); + DCHECK(loaded()); + + std::unique_ptr<DualReadingListModel::ScopedReadingListBatchUpdate> + scoped_model_batch_updates = BeginBatchUpdates(); + + for (const auto& url : GetKeys()) { + scoped_refptr<const ReadingListEntry> entry = GetEntryByURL(url); + const bool notify_observers = !entry->HasBeenSeen(); + if (notify_observers) { + NotifyObserversWithWillUpdateEntry(url); + UpdateEntryStateCountersOnEntryRemoval(*entry); + } + + { + base::AutoReset<bool> auto_reset_suppress_observer_notifications( + &suppress_observer_notifications_, true); + local_or_syncable_model_->MarkEntrySeenIfExists(url); + account_model_->MarkEntrySeenIfExists(url); + } + + if (notify_observers) { + UpdateEntryStateCountersOnEntryInsertion(*GetEntryByURL(url)); + NotifyObserversWithDidUpdateEntry(url); + NotifyObserversWithDidApplyChanges(); + } + } + + DCHECK_EQ(unseen_entry_count_, 0ul); } bool DualReadingListModel::DeleteAllEntries() {
diff --git a/components/reading_list/core/dual_reading_list_model_unittest.cc b/components/reading_list/core/dual_reading_list_model_unittest.cc index 904b3b9..d8c3abd 100644 --- a/components/reading_list/core/dual_reading_list_model_unittest.cc +++ b/components/reading_list/core/dual_reading_list_model_unittest.cc
@@ -307,6 +307,74 @@ EXPECT_EQ(2ul, dual_model_->size()); } +TEST_F(DualReadingListModelTest, MarkAllSeen) { + const GURL kLocalUrl("http://local_url.com/"); + const GURL kAccountUrl("http://account_url.com/"); + const GURL kCommonUrl("http://common_url.com/"); + + ASSERT_TRUE(ResetStorageAndTriggerLoadCompletion( + /*initial_local_or_syncable_entries_builders=*/ + {TestEntryBuilder(kLocalUrl, clock_.Now()), + TestEntryBuilder(kCommonUrl, clock_.Now())}, + /*initial_account_entries_builders=*/{ + TestEntryBuilder(kAccountUrl, clock_.Now()), + TestEntryBuilder(kCommonUrl, clock_.Now())})); + ASSERT_TRUE(dual_model_->loaded()); + + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kLocalUrl), + StorageStateForTesting::kExistsInLocalOrSyncableModelOnly); + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kAccountUrl), + StorageStateForTesting::kExistsInAccountModelOnly); + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kCommonUrl), + StorageStateForTesting::kExistsInBothModels); + + ASSERT_FALSE(dual_model_->GetEntryByURL(kLocalUrl)->HasBeenSeen()); + ASSERT_FALSE(dual_model_->GetEntryByURL(kAccountUrl)->HasBeenSeen()); + ASSERT_FALSE(dual_model_->GetEntryByURL(kCommonUrl)->HasBeenSeen()); + ASSERT_FALSE(dual_model_->GetEntryByURL(kLocalUrl)->IsRead()); + ASSERT_FALSE(dual_model_->GetEntryByURL(kAccountUrl)->IsRead()); + ASSERT_FALSE(dual_model_->GetEntryByURL(kCommonUrl)->IsRead()); + + { + testing::InSequence seq1; + EXPECT_CALL(observer_, + ReadingListWillUpdateEntry(dual_model_.get(), kLocalUrl)); + EXPECT_CALL(observer_, + ReadingListDidUpdateEntry(dual_model_.get(), kLocalUrl)); + EXPECT_CALL(observer_, ReadingListDidApplyChanges(dual_model_.get())) + .RetiresOnSaturation(); + } + + { + testing::InSequence seq2; + EXPECT_CALL(observer_, + ReadingListWillUpdateEntry(dual_model_.get(), kAccountUrl)); + EXPECT_CALL(observer_, + ReadingListDidUpdateEntry(dual_model_.get(), kAccountUrl)); + EXPECT_CALL(observer_, ReadingListDidApplyChanges(dual_model_.get())) + .RetiresOnSaturation(); + } + + { + testing::InSequence seq3; + EXPECT_CALL(observer_, + ReadingListWillUpdateEntry(dual_model_.get(), kCommonUrl)); + EXPECT_CALL(observer_, + ReadingListDidUpdateEntry(dual_model_.get(), kCommonUrl)); + EXPECT_CALL(observer_, ReadingListDidApplyChanges(dual_model_.get())) + .RetiresOnSaturation(); + } + + dual_model_->MarkAllSeen(); + + EXPECT_TRUE(dual_model_->GetEntryByURL(kLocalUrl)->HasBeenSeen()); + EXPECT_TRUE(dual_model_->GetEntryByURL(kAccountUrl)->HasBeenSeen()); + EXPECT_TRUE(dual_model_->GetEntryByURL(kCommonUrl)->HasBeenSeen()); + EXPECT_FALSE(dual_model_->GetEntryByURL(kLocalUrl)->IsRead()); + EXPECT_FALSE(dual_model_->GetEntryByURL(kAccountUrl)->IsRead()); + EXPECT_FALSE(dual_model_->GetEntryByURL(kCommonUrl)->IsRead()); +} + TEST_F(DualReadingListModelTest, BatchUpdates) { ASSERT_TRUE(ResetStorageAndTriggerLoadCompletion()); EXPECT_CALL(observer_, ReadingListModelBeganBatchUpdates(dual_model_.get())); @@ -1884,6 +1952,63 @@ EXPECT_EQ(5ul, dual_model_->unread_size()); } +TEST_F(DualReadingListModelTest, ShouldMaintainCountsWhenMarkAllSeen) { + const GURL kUnseenLocalUrl("http://unseen_local_url.com/"); + const GURL kUnreadLocalUrl("http://unread_local_url.com/"); + const GURL kReadLocalUrl("http://read_local_url.com/"); + const GURL kUnseenAccountUrl("http://unseen_account_url.com/"); + const GURL kUnreadAccountUrl("http://unread_account_url.com/"); + const GURL kReadAccountUrl("http://read_account_url.com/"); + const GURL kUnseenCommonUrl("http://unseen_common_url.com/"); + const GURL kUnreadCommonUrl("http://unread_common_url.com/"); + const GURL kReadCommonUrl("http://read_common_url.com/"); + + ASSERT_TRUE(ResetStorageAndTriggerLoadCompletion( + /*initial_local_or_syncable_entries_builders=*/ + {TestEntryBuilder(kUnseenLocalUrl, clock_.Now()), + TestEntryBuilder(kUnreadLocalUrl, clock_.Now()).SetRead(false), + TestEntryBuilder(kReadLocalUrl, clock_.Now()).SetRead(), + TestEntryBuilder(kUnseenCommonUrl, clock_.Now()), + TestEntryBuilder(kUnreadCommonUrl, clock_.Now()).SetRead(false), + TestEntryBuilder(kReadCommonUrl, clock_.Now())}, + /*initial_account_entries_builders=*/{ + TestEntryBuilder(kUnseenAccountUrl, clock_.Now()), + TestEntryBuilder(kUnreadAccountUrl, clock_.Now()).SetRead(false), + TestEntryBuilder(kReadAccountUrl, clock_.Now()).SetRead(), + TestEntryBuilder(kUnseenCommonUrl, clock_.Now()), + TestEntryBuilder(kUnreadCommonUrl, clock_.Now()).SetRead(false), + TestEntryBuilder(kReadCommonUrl, clock_.Now()) + .SetRead(clock_.Now() + base::Seconds(1))})); + ASSERT_TRUE(dual_model_->loaded()); + + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnseenLocalUrl), + StorageStateForTesting::kExistsInLocalOrSyncableModelOnly); + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadLocalUrl), + StorageStateForTesting::kExistsInLocalOrSyncableModelOnly); + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadLocalUrl), + StorageStateForTesting::kExistsInLocalOrSyncableModelOnly); + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnseenAccountUrl), + StorageStateForTesting::kExistsInAccountModelOnly); + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadAccountUrl), + StorageStateForTesting::kExistsInAccountModelOnly); + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadAccountUrl), + StorageStateForTesting::kExistsInAccountModelOnly); + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kUnreadCommonUrl), + StorageStateForTesting::kExistsInBothModels); + ASSERT_EQ(dual_model_->GetStorageStateForURLForTesting(kReadCommonUrl), + StorageStateForTesting::kExistsInBothModels); + + ASSERT_EQ(9ul, dual_model_->size()); + ASSERT_EQ(3ul, dual_model_->unseen_size()); + ASSERT_EQ(6ul, dual_model_->unread_size()); + + dual_model_->MarkAllSeen(); + + EXPECT_EQ(9ul, dual_model_->size()); + EXPECT_EQ(0ul, dual_model_->unseen_size()); + EXPECT_EQ(6ul, dual_model_->unread_size()); +} + TEST_F(DualReadingListModelTest, ShouldMaintainCountsWhenRemoveLocalUnreadEntry) { ASSERT_TRUE(ResetStorageAndTriggerLoadCompletion(
diff --git a/components/reading_list/core/reading_list_model_impl.cc b/components/reading_list/core/reading_list_model_impl.cc index f455fb7..f5d58eab 100644 --- a/components/reading_list/core/reading_list_model_impl.cc +++ b/components/reading_list/core/reading_list_model_impl.cc
@@ -151,26 +151,7 @@ BeginBatchUpdatesWithSyncMetadata(); for (auto& iterator : entries_) { - ReadingListEntry& entry = *(iterator.second); - if (entry.HasBeenSeen()) { - continue; - } - for (auto& observer : observers_) { - observer.ReadingListWillUpdateEntry(this, iterator.first); - } - UpdateEntryStateCountersOnEntryRemoval(entry); - entry.SetRead(false, clock_->Now()); - UpdateEntryStateCountersOnEntryInsertion(entry); - - batch->GetStorageBatch()->SaveEntry(entry); - sync_bridge_.DidAddOrUpdateEntry(entry, batch->GetSyncMetadataChangeList()); - - for (ReadingListModelObserver& observer : observers_) { - observer.ReadingListDidUpdateEntry(this, iterator.first); - } - for (auto& observer : observers_) { - observer.ReadingListDidApplyChanges(this); - } + MarkEntrySeenImpl(iterator.second.get()); } DCHECK(unseen_entry_count_ == 0); } @@ -572,6 +553,17 @@ return token; } +void ReadingListModelImpl::MarkEntrySeenIfExists(const GURL& url) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(loaded()); + + auto iterator = entries_.find(url); + if (iterator == entries_.end()) { + return; + } + MarkEntrySeenImpl(iterator->second.get()); +} + bool ReadingListModelImpl::IsTrackingSyncMetadata() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return sync_bridge_.change_processor()->IsTrackingMetadata(); @@ -659,6 +651,37 @@ return storage_layer_.get(); } +void ReadingListModelImpl::MarkEntrySeenImpl(ReadingListEntry* entry) { + DCHECK(entry); + + if (entry->HasBeenSeen()) { + return; + } + + for (auto& observer : observers_) { + observer.ReadingListWillUpdateEntry(this, entry->URL()); + } + + UpdateEntryStateCountersOnEntryRemoval(*entry); + DCHECK(!entry->IsRead()); + // SetRead() is used to transition the entry from the UNSEEN state to the + // UNREAD state. + entry->SetRead(false, clock_->Now()); + UpdateEntryStateCountersOnEntryInsertion(*entry); + + std::unique_ptr<ReadingListModelStorage::ScopedBatchUpdate> batch = + storage_layer_->EnsureBatchCreated(); + batch->SaveEntry(*entry); + sync_bridge_.DidAddOrUpdateEntry(*entry, batch->GetSyncMetadataChangeList()); + + for (ReadingListModelObserver& observer : observers_) { + observer.ReadingListDidUpdateEntry(this, entry->URL()); + } + for (ReadingListModelObserver& observer : observers_) { + observer.ReadingListDidApplyChanges(this); + } +} + void ReadingListModelImpl::AddEntryImpl(scoped_refptr<ReadingListEntry> entry, reading_list::EntrySource source) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/reading_list/core/reading_list_model_impl.h b/components/reading_list/core/reading_list_model_impl.h index 6f6ec66..42972f6 100644 --- a/components/reading_list/core/reading_list_model_impl.h +++ b/components/reading_list/core/reading_list_model_impl.h
@@ -110,6 +110,10 @@ std::unique_ptr<ReadingListModelStorage::ScopedBatchUpdate> storage_token_; }; + // If an entry exists with `url` and is unseen, it gets marked as seen (but + // unread). + void MarkEntrySeenIfExists(const GURL& url); + // Same as BeginBatchUpdates(), but returns specifically // ReadingListModelImpl's ScopedReadingListBatchUpdateImpl. std::unique_ptr<ScopedReadingListBatchUpdateImpl> @@ -151,6 +155,8 @@ // Returns the |storage_layer_| of the model. ReadingListModelStorage* StorageLayer(); + void MarkEntrySeenImpl(ReadingListEntry* entry); + // Add |entry| to the model, which must not exist before, and notify the sync // bridge if |source| is not ADDED_VIA_SYNC. void AddEntryImpl(scoped_refptr<ReadingListEntry> entry,
diff --git a/components/reading_list/core/reading_list_model_unittest.cc b/components/reading_list/core/reading_list_model_unittest.cc index 0313939..209d5f6 100644 --- a/components/reading_list/core/reading_list_model_unittest.cc +++ b/components/reading_list/core/reading_list_model_unittest.cc
@@ -117,6 +117,18 @@ void FakeStorageDidSaveEntry() override { storage_saved_ += 1; } void FakeStorageDidRemoveEntry() override { storage_removed_ += 1; } + size_t UnseenSize() { + size_t size = 0; + for (const auto& url : model_->GetKeys()) { + scoped_refptr<const ReadingListEntry> entry = model_->GetEntryByURL(url); + if (!entry->HasBeenSeen()) { + size++; + } + } + DCHECK_EQ(size, model_->unseen_size()); + return size; + } + size_t UnreadSize() { size_t size = 0; for (const auto& url : model_->GetKeys()) { @@ -215,6 +227,74 @@ model_.reset(); } +TEST_F(ReadingListModelTest, MarkEntrySeenIfExists) { + const GURL example1("http://example1.com/"); + ASSERT_TRUE(ResetStorage()->TriggerLoadCompletion( + /*entries=*/{base::MakeRefCounted<ReadingListEntry>( + example1, "example1_title", clock_.Now())})); + + ASSERT_TRUE(model_->loaded()); + ASSERT_FALSE(model_->GetEntryByURL(example1)->HasBeenSeen()); + ASSERT_FALSE(model_->GetEntryByURL(example1)->IsRead()); + ASSERT_EQ(1ul, UnseenSize()); + ASSERT_EQ(1ul, UnreadSize()); + + testing::InSequence seq; + EXPECT_CALL(observer_, ReadingListWillUpdateEntry(model_.get(), example1)); + EXPECT_CALL(observer_, ReadingListDidUpdateEntry(model_.get(), example1)); + EXPECT_CALL(observer_, ReadingListDidApplyChanges(model_.get())); + + model_->MarkEntrySeenIfExists(example1); + + EXPECT_TRUE(model_->GetEntryByURL(example1)->HasBeenSeen()); + EXPECT_FALSE(model_->GetEntryByURL(example1)->IsRead()); + EXPECT_EQ(0ul, UnseenSize()); + EXPECT_EQ(1ul, UnreadSize()); +} + +TEST_F(ReadingListModelTest, MarkAllSeen) { + const GURL example1("http://example1.com/"); + const GURL example2("http://example2.com/"); + ASSERT_TRUE(ResetStorage()->TriggerLoadCompletion( + /*entries=*/{base::MakeRefCounted<ReadingListEntry>( + example1, "example1_title", clock_.Now()), + base::MakeRefCounted<ReadingListEntry>( + example2, "example2_title", clock_.Now())})); + + ASSERT_TRUE(model_->loaded()); + ASSERT_FALSE(model_->GetEntryByURL(example1)->HasBeenSeen()); + ASSERT_FALSE(model_->GetEntryByURL(example2)->HasBeenSeen()); + ASSERT_FALSE(model_->GetEntryByURL(example1)->IsRead()); + ASSERT_FALSE(model_->GetEntryByURL(example2)->IsRead()); + ASSERT_EQ(2ul, UnseenSize()); + ASSERT_EQ(2ul, UnreadSize()); + + { + testing::InSequence seq1; + EXPECT_CALL(observer_, ReadingListWillUpdateEntry(model_.get(), example1)); + EXPECT_CALL(observer_, ReadingListDidUpdateEntry(model_.get(), example1)); + EXPECT_CALL(observer_, ReadingListDidApplyChanges(model_.get())) + .RetiresOnSaturation(); + } + + { + testing::InSequence seq2; + EXPECT_CALL(observer_, ReadingListWillUpdateEntry(model_.get(), example2)); + EXPECT_CALL(observer_, ReadingListDidUpdateEntry(model_.get(), example2)); + EXPECT_CALL(observer_, ReadingListDidApplyChanges(model_.get())) + .RetiresOnSaturation(); + } + + model_->MarkAllSeen(); + + EXPECT_TRUE(model_->GetEntryByURL(example1)->HasBeenSeen()); + EXPECT_TRUE(model_->GetEntryByURL(example2)->HasBeenSeen()); + EXPECT_FALSE(model_->GetEntryByURL(example1)->IsRead()); + EXPECT_FALSE(model_->GetEntryByURL(example2)->IsRead()); + EXPECT_EQ(0ul, UnseenSize()); + EXPECT_EQ(2ul, UnreadSize()); +} + TEST_F(ReadingListModelTest, DeleteAllEntries) { const GURL example1("http://example1.com/"); const GURL example2("http://example2.com/");
diff --git a/components/safe_browsing/content/browser/client_side_detection_host.cc b/components/safe_browsing/content/browser/client_side_detection_host.cc index d314e48..4919b4ac2 100644 --- a/components/safe_browsing/content/browser/client_side_detection_host.cc +++ b/components/safe_browsing/content/browser/client_side_detection_host.cc
@@ -581,6 +581,10 @@ cached_csd_type == safe_browsing::ClientSideDetectionType::FORCE_REQUEST && IsEnhancedProtectionEnabled(*delegate_->GetPrefs()); + if (force_request_from_rt_url_lookup) { + verdict->set_client_side_detection_type( + safe_browsing::ClientSideDetectionType::FORCE_REQUEST); + } } base::UmaHistogramBoolean("SBClientPhishing.RTLookupForceRequest",
diff --git a/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc b/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc index 91ff17e..38729c3 100644 --- a/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc +++ b/components/safe_browsing/content/browser/web_ui/safe_browsing_ui.cc
@@ -632,6 +632,16 @@ #endif +std::string SerializeClientSideDetectionType(ClientSideDetectionType csd_type) { + switch (csd_type) { + case ClientSideDetectionType::CLIENT_SIDE_DETECTION_TYPE_UNSPECIFIED: + return "CLIENT_SIDE_DETECTION_TYPE_UNSPECIFIED"; + case ClientSideDetectionType::FORCE_REQUEST: + return "FORCE_REQUEST"; + } + return "UNKNOWN_ENUM_SPECIFIED"; +} + base::Value::Dict SerializeChromeUserPopulation( const ChromeUserPopulation& population) { base::Value::Dict population_dict; @@ -1073,6 +1083,11 @@ dict.Set("model_version", cpr.model_version()); if (cpr.has_dom_model_version()) dict.Set("dom_model_version", cpr.dom_model_version()); + if (cpr.has_client_side_detection_type()) { + dict.Set( + "client_side_detection_type", + SerializeClientSideDetectionType(cpr.client_side_detection_type())); + } base::Value::List features; for (const auto& feature : cpr.feature_map()) {
diff --git a/components/search/ntp_features.cc b/components/search/ntp_features.cc index 4002cb9..83d4e9647 100644 --- a/components/search/ntp_features.cc +++ b/components/search/ntp_features.cc
@@ -233,6 +233,11 @@ // If enabled, shortcuts will be shown. BASE_FEATURE(kNtpShortcuts, "NtpShortcuts", base::FEATURE_ENABLED_BY_DEFAULT); +// If enabled, shortcuts will be shown in a wide single row. +BASE_FEATURE(kNtpSingleRowShortcuts, + "NtpSingleRowShortcuts", + base::FEATURE_DISABLED_BY_DEFAULT); + // If enabled, the History clusters module will be shown. BASE_FEATURE(kNtpHistoryClustersModule, "NtpHistoryClustersModule",
diff --git a/components/search/ntp_features.h b/components/search/ntp_features.h index 69dd969..1490c4d 100644 --- a/components/search/ntp_features.h +++ b/components/search/ntp_features.h
@@ -63,6 +63,7 @@ BASE_DECLARE_FEATURE(kNtpRemoveScrim); BASE_DECLARE_FEATURE(kNtpSafeBrowsingModule); BASE_DECLARE_FEATURE(kNtpShortcuts); +BASE_DECLARE_FEATURE(kNtpSingleRowShortcuts); BASE_DECLARE_FEATURE(kNtpHandleMostVisitedNavigationExplicitly); BASE_DECLARE_FEATURE(kNtpHistoryClustersModule); BASE_DECLARE_FEATURE(kNtpHistoryClustersModuleBeginTimeDuration);
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc index db259fea..a92f77fa 100644 --- a/components/sync/driver/data_type_manager_impl.cc +++ b/components/sync/driver/data_type_manager_impl.cc
@@ -140,6 +140,13 @@ // Add types with controllers. for (const auto& [type, controller] : *controllers_) { allowed_types.Put(type); + + // Ensure that the initial precondition state is accurate, and clear + // existing metadata if necessary. Note that this happens for *all* data + // types, not just the preferred ones! + // TODO(crbug.com/897628): For non-preferred types, metadata should probably + // be cleared independent of the precondition state. + DataTypePreconditionChanged(type); } ConfigureImpl(Intersection(preferred_types, allowed_types), context); @@ -357,7 +364,7 @@ data_type_status_table_.ResetCryptoErrors(); } - UpdatePreconditionErrors(preferred_types_); + UpdatePreconditionErrors(); last_restart_time_ = base::Time::Now(); @@ -409,9 +416,8 @@ StartNextConfiguration(); } -void DataTypeManagerImpl::UpdatePreconditionErrors( - const ModelTypeSet& desired_types) { - for (ModelType type : desired_types) { +void DataTypeManagerImpl::UpdatePreconditionErrors() { + for (ModelType type : preferred_types_) { UpdatePreconditionError(type); } }
diff --git a/components/sync/driver/data_type_manager_impl.h b/components/sync/driver/data_type_manager_impl.h index aa5eded..4799178c 100644 --- a/components/sync/driver/data_type_manager_impl.h +++ b/components/sync/driver/data_type_manager_impl.h
@@ -88,9 +88,9 @@ // Prepare the parameters for the configurer's configuration. ModelTypeConfigurer::ConfigureParams PrepareConfigureParams(); - // Update precondition state of types in data_type_status_table_ to match + // Update precondition state of types in `data_type_status_table_` to match // value of DataTypeController::GetPreconditionState(). - void UpdatePreconditionErrors(const ModelTypeSet& desired_types); + void UpdatePreconditionErrors(); // Update precondition state for |type|, such that data_type_status_table_ // matches DataTypeController::GetPreconditionState(). Returns true if there
diff --git a/components/sync/driver/data_type_manager_impl_unittest.cc b/components/sync/driver/data_type_manager_impl_unittest.cc index 195990440..3400a82 100644 --- a/components/sync/driver/data_type_manager_impl_unittest.cc +++ b/components/sync/driver/data_type_manager_impl_unittest.cc
@@ -1001,6 +1001,32 @@ dtm_->Stop(ShutdownReason::STOP_SYNC_AND_KEEP_DATA); EXPECT_EQ(DataTypeManager::STOPPED, dtm_->state()); EXPECT_TRUE(configurer_.connected_types().Empty()); + + EXPECT_EQ(0, GetController(BOOKMARKS)->model()->clear_metadata_call_count()); +} + +TEST_F(SyncDataTypeManagerImplTest, FailingPreconditionClearData) { + AddController(BOOKMARKS); + GetController(BOOKMARKS)->SetPreconditionState( + DataTypeController::PreconditionState::kMustStopAndClearData); + + // Bookmarks is never started due to failing preconditions. + DataTypeStatusTable::TypeErrorMap error_map; + error_map[BOOKMARKS] = + SyncError(FROM_HERE, SyncError::DATATYPE_POLICY_ERROR, "", BOOKMARKS); + DataTypeStatusTable expected_status_table; + expected_status_table.UpdateFailedDataTypes(error_map); + SetConfigureStartExpectation(); + SetConfigureDoneExpectation(DataTypeManager::OK, expected_status_table); + + Configure(ModelTypeSet(BOOKMARKS)); + FinishDownload(ModelTypeSet(), ModelTypeSet()); // control types + + EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state()); + EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state()); + EXPECT_EQ(0U, configurer_.connected_types().Size()); + + EXPECT_EQ(1, GetController(BOOKMARKS)->model()->clear_metadata_call_count()); } // Tests that unready types are not started after ResetDataTypeErrors and
diff --git a/components/sync/protocol/entity_specifics.proto b/components/sync/protocol/entity_specifics.proto index 09713b5..97c0e080 100644 --- a/components/sync/protocol/entity_specifics.proto +++ b/components/sync/protocol/entity_specifics.proto
@@ -57,6 +57,7 @@ import "components/sync/protocol/typed_url_specifics.proto"; import "components/sync/protocol/user_consent_specifics.proto"; import "components/sync/protocol/user_event_specifics.proto"; +import "components/sync/protocol/web_apk_specifics.proto"; import "components/sync/protocol/web_app_specifics.proto"; import "components/sync/protocol/webauthn_credential_specifics.proto"; import "components/sync/protocol/wifi_configuration_specifics.proto"; @@ -150,6 +151,7 @@ UserConsentSpecifics user_consent = 556014; SendTabToSelfSpecifics send_tab_to_self = 601980; SecurityEventSpecifics security_event = 600372; + WebApkSpecifics web_apk = 1117170; WebAppSpecifics web_app = 673225; WifiConfigurationSpecifics wifi_configuration = 662827; OsPreferenceSpecifics os_preference = 702141;
diff --git a/components/sync/protocol/proto_enum_conversions.cc b/components/sync/protocol/proto_enum_conversions.cc index 80a1cd6..106f628 100644 --- a/components/sync/protocol/proto_enum_conversions.cc +++ b/components/sync/protocol/proto_enum_conversions.cc
@@ -676,6 +676,17 @@ return ""; } +const char* ProtoEnumToString(sync_pb::WebApkIconInfo::Purpose purpose) { + ASSERT_ENUM_BOUNDS(sync_pb::WebApkIconInfo, Purpose, UNSPECIFIED, MONOCHROME); + switch (purpose) { + ENUM_CASE(sync_pb::WebApkIconInfo, UNSPECIFIED); + ENUM_CASE(sync_pb::WebApkIconInfo, ANY); + ENUM_CASE(sync_pb::WebApkIconInfo, MASKABLE); + ENUM_CASE(sync_pb::WebApkIconInfo, MONOCHROME); + } + NOTREACHED_NORETURN(); +} + const char* ProtoEnumToString(sync_pb::WebAppIconInfo::Purpose purpose) { ASSERT_ENUM_BOUNDS(sync_pb::WebAppIconInfo, Purpose, UNSPECIFIED, MONOCHROME); switch (purpose) {
diff --git a/components/sync/protocol/proto_enum_conversions.h b/components/sync/protocol/proto_enum_conversions.h index 9245045..c020c28 100644 --- a/components/sync/protocol/proto_enum_conversions.h +++ b/components/sync/protocol/proto_enum_conversions.h
@@ -23,6 +23,7 @@ #include "components/sync/protocol/sync_enums.pb.h" #include "components/sync/protocol/user_consent_types.pb.h" #include "components/sync/protocol/user_event_specifics.pb.h" +#include "components/sync/protocol/web_apk_specifics.pb.h" #include "components/sync/protocol/web_app_specifics.pb.h" #include "components/sync/protocol/wifi_configuration_specifics.pb.h" #include "components/sync/protocol/workspace_desk_specifics.pb.h" @@ -149,6 +150,8 @@ const char* ProtoEnumToString( sync_pb::WalletMetadataSpecifics::Type wallet_metadata_type); +const char* ProtoEnumToString(sync_pb::WebApkIconInfo::Purpose purpose); + const char* ProtoEnumToString(sync_pb::WebAppIconInfo::Purpose purpose); const char* ProtoEnumToString(
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h index ceea5e9..c294bc8 100644 --- a/components/sync/protocol/proto_visitors.h +++ b/components/sync/protocol/proto_visitors.h
@@ -53,6 +53,7 @@ #include "components/sync/protocol/unique_position.pb.h" #include "components/sync/protocol/user_consent_specifics.pb.h" #include "components/sync/protocol/user_event_specifics.pb.h" +#include "components/sync/protocol/web_apk_specifics.pb.h" #include "components/sync/protocol/web_app_specifics.pb.h" #include "components/sync/protocol/webauthn_credential_specifics.pb.h" #include "components/sync/protocol/workspace_desk_specifics.pb.h" @@ -1414,6 +1415,21 @@ VISIT(instrument_token); } +VISIT_PROTO_FIELDS(const sync_pb::WebApkIconInfo& proto) { + VISIT(size_in_px); + VISIT(url); + VISIT_ENUM(purpose); +} + +VISIT_PROTO_FIELDS(const sync_pb::WebApkSpecifics& proto) { + VISIT(manifest_id); + VISIT(start_url); + VISIT(name); + VISIT(theme_color); + VISIT(scope); + VISIT_REP(icon_infos); +} + VISIT_PROTO_FIELDS(const sync_pb::WebAppIconInfo& proto) { VISIT(size_in_px); VISIT(url);
diff --git a/components/sync/protocol/protocol_sources.gni b/components/sync/protocol/protocol_sources.gni index 83bd7faf..877ac18 100644 --- a/components/sync/protocol/protocol_sources.gni +++ b/components/sync/protocol/protocol_sources.gni
@@ -73,6 +73,7 @@ "user_consent_types.proto", "user_event_specifics.proto", "vault.proto", + "web_apk_specifics.proto", "web_app_specifics.proto", "webauthn_credential_specifics.proto", "wifi_configuration_specifics.proto",
diff --git a/components/sync/protocol/web_apk_specifics.proto b/components/sync/protocol/web_apk_specifics.proto new file mode 100644 index 0000000..f727ce6 --- /dev/null +++ b/components/sync/protocol/web_apk_specifics.proto
@@ -0,0 +1,46 @@ +// Copyright 2023 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// If you change or add any fields in this file, update +// components/sync/protocol/proto_visitors.h and potentially +// components/sync/protocol/proto_enum_conversions.{h, cc}. + +syntax = "proto2"; + +option java_multiple_files = true; +option java_package = "org.chromium.components.sync.protocol"; + +option optimize_for = LITE_RUNTIME; + +package sync_pb; + +// Sync & local data: Information about web app icon. +message WebApkIconInfo { + enum Purpose { + UNSPECIFIED = 0; + // Suitable for any purpose. + ANY = 1; + // Designed for masking. + MASKABLE = 2; + // Suitable for monochrome purposes. + MONOCHROME = 3; + } + + // The size of the square app icon, in raw pixels. + optional int32 size_in_px = 1; + // The URL of the app icon. + optional string url = 2; + // The purpose or context in which the icon should be used. + optional Purpose purpose = 3; +} + +// WebApk data. +message WebApkSpecifics { + optional string manifest_id = 1; + optional string start_url = 2; + optional string name = 3; + optional uint32 theme_color = 4; + optional string scope = 5; + repeated WebApkIconInfo icon_infos = 6; +}
diff --git a/components/unified_consent/BUILD.gn b/components/unified_consent/BUILD.gn index 4c1a392..635cc8b9 100644 --- a/components/unified_consent/BUILD.gn +++ b/components/unified_consent/BUILD.gn
@@ -4,6 +4,8 @@ static_library("unified_consent") { sources = [ + "consent_throttle.cc", + "consent_throttle.h", "pref_names.cc", "pref_names.h", "unified_consent_metrics.cc", @@ -27,6 +29,7 @@ source_set("unit_tests") { testonly = true sources = [ + "consent_throttle_unittest.cc", "unified_consent_service_unittest.cc", "url_keyed_data_collection_consent_helper_unittest.cc", ]
diff --git a/components/unified_consent/consent_throttle.cc b/components/unified_consent/consent_throttle.cc new file mode 100644 index 0000000..b0660e4 --- /dev/null +++ b/components/unified_consent/consent_throttle.cc
@@ -0,0 +1,82 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/unified_consent/consent_throttle.h" +#include "base/functional/bind.h" +#include "base/time/time.h" +#include "components/unified_consent/url_keyed_data_collection_consent_helper.h" + +namespace unified_consent { + +namespace { + +void FulfillRequestCallback( + UrlKeyedDataCollectionConsentHelper::State consent_state, + ConsentThrottle::RequestCallback callback) { + DCHECK_NE(consent_state, + UrlKeyedDataCollectionConsentHelper::State::kInitializing); + std::move(callback).Run(consent_state == + UrlKeyedDataCollectionConsentHelper::State::kEnabled); +} + +} // namespace + +ConsentThrottle::ConsentThrottle( + std::unique_ptr<unified_consent::UrlKeyedDataCollectionConsentHelper> + consent_helper, + base::TimeDelta timeout) + : consent_helper_(std::move(consent_helper)), timeout_(timeout) { + DCHECK(consent_helper_); + handle_observation_.Observe(consent_helper_.get()); +} + +ConsentThrottle::~ConsentThrottle() = default; + +void ConsentThrottle::OnUrlKeyedDataCollectionConsentStateChanged( + UrlKeyedDataCollectionConsentHelper* consent_helper) { + DCHECK_EQ(consent_helper, consent_helper_.get()); + + auto consent_state = consent_helper->GetConsentState(); + if (consent_state == + UrlKeyedDataCollectionConsentHelper::State::kInitializing) { + return; + } + + for (auto& request_callback : enqueued_request_callbacks_) { + FulfillRequestCallback(consent_state, std::move(request_callback)); + } + + enqueued_request_callbacks_.clear(); + request_processing_timer_.Stop(); +} + +void ConsentThrottle::EnqueueRequest(RequestCallback callback) { + auto consent_state = consent_helper_->GetConsentState(); + if (consent_state != + UrlKeyedDataCollectionConsentHelper::State::kInitializing) { + FulfillRequestCallback(consent_state, std::move(callback)); + return; + } + + enqueued_request_callbacks_.emplace_back(std::move(callback)); + if (!request_processing_timer_.IsRunning()) { + request_processing_timer_.Start( + FROM_HERE, timeout_, + base::BindOnce( + &ConsentThrottle::OnTimeoutExpired, + // Unretained usage here okay, because this object owns the timer. + base::Unretained(this))); + } +} + +void ConsentThrottle::OnTimeoutExpired() { + for (auto& request_callback : enqueued_request_callbacks_) { + CHECK_EQ(consent_helper_->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kInitializing); + std::move(request_callback).Run(false); + } + enqueued_request_callbacks_.clear(); +} + +} // namespace unified_consent
diff --git a/components/unified_consent/consent_throttle.h b/components/unified_consent/consent_throttle.h new file mode 100644 index 0000000..2ff7d670 --- /dev/null +++ b/components/unified_consent/consent_throttle.h
@@ -0,0 +1,76 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_UNIFIED_CONSENT_CONSENT_THROTTLE_H_ +#define COMPONENTS_UNIFIED_CONSENT_CONSENT_THROTTLE_H_ + +#include <vector> + +#include "base/functional/callback.h" +#include "base/scoped_observation.h" +#include "base/time/time.h" +#include "base/timer/elapsed_timer.h" +#include "base/timer/timer.h" +#include "components/unified_consent/url_keyed_data_collection_consent_helper.h" + +namespace unified_consent { + +// This class throttles consent requests when the underlying consent helper is +// still initializing. It operates in two modes: +// +// 1) If the underlying consent helper is still initializing: +// - It holds requests in a queue for up to as long as the timeout. +// - If the consent helper finishes initializing in that time, it will call +// the request callback with the definitive answer. +// - If the consent helper doesn't finish initializing in that time, it +// will call the callback with a False answer. +// +// 2) If the underlying consent helper is already initialized, this class is +// just a passthrough, and the underlying consent helper and request +// callback are both called synchronously. +class ConsentThrottle : public UrlKeyedDataCollectionConsentHelper::Observer { + public: + using RequestCallback = base::OnceCallback<void(bool)>; + + explicit ConsentThrottle( + std::unique_ptr<UrlKeyedDataCollectionConsentHelper> consent_helper, + base::TimeDelta timeout = base::Seconds(5)); + ConsentThrottle(const ConsentThrottle&) = delete; + ConsentThrottle& operator=(const ConsentThrottle&) = delete; + ~ConsentThrottle(); + + // UrlKeyedDataCollectionConsentHelper::Observer: + void OnUrlKeyedDataCollectionConsentStateChanged( + UrlKeyedDataCollectionConsentHelper* consent_helper) override; + + // If the underlying consent helper is initialized already, this method calls + // `callback` synchronously with the result. If not, it will hold the request + // up until the timeout for the consent helper to initialize. + void EnqueueRequest(RequestCallback callback); + + private: + // This is run periodically to sweep away old queued requests. + void OnTimeoutExpired(); + + // The underlying consent helper. + std::unique_ptr<UrlKeyedDataCollectionConsentHelper> consent_helper_; + // The minimum timeout duration to hold the request for. + base::TimeDelta timeout_; + + // Observe the consent helper to handle to state changes immediately. + base::ScopedObservation<UrlKeyedDataCollectionConsentHelper, ConsentThrottle> + handle_observation_{this}; + + // Requests waiting for the consent throttle to initialize. Requests are + // stored in the queue in order of their arrival. + std::vector<RequestCallback> enqueued_request_callbacks_; + + // Timer used to periodically process unanswered enqueued requests, and + // respond to them in the negative. + base::OneShotTimer request_processing_timer_; +}; + +} // namespace unified_consent + +#endif // CHROME_BROWSER_COMPONENTS_UNIFIED_CONSENT_CONSENT_THROTTLE_H_
diff --git a/components/unified_consent/consent_throttle_unittest.cc b/components/unified_consent/consent_throttle_unittest.cc new file mode 100644 index 0000000..0566d233 --- /dev/null +++ b/components/unified_consent/consent_throttle_unittest.cc
@@ -0,0 +1,143 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/unified_consent/consent_throttle.h" +#include <memory> + +#include "base/run_loop.h" +#include "base/test/bind.h" +#include "base/test/task_environment.h" +#include "components/unified_consent/url_keyed_data_collection_consent_helper.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace unified_consent { +namespace { + +class TestUrlKeyedDataCollectionConsentHelper + : public UrlKeyedDataCollectionConsentHelper { + public: + void SetConsentStateAndFireNotification(State state) { + consent_state_ = state; + FireOnStateChanged(); + } + + // UrlKeyedCollectionConsentHelper: + State GetConsentState() override { return consent_state_; } + + private: + State consent_state_ = State::kInitializing; +}; + +class ConsentThrottleTest : public testing::Test { + protected: + bool GetResultSynchronously(ConsentThrottle* throttle) { + absl::optional<bool> out_result; + throttle->EnqueueRequest( + base::BindLambdaForTesting([&](bool result) { out_result = result; })); + EXPECT_TRUE(out_result.has_value()) + << "The throttle must have run the callback."; + return *out_result; + } + + base::test::TaskEnvironment task_environment_{ + base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME}; +}; + +TEST_F(ConsentThrottleTest, EnabledAndDisabledRunSynchronously) { + auto helper = std::make_unique<TestUrlKeyedDataCollectionConsentHelper>(); + helper->SetConsentStateAndFireNotification( + UrlKeyedDataCollectionConsentHelper::State::kDisabled); + + auto* helper_ptr = helper.get(); + + auto consent_throttle = ConsentThrottle(std::move(helper)); + EXPECT_FALSE(GetResultSynchronously(&consent_throttle)); + + helper_ptr->SetConsentStateAndFireNotification( + UrlKeyedDataCollectionConsentHelper::State::kEnabled); + EXPECT_TRUE(GetResultSynchronously(&consent_throttle)); +} + +TEST_F(ConsentThrottleTest, ExpireOldRequests) { + auto helper = std::make_unique<TestUrlKeyedDataCollectionConsentHelper>(); + ASSERT_EQ(helper->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kInitializing); + + auto consent_throttle = ConsentThrottle(std::move(helper)); + std::vector<bool> results; + consent_throttle.EnqueueRequest(base::BindLambdaForTesting( + [&](bool result) { results.push_back(result); })); + + EXPECT_TRUE(results.empty()) << "Callback should not be run immediately."; + task_environment_.FastForwardBy(base::Seconds(3)); + EXPECT_TRUE(results.empty()) << "Callback should not be run after 3 seconds."; + + // Add another request while the first request is still pending. + consent_throttle.EnqueueRequest(base::BindLambdaForTesting( + [&](bool result) { results.push_back(result); })); + + task_environment_.FastForwardBy(base::Seconds(5)); + ASSERT_EQ(results.size(), 2U) << "Both callbacks should expire as false."; + EXPECT_FALSE(results[0]); + EXPECT_FALSE(results[1]); + + // Enqueuing another one should restart the timer, which should expire after + // a second delay of 5 seconds. + consent_throttle.EnqueueRequest(base::BindLambdaForTesting( + [&](bool result) { results.push_back(result); })); + EXPECT_EQ(results.size(), 2U) << "Callback should not be run immediately."; + task_environment_.FastForwardBy(base::Seconds(3)); + EXPECT_EQ(results.size(), 2U); + task_environment_.FastForwardBy(base::Seconds(3)); + ASSERT_EQ(results.size(), 3U); + EXPECT_FALSE(results[2]); +} + +TEST_F(ConsentThrottleTest, InitializationFulfillsAllQueuedRequests) { + auto helper = std::make_unique<TestUrlKeyedDataCollectionConsentHelper>(); + ASSERT_EQ(helper->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kInitializing); + + auto* helper_ptr = helper.get(); + auto consent_throttle = ConsentThrottle(std::move(helper)); + + // Enqueue two requests, 2 seconds apart. + std::vector<bool> results; + consent_throttle.EnqueueRequest(base::BindLambdaForTesting( + [&](bool result) { results.push_back(result); })); + ASSERT_TRUE(results.empty()); + task_environment_.FastForwardBy(base::Seconds(2)); + consent_throttle.EnqueueRequest(base::BindLambdaForTesting( + [&](bool result) { results.push_back(result); })); + ASSERT_TRUE(results.empty()) << "Still nothing should be run yet."; + + helper_ptr->SetConsentStateAndFireNotification( + UrlKeyedDataCollectionConsentHelper::State::kEnabled); + ASSERT_EQ(results.size(), 2U) + << "Requests should have been immediately fulfilled as true."; + EXPECT_TRUE(results[0]); + EXPECT_TRUE(results[1]); +} + +TEST_F(ConsentThrottleTest, InitializationDisabledCase) { + auto helper = std::make_unique<TestUrlKeyedDataCollectionConsentHelper>(); + ASSERT_EQ(helper->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kInitializing); + + auto* helper_ptr = helper.get(); + auto consent_throttle = ConsentThrottle(std::move(helper)); + + std::vector<bool> results; + consent_throttle.EnqueueRequest(base::BindLambdaForTesting( + [&](bool result) { results.push_back(result); })); + ASSERT_TRUE(results.empty()); + + helper_ptr->SetConsentStateAndFireNotification( + UrlKeyedDataCollectionConsentHelper::State::kDisabled); + ASSERT_EQ(results.size(), 1U); + EXPECT_FALSE(results[0]); +} + +} // namespace +} // namespace unified_consent
diff --git a/components/unified_consent/url_keyed_data_collection_consent_helper.cc b/components/unified_consent/url_keyed_data_collection_consent_helper.cc index c7fa659..3624664 100644 --- a/components/unified_consent/url_keyed_data_collection_consent_helper.cc +++ b/components/unified_consent/url_keyed_data_collection_consent_helper.cc
@@ -10,6 +10,7 @@ #include "base/functional/bind.h" #include "base/memory/raw_ptr.h" #include "base/observer_list.h" +#include "base/ranges/algorithm.h" #include "components/prefs/pref_change_registrar.h" #include "components/prefs/pref_service.h" #include "components/sync/base/model_type.h" @@ -36,7 +37,7 @@ ~PrefBasedUrlKeyedDataCollectionConsentHelper() override = default; // UrlKeyedDataCollectionConsentHelper: - bool IsEnabled() override; + State GetConsentState() override; private: void OnPrefChanged(); @@ -60,7 +61,7 @@ ~SyncBasedUrlKeyedDataCollectionConsentHelper() override; // UrlKeyedDataCollectionConsentHelper: - bool IsEnabled() override; + State GetConsentState() override; // syncer::SyncServiceObserver: void OnStateChanged(syncer::SyncService* sync) override; @@ -84,9 +85,13 @@ base::Unretained(this))); } -bool PrefBasedUrlKeyedDataCollectionConsentHelper::IsEnabled() { +UrlKeyedDataCollectionConsentHelper::State +PrefBasedUrlKeyedDataCollectionConsentHelper::GetConsentState() { + // There's no initializing state for pref-based helpers. return pref_service_->GetBoolean( - prefs::kUrlKeyedAnonymizedDataCollectionEnabled); + prefs::kUrlKeyedAnonymizedDataCollectionEnabled) + ? State::kEnabled + : State::kDisabled; } void PrefBasedUrlKeyedDataCollectionConsentHelper::OnPrefChanged() { @@ -115,21 +120,37 @@ sync_service_->RemoveObserver(this); } -bool SyncBasedUrlKeyedDataCollectionConsentHelper::IsEnabled() { +UrlKeyedDataCollectionConsentHelper::State +SyncBasedUrlKeyedDataCollectionConsentHelper::GetConsentState() { + // Any sync type that's NOT_ACTIVE makes the whole consent kDisabled. for (const auto& sync_data_type_states : sync_data_type_states_) { - if (sync_data_type_states.second != syncer::UploadState::ACTIVE) - return false; + if (sync_data_type_states.second == syncer::UploadState::NOT_ACTIVE) { + return State::kDisabled; + } } - return true; + + // If no sync type is NOT_ACTIVE, any sync type still INITIALIZING makes the + // whole consent kInitializing. + for (const auto& sync_data_type_states : sync_data_type_states_) { + if (sync_data_type_states.second == syncer::UploadState::INITIALIZING) { + return State::kInitializing; + } + } + + DCHECK(base::ranges::all_of(sync_data_type_states_, [](auto& state) { + return state.second == syncer::UploadState::ACTIVE; + })) << "Nothing is NOT_ACTIVE or INITIALIZING, so all must be ACTIVE."; + return State::kEnabled; } void SyncBasedUrlKeyedDataCollectionConsentHelper::OnStateChanged( syncer::SyncService* sync_service) { DCHECK_EQ(sync_service_, sync_service); - bool enabled_before_state_updated = IsEnabled(); + auto old_state = GetConsentState(); UpdateSyncDataTypeStates(); - if (enabled_before_state_updated != IsEnabled()) + if (old_state != GetConsentState()) { FireOnStateChanged(); + } } void SyncBasedUrlKeyedDataCollectionConsentHelper::OnSyncShutdown( @@ -180,6 +201,10 @@ std::set<syncer::ModelType>({syncer::ModelType::BOOKMARKS})); } +bool UrlKeyedDataCollectionConsentHelper::IsEnabled() { + return GetConsentState() == State::kEnabled; +} + void UrlKeyedDataCollectionConsentHelper::AddObserver(Observer* observer) { observer_list_.AddObserver(observer); }
diff --git a/components/unified_consent/url_keyed_data_collection_consent_helper.h b/components/unified_consent/url_keyed_data_collection_consent_helper.h index 1e648ab..6daa4ac 100644 --- a/components/unified_consent/url_keyed_data_collection_consent_helper.h +++ b/components/unified_consent/url_keyed_data_collection_consent_helper.h
@@ -20,6 +20,12 @@ // for URL-keyed data collection. class UrlKeyedDataCollectionConsentHelper { public: + enum class State { + kInitializing, + kDisabled, + kEnabled, + }; + class Observer { public: // Called when the state of the URL-keyed data collection changes. @@ -63,9 +69,14 @@ virtual ~UrlKeyedDataCollectionConsentHelper(); + // Returns the state of the consent helper. To throttle requests until after + // initialization, use the `ConsentThrottle` class. + virtual State GetConsentState() = 0; + // Returns true if the user has consented for URL keyed anonymized data - // collection. - virtual bool IsEnabled() = 0; + // collection. Note, this is a simplified form of `GetConsentState()` where + // kInitializing and kDisabled are both considered NOT enabled. + bool IsEnabled(); // Methods to register or remove observers. void AddObserver(Observer* observer);
diff --git a/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc b/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc index 9586f13..d8a4eed0 100644 --- a/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc +++ b/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc
@@ -6,6 +6,7 @@ #include <vector> +#include "components/sync/driver/sync_service.h" #include "components/sync/engine/cycle/sync_cycle_snapshot.h" #include "components/sync/test/test_sync_service.h" #include "components/sync_preferences/testing_pref_service_syncable.h" @@ -66,11 +67,15 @@ UrlKeyedDataCollectionConsentHelper:: NewAnonymizedDataCollectionConsentHelper(&pref_service_); helper->AddObserver(this); + EXPECT_EQ(helper->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kDisabled); EXPECT_FALSE(helper->IsEnabled()); EXPECT_TRUE(state_changed_notifications_.empty()); pref_service_.SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled, true); + EXPECT_EQ(helper->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kEnabled); EXPECT_TRUE(helper->IsEnabled()); ASSERT_EQ(1U, state_changed_notifications_.size()); EXPECT_TRUE(state_changed_notifications_[0]); @@ -78,6 +83,8 @@ state_changed_notifications_.clear(); pref_service_.SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled, false); + EXPECT_EQ(helper->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kDisabled); EXPECT_FALSE(helper->IsEnabled()); ASSERT_EQ(1U, state_changed_notifications_.size()); EXPECT_FALSE(state_changed_notifications_[0]); @@ -89,17 +96,32 @@ UrlKeyedDataCollectionConsentHelper:: NewPersonalizedDataCollectionConsentHelper(&sync_service_); helper->AddObserver(this); + EXPECT_EQ(helper->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kDisabled); EXPECT_FALSE(helper->IsEnabled()); EXPECT_TRUE(state_changed_notifications_.empty()); + sync_service_.SetTransportState( + syncer::SyncService::TransportState::INITIALIZING); sync_service_.GetUserSettings()->SetSelectedTypes( /*sync_everything=*/false, /*types=*/syncer::UserSelectableTypeSet( syncer::UserSelectableType::kHistory)); sync_service_.FireOnStateChangeOnAllObservers(); + EXPECT_EQ(helper->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kInitializing); + EXPECT_FALSE(helper->IsEnabled()); + EXPECT_EQ(1U, state_changed_notifications_.size()) + << "No state change notifications fired, because it's still not enabled, " + "it's just initializing."; + + sync_service_.SetTransportState(syncer::SyncService::TransportState::ACTIVE); + sync_service_.FireOnStateChangeOnAllObservers(); + EXPECT_EQ(helper->GetConsentState(), + UrlKeyedDataCollectionConsentHelper::State::kEnabled); EXPECT_TRUE(helper->IsEnabled()); - EXPECT_EQ(1U, state_changed_notifications_.size()); + EXPECT_EQ(2U, state_changed_notifications_.size()); helper->RemoveObserver(this); }
diff --git a/components/viz/common/quads/shared_quad_state.cc b/components/viz/common/quads/shared_quad_state.cc index 2191ce0b..24d71867 100644 --- a/components/viz/common/quads/shared_quad_state.cc +++ b/components/viz/common/quads/shared_quad_state.cc
@@ -15,7 +15,11 @@ namespace viz { SharedQuadState::SharedQuadState() = default; + SharedQuadState::SharedQuadState(const SharedQuadState& other) = default; +SharedQuadState& SharedQuadState::operator=(const SharedQuadState& other) = + default; + SharedQuadState::~SharedQuadState() { TRACE_EVENT_OBJECT_DELETED_WITH_ID(TRACE_DISABLED_BY_DEFAULT("viz.quads"), "viz::SharedQuadState", this); @@ -31,7 +35,9 @@ clip_rect == other.clip_rect && are_contents_opaque == other.are_contents_opaque && opacity == other.opacity && blend_mode == other.blend_mode && - sorting_context_id == other.sorting_context_id; + sorting_context_id == other.sorting_context_id && + layer_id == other.layer_id && + layer_namespace_id == other.layer_namespace_id; } void SharedQuadState::SetAll(const SharedQuadState& other) { @@ -44,6 +50,8 @@ opacity = other.opacity; blend_mode = other.blend_mode; sorting_context_id = other.sorting_context_id; + layer_id = other.layer_id; + layer_namespace_id = other.layer_namespace_id; } void SharedQuadState::SetAll(const gfx::Transform& transform, @@ -54,7 +62,8 @@ bool contents_opaque, float opacity_f, SkBlendMode blend, - int sorting_context) { + int sorting_context, + uint32_t layer) { quad_to_target_transform = transform; quad_layer_rect = layer_rect; visible_quad_layer_rect = visible_layer_rect; @@ -64,6 +73,7 @@ opacity = opacity_f; blend_mode = blend; sorting_context_id = sorting_context; + layer_id = layer; } void SharedQuadState::AsValueInto(base::trace_event::TracedValue* value) const { @@ -92,6 +102,8 @@ value->SetDouble("opacity", opacity); value->SetString("blend_mode", SkBlendMode_Name(blend_mode)); value->SetInteger("sorting_context_id", sorting_context_id); + value->SetInteger("layer_id", layer_id); + value->SetInteger("layer_namespace_id", layer_id); value->SetBoolean("is_fast_rounded_corner", is_fast_rounded_corner); TracedValue::MakeDictIntoImplicitSnapshotWithCategory( TRACE_DISABLED_BY_DEFAULT("viz.quads"), value, "viz::SharedQuadState",
diff --git a/components/viz/common/quads/shared_quad_state.h b/components/viz/common/quads/shared_quad_state.h index 07fc4ad..9680bb8d 100644 --- a/components/viz/common/quads/shared_quad_state.h +++ b/components/viz/common/quads/shared_quad_state.h
@@ -13,11 +13,9 @@ #include "ui/gfx/geometry/rrect_f.h" #include "ui/gfx/geometry/transform.h" -namespace base { -namespace trace_event { +namespace base::trace_event { class TracedValue; -} -} // namespace base +} // namespace base::trace_event namespace viz { @@ -31,6 +29,7 @@ public: SharedQuadState(); SharedQuadState(const SharedQuadState& other); + SharedQuadState& operator=(const SharedQuadState& other); ~SharedQuadState(); // No comparison for |overlay_damage_index| and |is_fast_rounded_corner|. @@ -38,6 +37,8 @@ void SetAll(const SharedQuadState& other); + // TODO(kylechar): Remove default value for `layer_id` after updating all + // callers. void SetAll(const gfx::Transform& transform, const gfx::Rect& layer_rect, const gfx::Rect& visible_layer_rect, @@ -46,7 +47,8 @@ bool contents_opaque, float opacity_f, SkBlendMode blend, - int sorting_context); + int sorting_context, + uint32_t layer_id = 0); void AsValueInto(base::trace_event::TracedValue* dict) const; // Transforms quad rects into the target content space. @@ -67,9 +69,16 @@ absl::optional<gfx::Rect> clip_rect; // Indicates whether the content in |quad_layer_rect| are fully opaque. bool are_contents_opaque = true; - float opacity = 1.f; + float opacity = 1.0f; SkBlendMode blend_mode = SkBlendMode::kSrcOver; int sorting_context_id = 0; + // Optionally set by the client with a stable ID for the layer that produced + // the DrawQuad(s). This is used to help identify that DrawQuad(s) in one + // frame came from the same layer as DrawQuads() from a previous frame, even + // if they changed position or other attributes. + uint32_t layer_id = 0; + // Used by SurfaceAggregator to namespace layer_ids from different clients. + uint32_t layer_namespace_id = 0; // Used by SurfaceAggregator to decide whether to merge quads for a surface // into their target render pass. It is a performance optimization by avoiding // render passes as much as possible.
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index bc97fd6a..7f20730 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -9,6 +9,7 @@ #include <algorithm> #include <limits> #include <memory> +#include <string> #include <utility> #include "base/containers/contains.h" @@ -612,11 +613,15 @@ root_render_pass.damage_rect); for (auto* quad : root_render_pass.quad_list) { - auto& transform = quad->shared_quad_state->quad_to_target_transform; + auto* sqs = quad->shared_quad_state; + auto& transform = sqs->quad_to_target_transform; auto display_rect = transform.MapRect(gfx::RectF(quad->rect)); DBG_DRAW_TEXT_OPT("frame.root.material", DBG_OPT_GREEN, display_rect.origin(), base::NumberToString(static_cast<int>(quad->material))); + DBG_DRAW_TEXT_OPT( + "frame.root.layer_id", DBG_OPT_BLUE, display_rect.origin(), + base::StringPrintf("%u:%u", sqs->layer_namespace_id, sqs->layer_id)); DBG_DRAW_TEXT_OPT("frame.root.display_rect", DBG_OPT_GREEN, display_rect.origin(), display_rect.ToString()); DBG_DRAW_TEXT_OPT(
diff --git a/components/viz/service/display/resolved_frame_data.cc b/components/viz/service/display/resolved_frame_data.cc index 4ae7a29..641c102 100644 --- a/components/viz/service/display/resolved_frame_data.cc +++ b/components/viz/service/display/resolved_frame_data.cc
@@ -75,6 +75,10 @@ previous_frame_index_ = kInvalidFrameIndex; } +uint32_t ResolvedFrameData::GetClientNamespaceId() const { + return static_cast<uint32_t>(child_resource_id_); +} + void ResolvedFrameData::ForceReleaseResource() { // Resources for future frames are stored under a new child id going forward. resource_provider_->DestroyChild(child_resource_id_);
diff --git a/components/viz/service/display/resolved_frame_data.h b/components/viz/service/display/resolved_frame_data.h index eac90925..f4e111d2 100644 --- a/components/viz/service/display/resolved_frame_data.h +++ b/components/viz/service/display/resolved_frame_data.h
@@ -144,6 +144,10 @@ bool is_valid() const { return valid_; } uint64_t previous_frame_index() const { return previous_frame_index_; } + // Returns namespace ID for the client that submitted this frame. This is used + // to deduplicate layer IDs from different clients. + uint32_t GetClientNamespaceId() const; + void SetFullDamageForNextAggregation(); // Force release all resources registered with display resource provider. Note
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc index 280b757..d521e118 100644 --- a/components/viz/service/display/surface_aggregator.cc +++ b/components/viz/service/display/surface_aggregator.cc
@@ -161,6 +161,7 @@ // - |dest_render_pass| is where the new SharedQuadState will be created. SharedQuadState* CopyAndScaleSharedQuadState( const SharedQuadState* source_sqs, + uint32_t client_namespace_id, const gfx::Transform& quad_to_target_transform, const gfx::Transform& target_transform, const gfx::Rect& quad_layer_rect, @@ -185,7 +186,9 @@ new_transform, quad_layer_rect, visible_quad_layer_rect, mask_filter_info_ext.mask_filter_info, new_clip_rect, source_sqs->are_contents_opaque, source_sqs->opacity, - source_sqs->blend_mode, source_sqs->sorting_context_id); + source_sqs->blend_mode, source_sqs->sorting_context_id, + source_sqs->layer_id); + shared_quad_state->layer_namespace_id = client_namespace_id; shared_quad_state->is_fast_rounded_corner = mask_filter_info_ext.is_fast_rounded_corner; return shared_quad_state; @@ -195,14 +198,16 @@ // into it. See CopyAndScaleSharedQuadState() for full documentation. SharedQuadState* CopySharedQuadState( const SharedQuadState* source_sqs, + uint32_t client_namespace_id, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& added_clip_rect, const MaskFilterInfoExt& mask_filter_info, AggregatedRenderPass* dest_render_pass) { return CopyAndScaleSharedQuadState( - source_sqs, source_sqs->quad_to_target_transform, target_transform, - source_sqs->quad_layer_rect, source_sqs->visible_quad_layer_rect, - added_clip_rect, mask_filter_info, dest_render_pass); + source_sqs, client_namespace_id, source_sqs->quad_to_target_transform, + target_transform, source_sqs->quad_layer_rect, + source_sqs->visible_quad_layer_rect, added_clip_rect, mask_filter_info, + dest_render_pass); } // Returns true if |resolved_pass| needs full damage. This is because: @@ -561,6 +566,7 @@ void SurfaceAggregator::HandleSurfaceQuad( const CompositorRenderPass& source_pass, const SurfaceDrawQuad* surface_quad, + uint32_t embedder_client_namespace_id, float parent_device_scale_factor, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& added_clip_rect, @@ -615,9 +621,9 @@ // SolidColorDrawQuad with the provided default background color. This // can happen after a Viz process crash. if (!resolved_frame) { - EmitDefaultBackgroundColorQuad(surface_quad, target_transform, - surface_clip_rect, dest_pass, - mask_filter_info); + EmitDefaultBackgroundColorQuad(surface_quad, embedder_client_namespace_id, + target_transform, surface_clip_rect, + dest_pass, mask_filter_info); return; } @@ -638,14 +644,16 @@ // TODO(crbug.com/1308932): CompositorFrameMetadata to SkColor4f EmitGutterQuadsIfNecessary(surface_quad->visible_rect, fallback_rect, surface_quad->shared_quad_state, - target_transform, surface_clip_rect, + embedder_client_namespace_id, target_transform, + surface_clip_rect, fallback_frame.metadata.root_background_color, dest_pass, mask_filter_info); } EmitSurfaceContent(*resolved_frame, parent_device_scale_factor, surface_quad, - target_transform, surface_clip_rect, combined_clip_rect, - dest_pass, ignore_undamaged, damage_rect_in_quad_space, + embedder_client_namespace_id, target_transform, + surface_clip_rect, combined_clip_rect, dest_pass, + ignore_undamaged, damage_rect_in_quad_space, damage_rect_in_quad_space_valid, mask_filter_info); } @@ -653,6 +661,7 @@ const ResolvedFrameData& resolved_frame, float parent_device_scale_factor, const SurfaceDrawQuad* surface_quad, + uint32_t embedder_client_namespace_id, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& added_clip_rect, const absl::optional<gfx::Rect>& dest_root_target_clip_rect, @@ -845,7 +854,8 @@ mask_filter_info); } else { auto* shared_quad_state = CopyAndScaleSharedQuadState( - surface_quad_sqs, scaled_quad_to_target_transform, target_transform, + surface_quad_sqs, embedder_client_namespace_id, + scaled_quad_to_target_transform, target_transform, gfx::ScaleToEnclosingRect(surface_quad_sqs->quad_layer_rect, inverse_extra_content_scale_x, inverse_extra_content_scale_y), @@ -907,6 +917,7 @@ void SurfaceAggregator::EmitDefaultBackgroundColorQuad( const SurfaceDrawQuad* surface_quad, + uint32_t embedder_client_namespace_id, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& clip_rect, AggregatedRenderPass* dest_pass, @@ -917,9 +928,9 @@ // No matching surface was found so create a SolidColorDrawQuad with the // SurfaceDrawQuad default background color. SkColor4f background_color = surface_quad->default_background_color; - auto* shared_quad_state = - CopySharedQuadState(surface_quad->shared_quad_state, target_transform, - clip_rect, mask_filter_info, dest_pass); + auto* shared_quad_state = CopySharedQuadState( + surface_quad->shared_quad_state, embedder_client_namespace_id, + target_transform, clip_rect, mask_filter_info, dest_pass); auto* solid_color_quad = dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); @@ -931,6 +942,7 @@ const gfx::Rect& primary_rect, const gfx::Rect& fallback_rect, const SharedQuadState* primary_shared_quad_state, + uint32_t embedder_client_namespace_id, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& clip_rect, SkColor4f background_color, @@ -950,7 +962,7 @@ primary_rect.height()); SharedQuadState* shared_quad_state = CopyAndScaleSharedQuadState( - primary_shared_quad_state, + primary_shared_quad_state, embedder_client_namespace_id, primary_shared_quad_state->quad_to_target_transform, target_transform, right_gutter_rect, right_gutter_rect, clip_rect, mask_filter_info, dest_pass); @@ -967,7 +979,7 @@ primary_rect.height() - fallback_rect.height()); SharedQuadState* shared_quad_state = CopyAndScaleSharedQuadState( - primary_shared_quad_state, + primary_shared_quad_state, embedder_client_namespace_id, primary_shared_quad_state->quad_to_target_transform, target_transform, bottom_gutter_rect, bottom_gutter_rect, clip_rect, mask_filter_info, dest_pass); @@ -1221,6 +1233,9 @@ size_t quad_index = 0; auto& resolved_draw_quads = resolved_pass.draw_quads(); + + uint32_t client_namespace_id = resolved_frame.GetClientNamespaceId(); + for (auto* quad : source_quad_list) { const ResolvedQuadData& quad_data = resolved_draw_quads[quad_index++]; @@ -1247,9 +1262,10 @@ quad->shared_quad_state->is_fast_rounded_corner, target_transform); } - HandleSurfaceQuad(source_pass, surface_quad, parent_device_scale_factor, - target_transform, clip_rect, dest_root_target_clip_rect, - dest_pass, ignore_undamaged, &damage_rect_in_quad_space, + HandleSurfaceQuad(source_pass, surface_quad, client_namespace_id, + parent_device_scale_factor, target_transform, clip_rect, + dest_root_target_clip_rect, dest_pass, ignore_undamaged, + &damage_rect_in_quad_space, &damage_rect_in_quad_space_valid, new_mask_filter_info_ext); } else { @@ -1260,9 +1276,9 @@ quad->shared_quad_state->is_fast_rounded_corner, target_transform); } - SharedQuadState* dest_shared_quad_state = - CopySharedQuadState(quad->shared_quad_state, target_transform, - clip_rect, new_mask_filter_info_ext, dest_pass); + SharedQuadState* dest_shared_quad_state = CopySharedQuadState( + quad->shared_quad_state, client_namespace_id, target_transform, + clip_rect, new_mask_filter_info_ext, dest_pass); // Here we output the optional quad's |per_quad_damage| to the // |surface_damage_rect_list_|. Any non per quad damage associated with // this |source_pass| will have been added to the
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h index 6e01986c..51ae2e9 100644 --- a/components/viz/service/display/surface_aggregator.h +++ b/components/viz/service/display/surface_aggregator.h
@@ -139,6 +139,8 @@ ResolvedFrameData* GetResolvedFrame(const SurfaceId& surface_id); // - |source_pass| is the render pass that contains |surface_quad|. + // - |embedder_client_namespace_id| is portion of layer_id that uniquely + // identifies the client which contains |surface_quad|. // - |target_transform| is the transform from the coordinate space of // |source_pass| to |dest_pass|. // - |added_clip_rect| is an added clip rect in the |dest_pass| coordinate @@ -150,6 +152,7 @@ void HandleSurfaceQuad( const CompositorRenderPass& source_pass, const SurfaceDrawQuad* surface_quad, + uint32_t embedder_client_namespace_id, float parent_device_scale_factor, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& added_clip_rect, @@ -164,6 +167,7 @@ const ResolvedFrameData& resolved_frame, float parent_device_scale_factor, const SurfaceDrawQuad* surface_quad, + uint32_t embedder_client_namespace_id, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& added_clip_rect, const absl::optional<gfx::Rect>& dest_root_target_clip_rect, @@ -175,6 +179,7 @@ void EmitDefaultBackgroundColorQuad( const SurfaceDrawQuad* surface_quad, + uint32_t embedder_client_namespace_id, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& clip_rect, AggregatedRenderPass* dest_pass, @@ -184,6 +189,7 @@ const gfx::Rect& primary_rect, const gfx::Rect& fallback_rect, const SharedQuadState* primary_shared_quad_state, + uint32_t embedder_client_namespace_id, const gfx::Transform& target_transform, const absl::optional<gfx::Rect>& clip_rect, SkColor4f background_color,
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc index 5538812..76b4ce6 100644 --- a/components/viz/service/display/surface_aggregator_unittest.cc +++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -1448,6 +1448,113 @@ } } +// Verify that layer_ids are deduplicated in the final AggregatedFrame +// correctly. +TEST_F(SurfaceAggregatorValidSurfaceTest, LayerIds) { + TestSurfaceIdAllocator child_surface_id(child_sink_->frame_sink_id()); + + gfx::Rect child_surface_rect(20, 20); + { + CompositorFrame frame = + CompositorFrameBuilder() + .AddRenderPass( + RenderPassBuilder(child_surface_rect) + .AddSolidColorQuad(gfx::Rect(20, 20), SkColors::kRed) + .SetQuadLayerId(1u)) + .Build(); + + child_sink_->SubmitCompositorFrame(child_surface_id.local_surface_id(), + std::move(frame)); + } + + { + CompositorFrame frame = + CompositorFrameBuilder() + .AddRenderPass(RenderPassBuilder(kSurfaceSize) + .AddSurfaceQuad(child_surface_rect, + SurfaceRange(child_surface_id)) + .SetQuadLayerId(2) + .AddSolidColorQuad(gfx::Rect(kSurfaceSize), + SkColors::kBlack) + .SetQuadLayerId(3)) + .Build(); + root_sink_->SubmitCompositorFrame(root_surface_id_.local_surface_id(), + std::move(frame)); + } + + { + auto frame = AggregateFrame(root_surface_id_); + ASSERT_EQ(1u, frame.render_pass_list.size()); + auto* render_pass = frame.render_pass_list.back().get(); + + uint32_t root_surface_namespace = + aggregator_.GetLatestFrameData(root_surface_id_) + ->GetClientNamespaceId(); + uint32_t child_surface_namespace = + aggregator_.GetLatestFrameData(child_surface_id) + ->GetClientNamespaceId(); + + // The child surface is merged into the root surface so there is a single + // render pass with a solid color draw quad from both clients. Both will + // have client namespace ID + original layer ID as their final layer ID. + EXPECT_THAT(render_pass->quad_list, + ElementsAre(AllOf(IsSolidColorQuad(SkColors::kRed), + HasLayerNamespaceId(child_surface_namespace), + HasLayerId(1u)), + AllOf(IsSolidColorQuad(SkColors::kBlack), + HasLayerNamespaceId(root_surface_namespace), + HasLayerId(3u)))); + } + + // Redo the aggregation but don't allow merging child surface into the root + // render pass. + { + CompositorFrame frame = + CompositorFrameBuilder() + .AddRenderPass(RenderPassBuilder(kSurfaceSize) + .AddSurfaceQuad(child_surface_rect, + SurfaceRange(child_surface_id), + {.allow_merge = false}) + .SetQuadLayerId(2) + .AddSolidColorQuad(gfx::Rect(kSurfaceSize), + SkColors::kBlack) + .SetQuadLayerId(3)) + .Build(); + root_sink_->SubmitCompositorFrame(root_surface_id_.local_surface_id(), + std::move(frame)); + } + + { + auto frame = AggregateFrame(root_surface_id_); + ASSERT_EQ(2u, frame.render_pass_list.size()); + auto* child_pass = frame.render_pass_list.at(0).get(); + auto* root_pass = frame.render_pass_list.at(1).get(); + + uint32_t root_surface_namespace = + aggregator_.GetLatestFrameData(root_surface_id_) + ->GetClientNamespaceId(); + uint32_t child_surface_namespace = + aggregator_.GetLatestFrameData(child_surface_id) + ->GetClientNamespaceId(); + + EXPECT_THAT(child_pass->quad_list, + ElementsAre(AllOf(IsSolidColorQuad(SkColors::kRed), + HasLayerNamespaceId(child_surface_namespace), + HasLayerId(1u)))); + + // The AggregatedRenderPassDrawQuad is taking the place of the + // SurfaceDrawQuad so it should have the same client namespace as other + // quads from the root surface. + EXPECT_THAT(root_pass->quad_list, + ElementsAre(AllOf(IsAggregatedRenderPassQuad(), + HasLayerNamespaceId(root_surface_namespace), + HasLayerId(2u)), + AllOf(IsSolidColorQuad(SkColors::kBlack), + HasLayerNamespaceId(root_surface_namespace), + HasLayerId(3u)))); + } +} + // This test verifies that the appropriate transform will be applied to a // surface embedded by a parent SurfaceDrawQuad marked as // stretch_content_to_fill_bounds.
diff --git a/components/viz/test/compositor_frame_helpers.cc b/components/viz/test/compositor_frame_helpers.cc index b6539e6..1d2e6b2 100644 --- a/components/viz/test/compositor_frame_helpers.cc +++ b/components/viz/test/compositor_frame_helpers.cc
@@ -13,6 +13,7 @@ #include "components/viz/common/quads/compositor_render_pass.h" #include "components/viz/common/quads/compositor_render_pass_draw_quad.h" #include "components/viz/common/quads/shared_element_draw_quad.h" +#include "components/viz/common/quads/shared_quad_state.h" #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/quads/surface_draw_quad.h" #include "components/viz/common/quads/texture_draw_quad.h" @@ -275,6 +276,12 @@ return *this; } +RenderPassBuilder& RenderPassBuilder::SetQuadLayerId(uint32_t layer_id) { + auto* sqs = GetLastQuadSharedQuadState(); + sqs->layer_id = layer_id; + return *this; +} + SharedQuadState* RenderPassBuilder::AppendDefaultSharedQuadState( const gfx::Rect rect, const gfx::Rect visible_rect) {
diff --git a/components/viz/test/compositor_frame_helpers.h b/components/viz/test/compositor_frame_helpers.h index b7b80c4e..fea7f19 100644 --- a/components/viz/test/compositor_frame_helpers.h +++ b/components/viz/test/compositor_frame_helpers.h
@@ -165,6 +165,9 @@ RenderPassBuilder& SetMaskFilter(const gfx::MaskFilterInfo& mask_filter_info, bool is_fast_rounded_corner); + // Sets SharedQuadState::layer_id for the last quad. + RenderPassBuilder& SetQuadLayerId(uint32_t layer_id); + private: // Appends and returns a new SharedQuadState for quad. SharedQuadState* AppendDefaultSharedQuadState(const gfx::Rect rect,
diff --git a/components/viz/test/draw_quad_matchers.cc b/components/viz/test/draw_quad_matchers.cc index 1d4f25eb..f8a852b 100644 --- a/components/viz/test/draw_quad_matchers.cc +++ b/components/viz/test/draw_quad_matchers.cc
@@ -125,4 +125,16 @@ testing::Eq(opaque))); } +testing::Matcher<const DrawQuad*> HasLayerId(uint32_t layer_id) { + return HasSharedQuadState(testing::Field( + "layer_id", &SharedQuadState::layer_id, testing::Eq(layer_id))); +} + +testing::Matcher<const DrawQuad*> HasLayerNamespaceId( + uint32_t layer_namespace_id) { + return HasSharedQuadState(testing::Field("layer_namespace_id", + &SharedQuadState::layer_namespace_id, + testing::Eq(layer_namespace_id))); +} + } // namespace viz
diff --git a/components/viz/test/draw_quad_matchers.h b/components/viz/test/draw_quad_matchers.h index 6193afc..d50aedc2 100644 --- a/components/viz/test/draw_quad_matchers.h +++ b/components/viz/test/draw_quad_matchers.h
@@ -68,6 +68,13 @@ // Matches a DrawQuad with expected SharedQuadState::are_contents_opaque. testing::Matcher<const DrawQuad*> AreContentsOpaque(bool opaque); +// Matches a DrawQuad with expected SharedQuadState::layer_id. +testing::Matcher<const DrawQuad*> HasLayerId(uint32_t layer_id); + +// Matches a DrawQuad with expected SharedQuadState::layer_namespace_id. +testing::Matcher<const DrawQuad*> HasLayerNamespaceId( + uint32_t layer_namespace_id); + } // namespace viz #endif // COMPONENTS_VIZ_TEST_DRAW_QUAD_MATCHERS_H_
diff --git a/components/webxr/android/BUILD.gn b/components/webxr/android/BUILD.gn index d1c0434..e97e7593 100644 --- a/components/webxr/android/BUILD.gn +++ b/components/webxr/android/BUILD.gn
@@ -37,6 +37,13 @@ ] } + if (enable_cardboard) { + sources += [ + "cardboard_device_provider.cc", + "cardboard_device_provider.h", + ] + } + deps = [ ":android_utils", ":xr_jni_headers", @@ -55,6 +62,10 @@ deps += [ "//device/vr/android/arcore" ] } + if (enable_cardboard) { + deps += [ "//device/vr/android/cardboard:vr_cardboard" ] + } + libs = [ "android" ] } }
diff --git a/device/vr/android/cardboard/cardboard_device_provider.cc b/components/webxr/android/cardboard_device_provider.cc similarity index 69% rename from device/vr/android/cardboard/cardboard_device_provider.cc rename to components/webxr/android/cardboard_device_provider.cc index 62037bb..c108665d 100644 --- a/device/vr/android/cardboard/cardboard_device_provider.cc +++ b/components/webxr/android/cardboard_device_provider.cc
@@ -2,22 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "device/vr/android/cardboard/cardboard_device_provider.h" +#include "components/webxr/android/cardboard_device_provider.h" #include "device/vr/android/cardboard/cardboard_device.h" #include "device/vr/android/cardboard/cardboard_sdk_impl.h" -namespace device { +namespace webxr { CardboardDeviceProvider::CardboardDeviceProvider() = default; - CardboardDeviceProvider::~CardboardDeviceProvider() = default; -void CardboardDeviceProvider::Initialize(VRDeviceProviderClient* client) { +void CardboardDeviceProvider::Initialize( + device::VRDeviceProviderClient* client) { + CHECK(!initialized_); DVLOG(2) << __func__ << ": Cardboard is supported, creating device"; - cardboard_device_ = - std::make_unique<CardboardDevice>(std::make_unique<CardboardSdkImpl>()); + cardboard_device_ = std::make_unique<device::CardboardDevice>( + std::make_unique<device::CardboardSdkImpl>()); client->AddRuntime(cardboard_device_->GetId(), cardboard_device_->GetDeviceData(), @@ -30,4 +31,4 @@ return initialized_; } -} // namespace device +} // namespace webxr
diff --git a/device/vr/android/cardboard/cardboard_device_provider.h b/components/webxr/android/cardboard_device_provider.h similarity index 65% rename from device/vr/android/cardboard/cardboard_device_provider.h rename to components/webxr/android/cardboard_device_provider.h index 88c2319e..7c8a9582 100644 --- a/device/vr/android/cardboard/cardboard_device_provider.h +++ b/components/webxr/android/cardboard_device_provider.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef DEVICE_VR_ANDROID_CARDBOARD_CARDBOARD_DEVICE_PROVIDER_H_ -#define DEVICE_VR_ANDROID_CARDBOARD_CARDBOARD_DEVICE_PROVIDER_H_ +#ifndef COMPONENTS_WEBXR_ANDROID_CARDBOARD_DEVICE_PROVIDER_H_ +#define COMPONENTS_WEBXR_ANDROID_CARDBOARD_DEVICE_PROVIDER_H_ #include <memory> @@ -12,11 +12,12 @@ namespace device { class CardboardDevice; +} +namespace webxr { -class COMPONENT_EXPORT(VR_CARDBOARD) CardboardDeviceProvider - : public device::VRDeviceProvider { +class CardboardDeviceProvider : public device::VRDeviceProvider { public: - explicit CardboardDeviceProvider(); + CardboardDeviceProvider(); ~CardboardDeviceProvider() override; CardboardDeviceProvider(const CardboardDeviceProvider&) = delete; @@ -30,6 +31,6 @@ bool initialized_ = false; }; -} // namespace device +} // namespace webxr -#endif // DEVICE_VR_ANDROID_CARDBOARD_CARDBOARD_DEVICE_PROVIDER_H_ +#endif // COMPONENTS_WEBXR_ANDROID_CARDBOARD_DEVICE_PROVIDER_H_
diff --git a/components/webxr/android/java/src/org/chromium/components/webxr/ArOverlayDelegate.java b/components/webxr/android/java/src/org/chromium/components/webxr/ArOverlayDelegate.java index 6269134..fa9db20 100644 --- a/components/webxr/android/java/src/org/chromium/components/webxr/ArOverlayDelegate.java +++ b/components/webxr/android/java/src/org/chromium/components/webxr/ArOverlayDelegate.java
@@ -4,6 +4,7 @@ package org.chromium.components.webxr; +import android.content.res.Configuration; import android.graphics.PixelFormat; import android.view.MotionEvent; import android.view.SurfaceView; @@ -103,4 +104,9 @@ mArCompositorDelegate.dispatchTouchEvent(ev); } } + + @Override + public int getDesiredOrientation() { + return Configuration.ORIENTATION_UNDEFINED; + } }
diff --git a/components/webxr/android/java/src/org/chromium/components/webxr/XrImmersiveOverlay.java b/components/webxr/android/java/src/org/chromium/components/webxr/XrImmersiveOverlay.java index 7adf5901..6ca0770d 100644 --- a/components/webxr/android/java/src/org/chromium/components/webxr/XrImmersiveOverlay.java +++ b/components/webxr/android/java/src/org/chromium/components/webxr/XrImmersiveOverlay.java
@@ -7,6 +7,7 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.pm.ActivityInfo; +import android.content.res.Configuration; import android.os.Build; import android.view.MotionEvent; import android.view.SurfaceHolder; @@ -75,6 +76,15 @@ * otherwise been consumed by the XrImmersiveOverlay; e.g. to the compositor. */ void maybeForwardTouchEvent(MotionEvent ev); + + /** + * Returns the desired @{link android.content.res.Configuration} int representing the + * orientation that the OverlayDelegate desires the device to be in. Should be one of: + * Configuration.ORIENTATION_LANDSCAPE + * Configuration.ORIENTATION_PORTRAIT + * Configuration.ORIENTATION_UNDEFINED + */ + int getDesiredOrientation(); } private static final String TAG = "XrImmersiveOverlay"; @@ -448,7 +458,18 @@ if (mRestoreOrientation == null) { mRestoreOrientation = mActivity.getRequestedOrientation(); } - mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); + + int desiredOrientation = mOverlayDelegate.getDesiredOrientation(); + int currentOrientation = mActivity.getResources().getConfiguration().orientation; + + int requestOrientation = configurationToActivityInfoOrientation(desiredOrientation); + + // If we have a desired orientation and it does not equal the current orientation, then we + // will need to swap dimensions. + boolean swapScreenDimensions = desiredOrientation != Configuration.ORIENTATION_UNDEFINED + && desiredOrientation != currentOrientation; + + mActivity.setRequestedOrientation(requestOrientation); // While it would be preferable to wait until the surface is at the desired fullscreen // resolution, i.e. via mActivity.getFullscreenManager().getPersistentFullscreenMode(), that @@ -457,8 +478,10 @@ // after the session starts, but the session doesn't start until we report the drawing // surface being ready (including a configured size), so we use the reported size of the // display assuming that's what the fullscreen mode will use. - int screenWidth = display.getDisplayWidth(); - int screenHeight = display.getDisplayHeight(); + int screenWidth = + !swapScreenDimensions ? display.getDisplayWidth() : display.getDisplayHeight(); + int screenHeight = + !swapScreenDimensions ? display.getDisplayHeight() : display.getDisplayWidth(); if (width < screenWidth || height < screenHeight) { if (DEBUG_LOGS) { @@ -515,4 +538,29 @@ if (mRestoreOrientation != null) mActivity.setRequestedOrientation(mRestoreOrientation); mRestoreOrientation = null; } + + /** + * Translates the provided int, which is expected to be of the result of + * @{link Delegate.getDesiredOrientation} and thus one of: + * Configuration.ORIENTATION_UNDEFINED, + * Configuration.ORIENTATION_LANDSCAPE, + * Configuration.ORIENTATION_PORTRAIT + * and translates it to a corresponding "ActivityInfo" value that can then be passed on to + * setRequestedOrientation. + */ + private int configurationToActivityInfoOrientation(int configurationOrientation) { + switch (configurationOrientation) { + case Configuration.ORIENTATION_UNDEFINED: + return ActivityInfo.SCREEN_ORIENTATION_LOCKED; + case Configuration.ORIENTATION_LANDSCAPE: + return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + case Configuration.ORIENTATION_PORTRAIT: + return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; + default: + Log.e(TAG, + "Unexpected configurationOrientation: " + configurationOrientation + + " using default of 'Locked'."); + return ActivityInfo.SCREEN_ORIENTATION_LOCKED; + } + } }
diff --git a/content/browser/accessibility/browser_accessibility_android.cc b/content/browser/accessibility/browser_accessibility_android.cc index 96b0ed7..89c726da 100644 --- a/content/browser/accessibility/browser_accessibility_android.cc +++ b/content/browser/accessibility/browser_accessibility_android.cc
@@ -533,11 +533,8 @@ } bool BrowserAccessibilityAndroid::IsLeaf() const { - if (base::FeatureList::IsEnabled( - features::kOptimizeAccessibilityUiThreadWork)) { - if (g_leaf_map.Get().find(this) != g_leaf_map.Get().end()) { - return g_leaf_map.Get()[this]; - } + if (g_leaf_map.Get().find(this) != g_leaf_map.Get().end()) { + return g_leaf_map.Get()[this]; } if (BrowserAccessibility::IsLeaf()) { @@ -744,9 +741,7 @@ for (auto it = InternalChildrenBegin(); it != InternalChildrenEnd(); ++it) { text += static_cast<BrowserAccessibilityAndroid*>(it.get()) ->GetSubstringTextContentUTF16(predicate); - if (base::FeatureList::IsEnabled( - features::kOptimizeAccessibilityUiThreadWork) && - predicate && predicate.value().Run(text)) { + if (predicate && predicate.value().Run(text)) { break; } }
diff --git a/content/browser/attribution_reporting/attribution_host_unittest.cc b/content/browser/attribution_reporting/attribution_host_unittest.cc index 67c189255..d17df8f 100644 --- a/content/browser/attribution_reporting/attribution_host_unittest.cc +++ b/content/browser/attribution_reporting/attribution_host_unittest.cc
@@ -681,6 +681,7 @@ {blink::OriginWithPossibleWildcards( url::Origin::Create(GURL(kAllowedOriginUrl)), /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false)}); simulator->Commit(); fenced_frame = simulator->GetFinalRenderFrameHost(); @@ -713,10 +714,8 @@ simulator1->SetPermissionsPolicyHeader( {blink::ParsedPermissionsPolicyDeclaration( blink::mojom::PermissionsPolicyFeature::kAttributionReporting, - /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards( - url::Origin::Create(GURL(kAllowedOriginUrl)), - /*has_subdomain_wildcard=*/false)}, + /*allowed_origins=*/{}, + /*self_if_matches*/ url::Origin::Create(GURL(kAllowedOriginUrl)), /*matches_all_origins=*/false, /*matches_opaque_src=*/false)}); simulator1->Commit();
diff --git a/content/browser/attribution_reporting/attributions_browsertest.cc b/content/browser/attribution_reporting/attributions_browsertest.cc index 75c5d3f..39184606 100644 --- a/content/browser/attribution_reporting/attributions_browsertest.cc +++ b/content/browser/attribution_reporting/attributions_browsertest.cc
@@ -1691,7 +1691,6 @@ scoped_refptr<FencedFrameReporter> fenced_frame_reporter) { static constexpr char kAddFencedFrameScript[] = R"({ var f = document.createElement('fencedframe'); - f.mode = 'opaque-ads'; document.body.appendChild(f); })"; EXPECT_TRUE(ExecJs(root, kAddFencedFrameScript));
diff --git a/content/browser/browsing_topics/browsing_topics_url_loader_service_unittest.cc b/content/browser/browsing_topics/browsing_topics_url_loader_service_unittest.cc index e8372bf3..4c5f668b 100644 --- a/content/browser/browsing_topics/browsing_topics_url_loader_service_unittest.cc +++ b/content/browser/browsing_topics/browsing_topics_url_loader_service_unittest.cc
@@ -172,6 +172,7 @@ blink::OriginWithPossibleWildcards( url::Origin::Create(GURL("https://foo3.com")), /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false);
diff --git a/content/browser/direct_sockets/direct_sockets_test_utils.cc b/content/browser/direct_sockets/direct_sockets_test_utils.cc index 4835087..2764d99 100644 --- a/content/browser/direct_sockets/direct_sockets_test_utils.cc +++ b/content/browser/direct_sockets/direct_sockets_test_utils.cc
@@ -178,6 +178,7 @@ /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(app_origin, /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false); out.push_back(decl); return out;
diff --git a/content/browser/fenced_frame/fenced_frame_browsertest.cc b/content/browser/fenced_frame/fenced_frame_browsertest.cc index 82d5620..ebbd36a 100644 --- a/content/browser/fenced_frame/fenced_frame_browsertest.cc +++ b/content/browser/fenced_frame/fenced_frame_browsertest.cc
@@ -2195,7 +2195,6 @@ { EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); } EXPECT_EQ(1U, root->child_count()); @@ -2292,7 +2291,6 @@ EXPECT_TRUE(ExecJs(root, "var f1 = document.createElement('fencedframe');" - "f1.mode = 'opaque-ads';" "document.body.appendChild(f1);")); EXPECT_EQ(1U, root->child_count()); @@ -2319,7 +2317,6 @@ EXPECT_TRUE(ExecJs(fenced_frame_root_node1, "var f2 = document.createElement('fencedframe');" - "f2.mode = 'opaque-ads';" "document.body.appendChild(f2);")); EXPECT_EQ(1U, fenced_frame_root_node1->child_count()); @@ -2357,12 +2354,10 @@ { EXPECT_TRUE(ExecJs(root, "var f1 = document.createElement('fencedframe');" - "f1.mode = 'opaque-ads';" "document.body.appendChild(f1);")); EXPECT_TRUE(ExecJs(root, "var f2 = document.createElement('fencedframe');" - "f2.mode = 'opaque-ads';" "document.body.appendChild(f2);")); } @@ -2421,7 +2416,6 @@ { EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); } EXPECT_EQ(1U, root->child_count()); @@ -2500,7 +2494,6 @@ { EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); } EXPECT_EQ(1U, root->child_count()); @@ -2570,7 +2563,6 @@ { EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); } EXPECT_EQ(1U, root->child_count()); @@ -2648,7 +2640,6 @@ // Test the fenced frame. EXPECT_TRUE(ExecJs(root_rfh, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root_rfh->child_count()); @@ -2731,7 +2722,6 @@ // Add and navigate a fenced frame. EXPECT_TRUE(ExecJs(root_rfh, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root_rfh->child_count()); FrameTreeNode* fenced_frame_root_node = @@ -3074,7 +3064,6 @@ { EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); } EXPECT_EQ(1U, root->child_count()); @@ -3230,7 +3219,6 @@ // Create a fenced frame. EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -3284,7 +3272,6 @@ // Create a fenced frame. EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -4033,7 +4020,6 @@ { EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); } EXPECT_EQ(1U, root->child_count()); @@ -4090,7 +4076,6 @@ EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -4421,7 +4406,6 @@ nodeA, JsReplace( "var nested_fenced_frame = document.createElement('fencedframe');" - "nested_fenced_frame.mode = 'opaque-ads';" "nested_fenced_frame.width = $1;" "nested_fenced_frame.height = $2;" "document.body.appendChild(nested_fenced_frame);", @@ -4761,7 +4745,6 @@ EXPECT_TRUE( ExecJs(root, "var fenced_frame = document.createElement('fencedframe');" - "fenced_frame.mode = 'opaque-ads';" "document.body.appendChild(fenced_frame);")); EXPECT_EQ(1U, root->child_count()); FrameTreeNode* fenced_frame_root_node = @@ -4965,7 +4948,6 @@ .root(); EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'default';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -5406,7 +5388,6 @@ .root(); EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -5538,7 +5519,6 @@ .root(); EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -5713,7 +5693,6 @@ .root(); EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -5798,7 +5777,6 @@ .root(); EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -6220,7 +6198,6 @@ EXPECT_TRUE( ExecJs(root, JsReplace("var ad_frame = document.createElement($1);" - "ad_frame.mode = 'opaque-ads';" "document.body.appendChild(ad_frame);", GetParam())));
diff --git a/content/browser/geolocation/geolocation_service_impl_unittest.cc b/content/browser/geolocation/geolocation_service_impl_unittest.cc index 731afae..2f23dd0 100644 --- a/content/browser/geolocation/geolocation_service_impl_unittest.cc +++ b/content/browser/geolocation/geolocation_service_impl_unittest.cc
@@ -109,7 +109,9 @@ std::vector{blink::OriginWithPossibleWildcards( url::Origin::Create(kEmbeddedUrl), /*has_subdomain_wildcard=*/false)}, - false, false}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}); } RenderFrameHost* embedded_rfh = RenderFrameHostTester::For(main_rfh())
diff --git a/content/browser/interest_group/ad_auction_service_impl_unittest.cc b/content/browser/interest_group/ad_auction_service_impl_unittest.cc index e422593..1cf29ef 100644 --- a/content/browser/interest_group/ad_auction_service_impl_unittest.cc +++ b/content/browser/interest_group/ad_auction_service_impl_unittest.cc
@@ -6453,6 +6453,7 @@ std::vector<blink::OriginWithPossibleWildcards>{ blink::OriginWithPossibleWildcards(kOriginA, /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false); simulator->SetPermissionsPolicyHeader(std::move(policy)); @@ -6664,6 +6665,7 @@ blink::OriginWithPossibleWildcards( kOriginA, /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false); simulator->SetPermissionsPolicyHeader(std::move(policy)); @@ -6694,6 +6696,7 @@ blink::OriginWithPossibleWildcards( kOriginC, /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false); simulator->SetPermissionsPolicyHeader(std::move(policy)); @@ -6755,6 +6758,7 @@ blink::OriginWithPossibleWildcards( kOriginA, /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false); simulator->SetPermissionsPolicyHeader(std::move(policy)); @@ -6785,6 +6789,7 @@ blink::OriginWithPossibleWildcards( kOriginC, /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false); simulator->SetPermissionsPolicyHeader(std::move(policy));
diff --git a/content/browser/interest_group/interest_group_browsertest.cc b/content/browser/interest_group/interest_group_browsertest.cc index f7ad5c01..cb6c452 100644 --- a/content/browser/interest_group/interest_group_browsertest.cc +++ b/content/browser/interest_group/interest_group_browsertest.cc
@@ -8180,7 +8180,6 @@ EXPECT_TRUE(ExecJs(shell(), "document.querySelector('fencedframe').remove();" "const ff = document.createElement('fencedframe');" - "ff.mode = 'opaque-ads';" "document.body.appendChild(ff);")); } ClearReceivedRequests();
diff --git a/content/browser/media/media_devices_permission_checker_unittest.cc b/content/browser/media/media_devices_permission_checker_unittest.cc index 389ed7782..287615e 100644 --- a/content/browser/media/media_devices_permission_checker_unittest.cc +++ b/content/browser/media/media_devices_permission_checker_unittest.cc
@@ -57,8 +57,10 @@ std::vector<blink::OriginWithPossibleWildcards> allowlist; if (enabled) allowlist.emplace_back(origin_, /*has_subdomain_wildcard=*/false); - navigation->SetPermissionsPolicyHeader( - {{feature, allowlist, false, false}}); + navigation->SetPermissionsPolicyHeader({{feature, allowlist, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}); navigation->Commit(); }
diff --git a/content/browser/preloading/prefetch/prefetch_streaming_url_loader.cc b/content/browser/preloading/prefetch/prefetch_streaming_url_loader.cc index bbcc4d76..4613f37 100644 --- a/content/browser/preloading/prefetch/prefetch_streaming_url_loader.cc +++ b/content/browser/preloading/prefetch/prefetch_streaming_url_loader.cc
@@ -340,6 +340,9 @@ DCHECK(!serving_url_loader_receiver_.is_bound()); DCHECK(!self || self.get() == this); + // Once the prefetch is served, stop the timeout timer. + timeout_timer_.AbandonAndStop(); + status_ = completion_status_.has_value() ? PrefetchStreamingURLLoaderStatus::kSuccessfulServedAfterCompletion
diff --git a/content/browser/preloading/prefetch/prefetch_streaming_url_loader_unittest.cc b/content/browser/preloading/prefetch/prefetch_streaming_url_loader_unittest.cc index 0f95427..e04e6fb 100644 --- a/content/browser/preloading/prefetch/prefetch_streaming_url_loader_unittest.cc +++ b/content/browser/preloading/prefetch/prefetch_streaming_url_loader_unittest.cc
@@ -1268,6 +1268,109 @@ PrefetchStreamingURLLoaderStatus::kFailedNetError, 1); } +TEST_F(PrefetchStreamingURLLoaderTest, StopTimeoutTimerAfterBeingServed) { + base::HistogramTester histogram_tester; + const GURL kTestUrl = GURL("https://example.com"); + const std::string kBodyContent = "example body"; + + std::unique_ptr<network::ResourceRequest> prefetch_request = + std::make_unique<network::ResourceRequest>(); + prefetch_request->url = kTestUrl; + prefetch_request->method = "GET"; + + base::RunLoop on_response_received_loop; + base::RunLoop on_response_complete_loop; + + // Create the |PrefetchStreamingURLLoader| that is being tested. + std::unique_ptr<PrefetchStreamingURLLoader> streaming_loader = + std::make_unique<PrefetchStreamingURLLoader>( + test_url_loader_factory(), std::move(prefetch_request), + TRAFFIC_ANNOTATION_FOR_TESTS, /*timeout_duration=*/base::Seconds(1), + base::BindOnce( + [](base::RunLoop* on_response_received_loop, + network::mojom::URLResponseHead* head) { + on_response_received_loop->Quit(); + return PrefetchStreamingURLLoaderStatus:: + kHeadReceivedWaitingOnBody; + }, + &on_response_received_loop), + base::BindOnce( + [](base::RunLoop* on_response_complete_loop, + const network::URLLoaderCompletionStatus& completion_status) { + EXPECT_EQ(completion_status.error_code, net::OK); + on_response_complete_loop->Quit(); + }, + &on_response_complete_loop), + base::BindRepeating( + [](const net::RedirectInfo& redirect_info, + const network::mojom::URLResponseHead& response_head) { + NOTREACHED(); + return PrefetchStreamingURLLoaderStatus::kFollowRedirect; + })); + + // Simulates receiving the head of the prefetch response. + test_url_loader_factory()->SimulateReceiveHead(net::HTTP_OK, + kBodyContent.size()); + on_response_received_loop.Run(); + + EXPECT_TRUE(streaming_loader->Servable(base::TimeDelta::Max())); + + // Simulate serving the prefetch. This should stop the timeout timer. + base::WeakPtr<PrefetchStreamingURLLoader> weak_streaming_loader = + streaming_loader->GetWeakPtr(); + PrefetchStreamingURLLoader::RequestHandler request_handler = + weak_streaming_loader->ServingFinalResponseHandler( + std::move(streaming_loader)); + + std::unique_ptr<TestURLLoaderClient> serving_url_loader_client = + std::make_unique<TestURLLoaderClient>(); + + network::ResourceRequest serving_request; + serving_request.url = kTestUrl; + serving_request.method = "GET"; + + std::move(request_handler) + .Run(serving_request, + serving_url_loader_client->BindURLloaderAndGetReceiver(), + serving_url_loader_client->BindURLLoaderClientAndGetRemote()); + + // Since the prefetch has been served, the timeout trigger should not be + // triggered. + task_environment()->FastForwardBy(base::Seconds(10)); + + // Simulate receiving the body of the response. + test_url_loader_factory()->SimulateReceiveData(kBodyContent); + test_url_loader_factory()->SimulateResponseComplete(net::OK); + on_response_complete_loop.Run(); + + EXPECT_TRUE(weak_streaming_loader->Servable(base::TimeDelta::Max())); + + test_url_loader_factory()->DisconnectMojoPipes(); + + // Wait for the data to be drained from the body pipe. + task_environment()->RunUntilIdle(); + + EXPECT_TRUE(serving_url_loader_client->body_finished()); + EXPECT_EQ(serving_url_loader_client->body_content(), kBodyContent); + EXPECT_EQ(serving_url_loader_client->total_bytes_read(), kBodyContent.size()); + + EXPECT_TRUE(serving_url_loader_client->completion_status()); + EXPECT_EQ(serving_url_loader_client->completion_status()->error_code, + net::OK); + + serving_url_loader_client->DisconnectMojoPipes(); + task_environment()->RunUntilIdle(); + + // Once the streaming URL loader serves is finished (all prefetched data + // received and served) and all mojo pipes are disconnected, it should delete + // itself. + EXPECT_FALSE(weak_streaming_loader); + + histogram_tester.ExpectUniqueSample( + "PrefetchProxy.Prefetch.StreamingURLLoaderFinalStatus", + PrefetchStreamingURLLoaderStatus::kSuccessfulServedBeforeCompletion, 1); +} + TEST_F(PrefetchStreamingURLLoaderTest, StaleResponse) { base::HistogramTester histogram_tester; const GURL kTestUrl = GURL("https://example.com");
diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc index 8be1987..8d9f9f25 100644 --- a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc +++ b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
@@ -555,7 +555,10 @@ blink::mojom::PermissionsPolicyFeature feature) { auto navigation = NavigationSimulator::CreateRendererInitiated( main_rfh()->GetLastCommittedURL(), main_rfh()); - navigation->SetPermissionsPolicyHeader({{feature, {}, false, false}}); + navigation->SetPermissionsPolicyHeader( + {{feature, /*allowed_origins=*/{}, /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}); navigation->Commit(); }
diff --git a/content/browser/serial/serial_unittest.cc b/content/browser/serial/serial_unittest.cc index 7b1643d..3633599c 100644 --- a/content/browser/serial/serial_unittest.cc +++ b/content/browser/serial/serial_unittest.cc
@@ -491,9 +491,8 @@ ->AppendChildWithPolicy( "embedded_frame", {{blink::mojom::PermissionsPolicyFeature::kSerial, - std::vector{blink::OriginWithPossibleWildcards( - url::Origin::Create(kEmbeddedUrl), - /*has_subdomain_wildcard=*/false)}, + /*allowed_origins=*/{}, + /*self_if_matches=*/url::Origin::Create(kEmbeddedUrl), /*matches_all_origins=*/false, /*matches_opaque_src=*/true}}); embedded_rfh = NavigationSimulator::NavigateAndCommitFromDocument( kEmbeddedUrl, embedded_rfh);
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc index e998d341..5cd0a30 100644 --- a/content/browser/service_worker/service_worker_context_core.cc +++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -565,6 +565,15 @@ bool is_immediate, UnregistrationCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + + BrowserContext* browser_context = wrapper_->browser_context(); + DCHECK(browser_context); + if (!GetContentClient()->browser()->MayDeleteServiceWorkerRegistration( + scope, browser_context)) { + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorDisallowed); + return; + } + job_coordinator_->Unregister( scope, key, is_immediate, base::BindOnce(&ServiceWorkerContextCore::UnregistrationComplete, @@ -613,7 +622,19 @@ return; } - int* expected_calls = new int(2 * registrations.size()); + // Ignore any registrations we are not permitted to delete. + std::vector<scoped_refptr<ServiceWorkerRegistration>> filtered_registrations; + ContentBrowserClient* browser_client = GetContentClient()->browser(); + BrowserContext* browser_context = wrapper_->browser_context(); + DCHECK(browser_context); + for (auto registration : registrations) { + if (browser_client->MayDeleteServiceWorkerRegistration( + registration->scope(), browser_context)) { + filtered_registrations.push_back(std::move(registration)); + } + } + + int* expected_calls = new int(2 * filtered_registrations.size()); auto* listeners = new std::vector<std::unique_ptr<RegistrationDeletionListener>>(); @@ -624,7 +645,7 @@ base::BindRepeating(SuccessReportingCallback, base::Owned(expected_calls), base::Owned(listeners), base::OwnedRef(std::move(callback))); - for (const auto& registration : registrations) { + for (const auto& registration : filtered_registrations) { DCHECK(registration); if (*expected_calls != -1) { if (!registration->is_deleted()) {
diff --git a/content/browser/shared_storage/shared_storage_browsertest.cc b/content/browser/shared_storage/shared_storage_browsertest.cc index ab582d7..bc898ee3 100644 --- a/content/browser/shared_storage/shared_storage_browsertest.cc +++ b/content/browser/shared_storage/shared_storage_browsertest.cc
@@ -4853,7 +4853,6 @@ EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -4956,7 +4955,6 @@ EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -5160,7 +5158,6 @@ EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(2U, root->child_count()); @@ -5328,7 +5325,6 @@ EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count()); @@ -5448,7 +5444,6 @@ EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(1U, root->child_count());
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index 19726384..0fa82f5e 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -371,10 +371,14 @@ CreateParsedPermissionsPolicyDeclaration( blink::mojom::PermissionsPolicyFeature feature, const std::vector<GURL>& origins, - bool match_all_origins = false) { + bool match_all_origins = false, + const absl::optional<GURL> self_if_matches = absl::nullopt) { blink::ParsedPermissionsPolicyDeclaration declaration; declaration.feature = feature; + if (self_if_matches.has_value()) { + declaration.self_if_matches = url::Origin::Create(*self_if_matches); + } declaration.matches_all_origins = match_all_origins; declaration.matches_opaque_src = match_all_origins; @@ -391,15 +395,22 @@ blink::ParsedPermissionsPolicy CreateParsedPermissionsPolicy( const std::vector<blink::mojom::PermissionsPolicyFeature>& features, const std::vector<GURL>& origins, - bool match_all_origins = false) { + bool match_all_origins = false, + const absl::optional<GURL> self_if_matches = absl::nullopt) { blink::ParsedPermissionsPolicy result; result.reserve(features.size()); for (const auto& feature : features) result.push_back(CreateParsedPermissionsPolicyDeclaration( - feature, origins, match_all_origins)); + feature, origins, match_all_origins, self_if_matches)); return result; } +blink::ParsedPermissionsPolicy CreateParsedPermissionsPolicyMatchesSelf( + const std::vector<blink::mojom::PermissionsPolicyFeature>& features, + const GURL& self_if_matches) { + return CreateParsedPermissionsPolicy(features, {}, false, self_if_matches); +} + blink::ParsedPermissionsPolicy CreateParsedPermissionsPolicyMatchesAll( const std::vector<blink::mojom::PermissionsPolicyFeature>& features) { return CreateParsedPermissionsPolicy(features, {}, true); @@ -6800,9 +6811,9 @@ EXPECT_TRUE(NavigateToURL(shell(), url)); FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); - EXPECT_EQ(CreateParsedPermissionsPolicy( + EXPECT_EQ(CreateParsedPermissionsPolicyMatchesSelf( {blink::mojom::PermissionsPolicyFeature::kGeolocation}, - {url.DeprecatedGetOriginAsURL()}), + url.DeprecatedGetOriginAsURL()), root->current_replication_state().permissions_policy_header); } @@ -6817,10 +6828,10 @@ EXPECT_TRUE(NavigateToURL(shell(), start_url)); FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); - EXPECT_EQ(CreateParsedPermissionsPolicy( + EXPECT_EQ(CreateParsedPermissionsPolicyMatchesSelf( {blink::mojom::PermissionsPolicyFeature::kGeolocation, blink::mojom::PermissionsPolicyFeature::kPayment}, - {start_url.DeprecatedGetOriginAsURL()}), + start_url.DeprecatedGetOriginAsURL()), root->current_replication_state().permissions_policy_header); // When the main frame navigates to a page with a new policy, it should @@ -6849,10 +6860,10 @@ EXPECT_TRUE(NavigateToURL(shell(), start_url)); FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); - EXPECT_EQ(CreateParsedPermissionsPolicy( + EXPECT_EQ(CreateParsedPermissionsPolicyMatchesSelf( {blink::mojom::PermissionsPolicyFeature::kGeolocation, blink::mojom::PermissionsPolicyFeature::kPayment}, - {start_url.DeprecatedGetOriginAsURL()}), + start_url.DeprecatedGetOriginAsURL()), root->current_replication_state().permissions_policy_header); // When the main frame navigates to a page with a new policy, it should @@ -6883,18 +6894,18 @@ EXPECT_TRUE(NavigateToURL(shell(), main_url)); FrameTreeNode* root = web_contents()->GetPrimaryFrameTree().root(); - EXPECT_EQ( - CreateParsedPermissionsPolicy( - {blink::mojom::PermissionsPolicyFeature::kGeolocation, - blink::mojom::PermissionsPolicyFeature::kPayment}, - {main_url.DeprecatedGetOriginAsURL(), GURL("http://example.com/")}), - root->current_replication_state().permissions_policy_header); + EXPECT_EQ(CreateParsedPermissionsPolicy( + {blink::mojom::PermissionsPolicyFeature::kGeolocation, + blink::mojom::PermissionsPolicyFeature::kPayment}, + {GURL("http://example.com/")}, /*match_all_origins=*/false, + main_url.DeprecatedGetOriginAsURL()), + root->current_replication_state().permissions_policy_header); EXPECT_EQ(1UL, root->child_count()); EXPECT_EQ( - CreateParsedPermissionsPolicy( + CreateParsedPermissionsPolicyMatchesSelf( {blink::mojom::PermissionsPolicyFeature::kGeolocation, blink::mojom::PermissionsPolicyFeature::kPayment}, - {main_url.DeprecatedGetOriginAsURL()}), + main_url.DeprecatedGetOriginAsURL()), root->child_at(0)->current_replication_state().permissions_policy_header); // Navigate the iframe cross-site.
diff --git a/content/browser/smart_card/smart_card_browsertest.cc b/content/browser/smart_card/smart_card_browsertest.cc index 31dc608..7f8f2b4 100644 --- a/content/browser/smart_card/smart_card_browsertest.cc +++ b/content/browser/smart_card/smart_card_browsertest.cc
@@ -172,10 +172,9 @@ blink::ParsedPermissionsPolicy out; blink::ParsedPermissionsPolicyDeclaration decl( blink::mojom::PermissionsPolicyFeature::kSmartCard, - /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(app_origin, - /*has_subdomain_wildcard=*/false)}, - /*matches_all_origins=*/false, /*matches_opaque_src=*/false); + /*allowed_origins=*/{}, + /*self_if_matches=*/app_origin, /*matches_all_origins=*/false, + /*matches_opaque_src=*/false); out.push_back(decl); return out; }
diff --git a/content/browser/usb/web_usb_service_impl_unittest.cc b/content/browser/usb/web_usb_service_impl_unittest.cc index 24c2e16..6ab4a98 100644 --- a/content/browser/usb/web_usb_service_impl_unittest.cc +++ b/content/browser/usb/web_usb_service_impl_unittest.cc
@@ -436,9 +436,8 @@ ->AppendChildWithPolicy( "embedded_frame", {{blink::mojom::PermissionsPolicyFeature::kUsb, - std::vector{blink::OriginWithPossibleWildcards( - url::Origin::Create(kEmbeddedUrl), - /*has_subdomain_wildcard=*/false)}, + /*allowed_origins=*/{}, + /*self_if_matches=*/url::Origin::Create(kEmbeddedUrl), /*matches_all_origins=*/false, /*matches_opaque_src=*/true}}); embedded_rfh = NavigationSimulator::NavigateAndCommitFromDocument( kEmbeddedUrl, embedded_rfh);
diff --git a/content/browser/webauth/webauth_request_security_checker_unittest.cc b/content/browser/webauth/webauth_request_security_checker_unittest.cc index a8f6d1d..fb5588e 100644 --- a/content/browser/webauth/webauth_request_security_checker_unittest.cc +++ b/content/browser/webauth/webauth_request_security_checker_unittest.cc
@@ -27,7 +27,8 @@ blink::ParsedPermissionsPolicy CreatePolicyToAllowWebAuthn() { return {blink::ParsedPermissionsPolicyDeclaration( blink::mojom::PermissionsPolicyFeature::kPublicKeyCredentialsGet, - /*values=*/{}, /*matches_all_origins=*/true, + /*allowed_origins=*/{}, /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, /*matches_opaque_src=*/false)}; } @@ -36,13 +37,15 @@ blink::ParsedPermissionsPolicy CreatePolicyToDenyWebAuthn() { return {blink::ParsedPermissionsPolicyDeclaration( blink::mojom::PermissionsPolicyFeature::kPublicKeyCredentialsGet, - /*values=*/{}, /*matches_all_origins=*/false, + /*allowed_origins=*/{}, /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, /*matches_opaque_src=*/false)}; } blink::ParsedPermissionsPolicy CreatePolicyToAllowWebPayments() { return {blink::ParsedPermissionsPolicyDeclaration( - blink::mojom::PermissionsPolicyFeature::kPayment, /*values=*/{}, + blink::mojom::PermissionsPolicyFeature::kPayment, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/true, /*matches_opaque_src=*/false)}; }
diff --git a/content/common/profiling_utils.cc b/content/common/profiling_utils.cc index a1037663..279ab85 100644 --- a/content/common/profiling_utils.cc +++ b/content/common/profiling_utils.cc
@@ -23,6 +23,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_restrictions.h" #include "build/build_config.h" +#include "content/public/common/content_switches.h" namespace content { @@ -40,7 +41,15 @@ #if BUILDFLAG(IS_ANDROID) base::PathService::Get(base::DIR_TEMP, &path); path = path.Append("pgo_profiles/"); -#else // !BUILDFLAG(IS_ANDROID) + // Lacros is similar to Android that it's running on a device that is not + // the host machine and environment variables aren't well supported. + // But Lacros also need to pass in the path so it is the same path as + // isolate test output folder on bots. +#elif BUILDFLAG(IS_CHROMEOS_LACROS) + path = base::CommandLine::ForCurrentProcess() + ->GetSwitchValuePath(switches::kLLVMProfileFile) + .DirName(); +#else std::string prof_template; std::unique_ptr<base::Environment> env(base::Environment::Create()); if (env->GetVar("LLVM_PROFILE_FILE", &prof_template)) {
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 3fd3620..cd77eef 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -397,6 +397,12 @@ return AllowServiceWorkerResult::Yes(); } +bool ContentBrowserClient::MayDeleteServiceWorkerRegistration( + const GURL& scope, + BrowserContext* browser_context) { + return true; +} + void ContentBrowserClient::UpdateEnabledBlinkRuntimeFeaturesInIsolatedWorker( BrowserContext* context, const GURL& script_url,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index e7b210e8..5500a0c 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -725,6 +725,14 @@ const GURL& script_url, BrowserContext* context); + // Returns true if the service worker associated with the given `scope` may be + // deleted. This can return false if the service worker is tied to another + // service that fundamentally should not be allowed to be removed (today, this + // is limited to extensions). + virtual bool MayDeleteServiceWorkerRegistration( + const GURL& scope, + BrowserContext* browser_context); + // Allows the embedder to enable process-wide blink features before starting a // service worker. This is similar to // `blink.mojom.CommitNavigationParams.force_enabled_origin_trials` but for
diff --git a/content/public/browser/trust_token_access_details.cc b/content/public/browser/trust_token_access_details.cc index e8995b7..8b975fc 100644 --- a/content/public/browser/trust_token_access_details.cc +++ b/content/public/browser/trust_token_access_details.cc
@@ -4,6 +4,8 @@ #include "content/public/browser/trust_token_access_details.h" +#include "services/network/public/mojom/trust_tokens.mojom.h" + namespace content { TrustTokenAccessDetails::TrustTokenAccessDetails() = default;
diff --git a/content/public/browser/trust_token_access_details.h b/content/public/browser/trust_token_access_details.h index bc4a0062..1d0efb303 100644 --- a/content/public/browser/trust_token_access_details.h +++ b/content/public/browser/trust_token_access_details.h
@@ -7,6 +7,8 @@ #include "content/common/content_export.h" #include "services/network/public/mojom/trust_token_access_observer.mojom.h" +#include "services/network/public/mojom/trust_tokens.mojom-forward.h" +#include "third_party/abseil-cpp/absl/types/optional.h" #include "url/origin.h" namespace content {
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 9f352c2..522d148 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -1008,6 +1008,10 @@ // Linux speech service. Because it's buggy, the user must explicitly // enable it so that visiting a random webpage can't cause instability. const char kEnableSpeechDispatcher[] = "enable-speech-dispatcher"; + +// For lacros, we do not use environment variable to pass values. Instead we +// use a command line flag to pass the path to the device. +const char kLLVMProfileFile[] = "llvm-profile-file"; #endif #if BUILDFLAG(IS_WIN)
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index a8e677a..ea42089 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -270,6 +270,7 @@ // of lacros-chrome is complete. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS) CONTENT_EXPORT extern const char kEnableSpeechDispatcher[]; +CONTENT_EXPORT extern const char kLLVMProfileFile[]; #endif #if BUILDFLAG(IS_WIN)
diff --git a/content/public/test/shared_storage_test_utils.cc b/content/public/test/shared_storage_test_utils.cc index 2d34c4ef..fb17719 100644 --- a/content/public/test/shared_storage_test_utils.cc +++ b/content/public/test/shared_storage_test_utils.cc
@@ -70,7 +70,6 @@ EXPECT_TRUE(ExecJs(root, "var f = document.createElement('fencedframe');" - "f.mode = 'opaque-ads';" "document.body.appendChild(f);")); EXPECT_EQ(initial_child_count + 1, root_node->child_count());
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index f56c616..e3f3e84 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc
@@ -831,6 +831,7 @@ blink::mojom::PermissionsPolicyFeature::kDirectSockets, {blink::OriginWithPossibleWildcards(app_origin, /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false); return {{decl}}; }
diff --git a/content/test/data/fenced_frames/basic_fenced_frame_src_navigate_on_click.html b/content/test/data/fenced_frames/basic_fenced_frame_src_navigate_on_click.html index 3f67d67..49ebcbeb 100644 --- a/content/test/data/fenced_frames/basic_fenced_frame_src_navigate_on_click.html +++ b/content/test/data/fenced_frames/basic_fenced_frame_src_navigate_on_click.html
@@ -4,7 +4,7 @@ <div> <button onclick="navigateFrames();">Navigate</button> </div> - <fencedframe mode=opaque-ads id="frame1"></fencedframe> + <fencedframe id="frame1"></fencedframe> <script> function navigateFrames() {
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index 6cb2d930..cbb0a63 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -322,6 +322,15 @@ crbug.com/1417485 [ android android-nexus-5x passthrough ] conformance/glsl/samplers/glsl-function-texture2dprojlod.html [ Failure ] crbug.com/1417485 [ android android-nexus-5x passthrough ] conformance/reading/read-pixels-test.html [ Failure ] +############################### +# Permanent Slow Expectations # +############################### +# The "Slow" expectations in this section are expected to stick around, i.e. +# they are not attributed to some known issue that needs resolving. + +# Seems to do enough JavaScript work that heartbeats are not reliably sent. +crbug.com/1426593 conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ] + ################### # Failures/Flakes # ################### @@ -428,7 +437,6 @@ crbug.com/1291276 [ win nvidia angle-vulkan passthrough ] conformance/ogles/GL/mod/mod_001_to_008.html [ Failure ] crbug.com/1364333 [ win debug angle-vulkan passthrough ] conformance/glsl/bugs/temp-expressions-should-not-crash.html [ Slow ] -crbug.com/1364333 [ win debug angle-vulkan passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ] #################### # Mac failures # @@ -570,7 +578,6 @@ crbug.com/1288590 [ android android-pixel-6 ] conformance/misc/shader-precision-format.html [ Failure ] crbug.com/1288603 [ android android-pixel-6 passthrough angle-opengles ] conformance/extensions/angle-instanced-arrays-out-of-bounds.html [ Failure ] crbug.com/1357064 [ android android-pixel-6 no-passthrough ] conformance/rendering/blending.html [ Failure ] -crbug.com/1426593 [ android android-pixel-6 no-passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ] crbug.com/1426535 [ android android-pixel-6 ] conformance/state/gl-enable-enum-test.html [ RetryOnFailure ] crbug.com/1426535 [ android android-pixel-6 ] conformance/state/gl-get-calls.html [ RetryOnFailure ] @@ -602,6 +609,10 @@ crbug.com/1372155 [ android android-sm-a135m ] conformance/uniforms/uniform-samplers-test.html [ Failure ] crbug.com/1372149 [ android android-sm-a235m no-passthrough ] conformance/rendering/blending.html [ Failure ] +crbug.com/1426793 [ android android-sm-a135m ] conformance/extensions/webgl-compressed-texture-astc.html [ Slow ] +crbug.com/1426793 [ android android-sm-a135m ] conformance/glsl/misc/shader-uniform-packing-restrictions.html [ Slow ] +crbug.com/1426793 [ android android-sm-a135m ] conformance/textures/misc/tex-image-and-sub-image-2d-with-array-buffer-view.html [ Slow ] + ############ # ChromeOS # ############
diff --git a/content/test/gpu/gpu_tests/webgpu_cts_integration_test.py b/content/test/gpu/gpu_tests/webgpu_cts_integration_test.py index dc71773..a2dbaa53 100644 --- a/content/test/gpu/gpu_tests/webgpu_cts_integration_test.py +++ b/content/test/gpu/gpu_tests/webgpu_cts_integration_test.py
@@ -102,12 +102,72 @@ return True def _GetSerialGlobs(self) -> Set[str]: - return { + globs = { # crbug.com/1406799. Large test. # Run serially to avoid impact on other tests. '*:api,operation,rendering,basic:large_draw:*', } + # crbug.com/dawn/1500. Flaky tests on Mac-Intel when using 16 byte formats + # in parallel. + FORMATS_WITH_16_BYTE_BLOCKS = [ + # Basic color formats + 'rgba32uint', + 'rgba32sint', + 'rgba32float', + # BC compression formats + 'bc2-rgba-unorm', + 'bc2-rgba-unorm-srgb', + 'bc3-rgba-unorm', + 'bc3-rgba-unorm-srgb', + 'bc5-rg-unorm', + 'bc5-rg-snorm', + 'bc6h-rgb-ufloat', + 'bc6h-rgb-float', + 'bc7-rgba-unorm', + 'bc7-rgba-unorm-srgb', + # ETC2 compression formats + 'etc2-rgba8unorm', + 'etc2-rgba8unorm-srgb', + 'eac-rg11unorm', + 'eac-rg11snorm', + # ASTC compression formats + 'astc-4x4-unorm', + 'astc-4x4-unorm-srgb', + 'astc-5x4-unorm', + 'astc-5x4-unorm-srgb', + 'astc-5x5-unorm', + 'astc-5x5-unorm-srgb', + 'astc-6x5-unorm', + 'astc-6x5-unorm-srgb', + 'astc-6x6-unorm', + 'astc-6x6-unorm-srgb', + 'astc-8x5-unorm', + 'astc-8x5-unorm-srgb', + 'astc-8x6-unorm', + 'astc-8x6-unorm-srgb', + 'astc-8x8-unorm', + 'astc-8x8-unorm-srgb', + 'astc-10x5-unorm', + 'astc-10x5-unorm-srgb', + 'astc-10x6-unorm', + 'astc-10x6-unorm-srgb', + 'astc-10x8-unorm', + 'astc-10x8-unorm-srgb', + 'astc-10x10-unorm', + 'astc-10x10-unorm-srgb', + 'astc-12x10-unorm', + 'astc-12x10-unorm-srgb', + 'astc-12x12-unorm', + 'astc-12x12-unorm-srgb' + ] + for f in FORMATS_WITH_16_BYTE_BLOCKS: + globs.add(( + '*:api,operation,command_buffer,image_copy:origins_and_extents:' + 'initMethod="WriteTexture";checkMethod="PartialCopyT2B";format="%s";*' + ) % f) + return globs + def _GetSerialTests(self) -> Set[str]: return set()
diff --git a/device/vr/android/cardboard/BUILD.gn b/device/vr/android/cardboard/BUILD.gn index a2d8afe..41b62f2 100644 --- a/device/vr/android/cardboard/BUILD.gn +++ b/device/vr/android/cardboard/BUILD.gn
@@ -12,8 +12,6 @@ sources = [ "cardboard_device.cc", "cardboard_device.h", - "cardboard_device_provider.cc", - "cardboard_device_provider.h", "cardboard_sdk.h", "cardboard_sdk_impl.cc", "cardboard_sdk_impl.h",
diff --git a/device/vr/android/cardboard/cardboard_sdk_impl.h b/device/vr/android/cardboard/cardboard_sdk_impl.h index 0770bd0..a9e56349 100644 --- a/device/vr/android/cardboard/cardboard_sdk_impl.h +++ b/device/vr/android/cardboard/cardboard_sdk_impl.h
@@ -7,6 +7,8 @@ #include "device/vr/android/cardboard/cardboard_sdk.h" +#include "base/component_export.h" + namespace device { class COMPONENT_EXPORT(VR_CARDBOARD) CardboardSdkImpl : public CardboardSdk {
diff --git a/docs/infra/new_builder.md b/docs/infra/new_builder.md index 8f321c5e..5477a6a 100644 --- a/docs/infra/new_builder.md +++ b/docs/infra/new_builder.md
@@ -101,7 +101,8 @@ (e.g. mac hardware, attached mobile devices, a specific GPU, etc.). Note that even if there's hardware currently available for the new builder, a resource request will still be needed if the footprint of the new builder equates to -at least 5 VMs or 50 CPU cores. See [go/estimating-bot-capacity](https://goto.google.com/estimating-bot-capacity) +at least 5 VMs or 50 CPU cores per hour. See +[go/estimating-bot-capacity](https://goto.google.com/estimating-bot-capacity) for guidance on how many hosts to request. See [infradata docs][4] (internal) for information on how to register
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc index 549c2f3..0d82b987 100644 --- a/extensions/browser/extension_function_dispatcher.cc +++ b/extensions/browser/extension_function_dispatcher.cc
@@ -491,16 +491,11 @@ scoped_refptr<ExtensionFunction> function = CreateExtensionFunction( params, extension, render_process_id, is_worker_request, rfh_url, - *process_map, ExtensionAPI::GetSharedInstance(), std::move(callback)); + *process_map, ExtensionAPI::GetSharedInstance(), std::move(callback), + render_frame_host); if (!function.get()) return; - function->set_worker_thread_id(params.worker_thread_id); - if (is_worker_request) { - function->set_service_worker_version_id(params.service_worker_version_id); - } else { - function->SetRenderFrameHost(render_frame_host); - } function->SetDispatcher(weak_ptr_factory_.GetWeakPtr()); if (extension && ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito( @@ -665,7 +660,8 @@ const GURL* rfh_url, const ProcessMap& process_map, ExtensionAPI* api, - ExtensionFunction::ResponseCallback callback) { + ExtensionFunction::ResponseCallback callback, + content::RenderFrameHost* render_frame_host) { constexpr char kCreationFailed[] = "Access to extension API denied."; scoped_refptr<ExtensionFunction> function = @@ -703,6 +699,12 @@ function->set_response_callback(std::move(callback)); function->set_source_context_type(context_type); function->set_source_process_id(requesting_process_id); + function->set_worker_thread_id(params.worker_thread_id); + if (is_worker_request) { + function->set_service_worker_version_id(params.service_worker_version_id); + } else { + function->SetRenderFrameHost(render_frame_host); + } if (!function->HasPermission()) { LOG(ERROR) << "Permission denied for " << params.name;
diff --git a/extensions/browser/extension_function_dispatcher.h b/extensions/browser/extension_function_dispatcher.h index e661317..da169d3 100644 --- a/extensions/browser/extension_function_dispatcher.h +++ b/extensions/browser/extension_function_dispatcher.h
@@ -141,7 +141,8 @@ const GURL* rfh_url, const ProcessMap& process_map, ExtensionAPI* api, - ExtensionFunction::ResponseCallback callback); + ExtensionFunction::ResponseCallback callback, + content::RenderFrameHost* render_frame_host); void DispatchWithCallbackInternal( const mojom::RequestParams& params,
diff --git a/extensions/browser/service_worker_task_queue.h b/extensions/browser/service_worker_task_queue.h index 404497e..7687b464 100644 --- a/extensions/browser/service_worker_task_queue.h +++ b/extensions/browser/service_worker_task_queue.h
@@ -138,6 +138,13 @@ // task queue. void ActivateIncognitoSplitModeExtensions(ServiceWorkerTaskQueue* other); + // Retrieves the version of the extension that has currently registered + // and stored an extension service worker. If there is no such version (if + // there was never a service worker or if the worker was unregistered), + // returns an invalid version. + base::Version RetrieveRegisteredServiceWorkerVersion( + const ExtensionId& extension_id); + // content::ServiceWorkerContextObserver: void OnRegistrationStored(int64_t registration_id, const GURL& scope) override; @@ -174,11 +181,6 @@ size_t GetNumPendingTasksForTest(const LazyContextId& lazy_context_id); - base::Version RetrieveRegisteredServiceWorkerVersionForTest( - const ExtensionId& extension_id) { - return RetrieveRegisteredServiceWorkerVersion(extension_id); - } - private: using SequencedContextId = std::pair<LazyContextId, base::UnguessableToken>; @@ -212,17 +214,11 @@ void DidStartWorkerFail(const SequencedContextId& context_id, blink::ServiceWorkerStatusCode status_code); - // The following three methods retrieve, store, and remove information - // about Service Worker registration of SW based background pages: - // - // Retrieves the last version of the extension, returns invalid version if - // there isn't any such extension. - base::Version RetrieveRegisteredServiceWorkerVersion( - const ExtensionId& extension_id); // Records that the extension with |extension_id| and |version| successfully // registered a Service Worker. void SetRegisteredServiceWorkerInfo(const ExtensionId& extension_id, const base::Version& version); + // Clears any record of registered Service Worker for the given extension with // |extension_id|. void RemoveRegisteredServiceWorkerInfo(const ExtensionId& extension_id);
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn index ee198edd..f66e3b1 100644 --- a/extensions/renderer/BUILD.gn +++ b/extensions/renderer/BUILD.gn
@@ -178,6 +178,8 @@ "render_frame_observer_natives.h", "renderer_extension_registry.cc", "renderer_extension_registry.h", + "renderer_frame_context_data.cc", + "renderer_frame_context_data.h", "resource_bundle_source_map.cc", "resource_bundle_source_map.h", "runtime_custom_bindings.cc",
diff --git a/extensions/renderer/renderer_frame_context_data.cc b/extensions/renderer/renderer_frame_context_data.cc new file mode 100644 index 0000000..abc0a17 --- /dev/null +++ b/extensions/renderer/renderer_frame_context_data.cc
@@ -0,0 +1,88 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/renderer/renderer_frame_context_data.h" + +#include "third_party/blink/public/platform/web_security_origin.h" +#include "third_party/blink/public/platform/web_url.h" +#include "third_party/blink/public/web/blink.h" +#include "third_party/blink/public/web/web_document.h" +#include "third_party/blink/public/web/web_frame.h" +#include "third_party/blink/public/web/web_local_frame.h" +#include "url/gurl.h" +#include "url/origin.h" + +namespace extensions { + +std::unique_ptr<ContextData> RendererFrameContextData::Clone() const { + return CloneFrameContextData(); +} + +std::unique_ptr<FrameContextData> +RendererFrameContextData::CloneFrameContextData() const { + return std::make_unique<RendererFrameContextData>(frame_); +} + +bool RendererFrameContextData::IsIsolatedApplication() const { + return blink::IsIsolatedContext(); +} + +std::unique_ptr<FrameContextData> +RendererFrameContextData::GetLocalParentOrOpener() const { + blink::WebFrame* parent_or_opener = nullptr; + if (frame_->Parent()) { + parent_or_opener = frame_->Parent(); + } else { + parent_or_opener = frame_->Opener(); + } + if (!parent_or_opener || !parent_or_opener->IsWebLocalFrame()) { + return nullptr; + } + + blink::WebLocalFrame* local_parent_or_opener = + parent_or_opener->ToWebLocalFrame(); + if (local_parent_or_opener->GetDocument().IsNull()) { + return nullptr; + } + + return std::make_unique<RendererFrameContextData>(local_parent_or_opener); +} + +GURL RendererFrameContextData::GetUrl() const { + if (frame_->GetDocument().Url().IsEmpty()) { + // It's possible for URL to be empty when `frame_` is on the initial empty + // document. TODO(https://crbug.com/1197308): Consider making `frame_`'s + // document's URL about:blank instead of empty in that case. + return GURL(url::kAboutBlankURL); + } + return frame_->GetDocument().Url(); +} + +url::Origin RendererFrameContextData::GetOrigin() const { + return frame_->GetSecurityOrigin(); +} + +bool RendererFrameContextData::CanAccess(const url::Origin& target) const { + return frame_->GetSecurityOrigin().CanAccess(target); +} + +bool RendererFrameContextData::CanAccess(const FrameContextData& target) const { + // It is important that below `web_security_origin` wraps the security + // origin of the `target_frame` (rather than a new origin created via + // url::Origin round-trip - such an origin wouldn't be 100% equivalent - + // e.g. `disallowdocumentaccess` information might be lost). FWIW, this + // scenario is execised by ScriptContextTest.GetEffectiveDocumentURL. + const blink::WebLocalFrame* target_frame = + static_cast<const RendererFrameContextData&>(target).frame_; + blink::WebSecurityOrigin web_security_origin = + target_frame->GetDocument().GetSecurityOrigin(); + + return frame_->GetSecurityOrigin().CanAccess(web_security_origin); +} + +uintptr_t RendererFrameContextData::GetId() const { + return reinterpret_cast<uintptr_t>(frame_); +} + +} // namespace extensions
diff --git a/extensions/renderer/renderer_frame_context_data.h b/extensions/renderer/renderer_frame_context_data.h new file mode 100644 index 0000000..7cea9a8 --- /dev/null +++ b/extensions/renderer/renderer_frame_context_data.h
@@ -0,0 +1,49 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_RENDERER_RENDERER_FRAME_CONTEXT_DATA_H_ +#define EXTENSIONS_RENDERER_RENDERER_FRAME_CONTEXT_DATA_H_ + +#include <stdint.h> +#include <memory> + +#include "extensions/common/frame_context_data.h" +#include "third_party/blink/public/web/web_local_frame.h" + +class GURL; + +namespace url { +class Origin; +} // namespace url + +namespace extensions { + +class RendererFrameContextData : public FrameContextData { + public: + explicit RendererFrameContextData(const blink::WebLocalFrame* frame) + : frame_(frame) {} + + ~RendererFrameContextData() override = default; + + std::unique_ptr<ContextData> Clone() const override; + std::unique_ptr<FrameContextData> CloneFrameContextData() const override; + bool IsIsolatedApplication() const override; + + std::unique_ptr<FrameContextData> GetLocalParentOrOpener() const override; + + GURL GetUrl() const override; + url::Origin GetOrigin() const override; + + bool CanAccess(const url::Origin& target) const override; + bool CanAccess(const FrameContextData& target) const override; + + uintptr_t GetId() const override; + + private: + const blink::WebLocalFrame* const frame_; +}; + +} // namespace extensions + +#endif // EXTENSIONS_RENDERER_RENDERER_FRAME_CONTEXT_DATA_H_
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc index bf4084c..27223c7 100644 --- a/extensions/renderer/script_context.cc +++ b/extensions/renderer/script_context.cc
@@ -20,16 +20,13 @@ #include "extensions/common/extension.h" #include "extensions/common/extension_api.h" #include "extensions/common/extension_urls.h" -#include "extensions/common/frame_context_data.h" #include "extensions/common/manifest_handlers/sandboxed_page_info.h" #include "extensions/common/permissions/permissions_data.h" #include "extensions/renderer/dispatcher.h" #include "extensions/renderer/renderer_extension_registry.h" +#include "extensions/renderer/renderer_frame_context_data.h" #include "extensions/renderer/v8_helpers.h" #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h" -#include "third_party/blink/public/platform/web_security_origin.h" -#include "third_party/blink/public/web/blink.h" -#include "third_party/blink/public/web/web_document.h" #include "third_party/blink/public/web/web_document_loader.h" #include "third_party/blink/public/web/web_local_frame.h" #include "v8/include/v8-context.h" @@ -43,80 +40,6 @@ namespace { -class RendererFrameContextData : public FrameContextData { - public: - explicit RendererFrameContextData(const blink::WebLocalFrame* frame) - : frame_(frame) {} - - ~RendererFrameContextData() override = default; - - std::unique_ptr<ContextData> Clone() const override { - return CloneFrameContextData(); - } - - std::unique_ptr<FrameContextData> CloneFrameContextData() const override { - return std::make_unique<RendererFrameContextData>(frame_); - } - - bool IsIsolatedApplication() const override { - return blink::IsIsolatedContext(); - } - - std::unique_ptr<FrameContextData> GetLocalParentOrOpener() const override { - blink::WebFrame* parent_or_opener = nullptr; - if (frame_->Parent()) - parent_or_opener = frame_->Parent(); - else - parent_or_opener = frame_->Opener(); - if (!parent_or_opener || !parent_or_opener->IsWebLocalFrame()) - return nullptr; - - blink::WebLocalFrame* local_parent_or_opener = - parent_or_opener->ToWebLocalFrame(); - if (local_parent_or_opener->GetDocument().IsNull()) - return nullptr; - - return std::make_unique<RendererFrameContextData>(local_parent_or_opener); - } - - GURL GetUrl() const override { - if (frame_->GetDocument().Url().IsEmpty()) { - // It's possible for URL to be empty when `frame_` is on the initial empty - // document. TODO(https://crbug.com/1197308): Consider making `frame_`'s - // document's URL about:blank instead of empty in that case. - return GURL(url::kAboutBlankURL); - } - return frame_->GetDocument().Url(); - } - - url::Origin GetOrigin() const override { return frame_->GetSecurityOrigin(); } - - bool CanAccess(const url::Origin& target) const override { - return frame_->GetSecurityOrigin().CanAccess(target); - } - - bool CanAccess(const FrameContextData& target) const override { - // It is important that below `web_security_origin` wraps the security - // origin of the `target_frame` (rather than a new origin created via - // url::Origin round-trip - such an origin wouldn't be 100% equivalent - - // e.g. `disallowdocumentaccess` information might be lost). FWIW, this - // scenario is execised by ScriptContextTest.GetEffectiveDocumentURL. - const blink::WebLocalFrame* target_frame = - static_cast<const RendererFrameContextData&>(target).frame_; - blink::WebSecurityOrigin web_security_origin = - target_frame->GetDocument().GetSecurityOrigin(); - - return frame_->GetSecurityOrigin().CanAccess(web_security_origin); - } - - uintptr_t GetId() const override { - return reinterpret_cast<uintptr_t>(frame_); - } - - private: - const blink::WebLocalFrame* const frame_; -}; - GURL GetEffectiveDocumentURL( blink::WebLocalFrame* frame, const GURL& document_url,
diff --git a/gpu/config/software_rendering_list.json b/gpu/config/software_rendering_list.json index e7d662d..ba7dfb0 100644 --- a/gpu/config/software_rendering_list.json +++ b/gpu/config/software_rendering_list.json
@@ -1638,12 +1638,12 @@ }, { "id": 174, - "description": "Disable canvas acceleration on some Haswell GPUs on ChromeOS", + "description": "Disable canvas acceleration on some Haswell and Crystal Well GPUs on ChromeOS", "os": { "type": "chromeos" }, "vendor_id": "0x8086", - "device_id": ["0x0a16", "0x0a1e"], + "device_id": ["0x0a16", "0x0a1e", "0x0d26"], "features": [ "accelerated_2d_canvas" ]
diff --git a/infra/config/generated/luci/commit-queue.cfg b/infra/config/generated/luci/commit-queue.cfg index fc92dbb..c37634c 100644 --- a/infra/config/generated/luci/commit-queue.cfg +++ b/infra/config/generated/luci/commit-queue.cfg
@@ -327,6 +327,10 @@ includable_only: true } builders { + name: "chromium/codesearch/gen-ios-try" + includable_only: true + } + builders { name: "chromium/codesearch/gen-lacros-try" includable_only: true }
diff --git a/infra/config/generated/luci/cr-buildbucket.cfg b/infra/config/generated/luci/cr-buildbucket.cfg index 1884132..8e2e725d 100644 --- a/infra/config/generated/luci/cr-buildbucket.cfg +++ b/infra/config/generated/luci/cr-buildbucket.cfg
@@ -49094,6 +49094,84 @@ } } builders { + name: "gen-ios-try" + swarming_host: "chromium-swarm.appspot.com" + dimensions: "builderless:1" + dimensions: "cores:8" + dimensions: "cpu:arm64" + dimensions: "os:Mac-13" + dimensions: "pool:luci.chromium.try" + exe { + cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build" + cipd_version: "refs/heads/main" + cmd: "luciexe" + } + properties: + '{' + ' "$build/goma": {' + ' "rpc_extra_params": "?prod",' + ' "server_host": "goma.chromium.org"' + ' },' + ' "$recipe_engine/resultdb/test_presentation": {' + ' "column_keys": [],' + ' "grouping_keys": [' + ' "status",' + ' "v.test_suite"' + ' ]' + ' },' + ' "builder_group": "tryserver.chromium.codesearch",' + ' "recipe": "chromium_codesearch",' + ' "recipe_properties": {' + ' "build_config": "ios",' + ' "platform": "ios"' + ' }' + '}' + execution_timeout_secs: 32400 + expiration_secs: 7200 + build_numbers: YES + service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com" + experiments { + key: "chromium_swarming.expose_merge_script_failures" + value: 100 + } + experiments { + key: "luci.recipes.use_python3" + value: 100 + } + resultdb { + enable: true + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "try_test_results" + test_results {} + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "gpu_try_test_results" + test_results { + predicate { + test_id_regexp: "ninja://chrome/test:telemetry_gpu_integration_test[^/]*/.+" + } + } + } + bq_exports { + project: "chrome-luci-data" + dataset: "chromium" + table: "blink_web_tests_try_test_results" + test_results { + predicate { + test_id_regexp: "(ninja://[^/]*blink_web_tests/.+)|(ninja://[^/]*blink_wpt_tests/.+)" + } + } + } + history_options { + use_invocation_timestamp: true + } + } + } + builders { name: "gen-lacros-try" swarming_host: "chromium-swarm.appspot.com" dimensions: "builderless:1"
diff --git a/infra/config/generated/luci/luci-milo.cfg b/infra/config/generated/luci/luci-milo.cfg index 48b54a0..49ee1fe 100644 --- a/infra/config/generated/luci/luci-milo.cfg +++ b/infra/config/generated/luci/luci-milo.cfg
@@ -18689,6 +18689,9 @@ name: "buildbucket/luci.chromium.codesearch/gen-fuchsia-try" } builders { + name: "buildbucket/luci.chromium.codesearch/gen-ios-try" + } + builders { name: "buildbucket/luci.chromium.codesearch/gen-lacros-try" } builders {
diff --git a/infra/config/subprojects/codesearch/codesearch.star b/infra/config/subprojects/codesearch/codesearch.star index 78a939c24..d61c60f8 100644 --- a/infra/config/subprojects/codesearch/codesearch.star +++ b/infra/config/subprojects/codesearch/codesearch.star
@@ -74,6 +74,18 @@ ) try_.builder( + name = "gen-ios-try", + os = os.MAC_13, + cpu = cpu.ARM64, + properties = { + "recipe_properties": { + "build_config": "ios", + "platform": "ios", + }, + }, +) + +try_.builder( name = "gen-lacros-try", properties = { "recipe_properties": {
diff --git a/ios/chrome/app/strings/ios_chromium_strings.grd b/ios/chrome/app/strings/ios_chromium_strings.grd index 1a025fc0..10c1f06 100644 --- a/ios/chrome/app/strings/ios_chromium_strings.grd +++ b/ios/chrome/app/strings/ios_chromium_strings.grd
@@ -620,6 +620,12 @@ <message name="IDS_IOS_ACCOUNT_TABLE_ERROR_HAS_TRUSTED_VAULT_RECOVERABILITY_DEGRADED_FOR_EVERYTHING_MESSAGE" desc="The error message to show in the account table when there is an error related to trusted vault recoverability degraded for everything. [iOS only]"> To use and save Chromium data in your Google Account, verify it's you. </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE" desc="The error message in the identity error info bar related to keep using your Chromium data in your Google account. [iOS only]"> + Keep using the Chromium data in your Google Account + </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_CHROME_DATA_MESSAGE" desc="The error message in the identity error info bar related to making sure your can always use Chromium data in your Google account. [iOS only]"> + Make sure you can always use the Chromium data in your Google Account + </message> </messages> </release> </grit>
diff --git a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE.png.sha1 new file mode 100644 index 0000000..9d309922 --- /dev/null +++ b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE.png.sha1
@@ -0,0 +1 @@ +3ae3fe7f782ef6e2abde6c2d67e39b6f3a8d7b8a \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_CHROME_DATA_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_CHROME_DATA_MESSAGE.png.sha1 new file mode 100644 index 0000000..90a1380 --- /dev/null +++ b/ios/chrome/app/strings/ios_chromium_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_CHROME_DATA_MESSAGE.png.sha1
@@ -0,0 +1 @@ +8d22d6cba893ed3026f5c0c528a4097c97a1bf03 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings.grd b/ios/chrome/app/strings/ios_google_chrome_strings.grd index 2d0a2f0..64b488b8 100644 --- a/ios/chrome/app/strings/ios_google_chrome_strings.grd +++ b/ios/chrome/app/strings/ios_google_chrome_strings.grd
@@ -620,6 +620,12 @@ <message name="IDS_IOS_ACCOUNT_TABLE_ERROR_HAS_TRUSTED_VAULT_RECOVERABILITY_DEGRADED_FOR_EVERYTHING_MESSAGE" desc="The error message to show in the account table when there is an error related to trusted vault recoverability degraded for everything. [iOS only]"> To use and save Chrome data in your Google Account, verify it's you. </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE" desc="The error message in the identity error info bar related to keep using your Chromium data in your Google account. [iOS only]"> + Keep using the Chrome data in your Google Account + </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_CHROME_DATA_MESSAGE" desc="The error message in the identity error info bar related to making sure your can always use Chromium data in your Google account. [iOS only]"> + Make sure you can always use the Chrome data in your Google Account + </message> </messages> </release> </grit>
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE.png.sha1 new file mode 100644 index 0000000..9d309922 --- /dev/null +++ b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE.png.sha1
@@ -0,0 +1 @@ +3ae3fe7f782ef6e2abde6c2d67e39b6f3a8d7b8a \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_CHROME_DATA_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_CHROME_DATA_MESSAGE.png.sha1 new file mode 100644 index 0000000..90a1380 --- /dev/null +++ b/ios/chrome/app/strings/ios_google_chrome_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_CHROME_DATA_MESSAGE.png.sha1
@@ -0,0 +1 @@ +8d22d6cba893ed3026f5c0c528a4097c97a1bf03 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index f3f1027..4cb6c98f 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -4301,6 +4301,24 @@ <message name="IDS_IOS_ACCOUNT_TABLE_ERROR_HAS_TRUSTED_VAULT_RECOVERABILITY_DEGRADED_FOR_PASSWORDS_MESSAGE" desc="The error message to show in the account table when there is an error related to trusted vault recoverability degraded for passwords. [iOS only]"> To make sure you can always use the passwords in your Google Account, verify it's you. </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_PASSPHRASE_TITLE" desc="The title of the identity error info bar when the passphrase is required. [iOS only]"> + Enter your passphrase + </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_ITS_YOU_TITLE" desc="The title of the identity error info bar when identity verification is needed. [iOS only]"> + Verify it's you + </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_PASSWORDS_MESSAGE" desc="The error message in the identity error info bar related to keep using passwords. [iOS only]"> + Keep using the passwords in your Google Account + </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_PASSWORDS_MESSAGE" desc="The error message in the identity error info bar related to making sure you can always use your passwords. [iOS only]"> + Make sure you can always use the passwords in your Google Account + </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_BUTTON_LABEL" desc="The label of the enter passphrase action button in the identity error info bar. [iOS only]"> + Enter + </message> + <message name="IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_BUTTON_LABEL" desc="The label of the verify your account action button in the identity error info bar. [iOS only]"> + Verify + </message> </messages> </release> </grit>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_BUTTON_LABEL.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_BUTTON_LABEL.png.sha1 new file mode 100644 index 0000000..9d309922 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@ +3ae3fe7f782ef6e2abde6c2d67e39b6f3a8d7b8a \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_PASSPHRASE_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_PASSPHRASE_TITLE.png.sha1 new file mode 100644 index 0000000..9d309922 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_PASSPHRASE_TITLE.png.sha1
@@ -0,0 +1 @@ +3ae3fe7f782ef6e2abde6c2d67e39b6f3a8d7b8a \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_PASSWORDS_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_PASSWORDS_MESSAGE.png.sha1 new file mode 100644 index 0000000..8c21dff1 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_PASSWORDS_MESSAGE.png.sha1
@@ -0,0 +1 @@ +61e63f995123ab2a64fd513df7379841ca7edaec \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_PASSWORDS_MESSAGE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_PASSWORDS_MESSAGE.png.sha1 new file mode 100644 index 0000000..4e5f6b9 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_PASSWORDS_MESSAGE.png.sha1
@@ -0,0 +1 @@ +a5c1839962f76466715be2ac383cd46f44a98c05 \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_BUTTON_LABEL.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_BUTTON_LABEL.png.sha1 new file mode 100644 index 0000000..8c21dff1 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_BUTTON_LABEL.png.sha1
@@ -0,0 +1 @@ +61e63f995123ab2a64fd513df7379841ca7edaec \ No newline at end of file
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_ITS_YOU_TITLE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_ITS_YOU_TITLE.png.sha1 new file mode 100644 index 0000000..8c21dff1 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_ITS_YOU_TITLE.png.sha1
@@ -0,0 +1 @@ +61e63f995123ab2a64fd513df7379841ca7edaec \ No newline at end of file
diff --git a/ios/chrome/browser/autofill/bottom_sheet/OWNERS b/ios/chrome/browser/autofill/bottom_sheet/OWNERS new file mode 100644 index 0000000..7b2f0d0 --- /dev/null +++ b/ios/chrome/browser/autofill/bottom_sheet/OWNERS
@@ -0,0 +1,2 @@ +tmartino@chromium.org +sugoi@chromium.org
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.mm index 7224d8e..75aad831 100644 --- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.mm +++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/test/mock_autofill_save_update_address_profile_delegate_ios.mm
@@ -18,10 +18,13 @@ const autofill::AutofillProfile* original_profile, const std::string& locale, autofill::AutofillClient::AddressProfileSavePromptCallback callback) - : AutofillSaveUpdateAddressProfileDelegateIOS(profile, - original_profile, - locale, - std::move(callback)) {} + : AutofillSaveUpdateAddressProfileDelegateIOS( + profile, + original_profile, + /*syncing_user_email=*/absl::nullopt, + locale, + autofill::AutofillClient::SaveAddressProfilePromptOptions{}, + std::move(callback)) {} MockAutofillSaveUpdateAddressProfileDelegateIOS:: ~MockAutofillSaveUpdateAddressProfileDelegateIOS() = default;
diff --git a/ios/chrome/browser/ntp/features.h b/ios/chrome/browser/ntp/features.h index d187506..614bc42 100644 --- a/ios/chrome/browser/ntp/features.h +++ b/ios/chrome/browser/ntp/features.h
@@ -81,8 +81,8 @@ extern const char kAppCloseBackgroundRefreshIntervalInSeconds[]; // Feature param under `kEnableFeedInvisibleForegroundRefresh` for the time -// interval used to set the session end timer. -extern const char kFeedSessionEndTimerTimeoutInSeconds[]; +// interval used to set the refresh timer. +extern const char kFeedRefreshTimerTimeoutInSeconds[]; // Feature param under `kEnableFeedInvisibleForegroundRefresh` for the refresh // threshold when the last refresh was seen. @@ -167,7 +167,7 @@ double GetAppCloseBackgroundRefreshIntervalInSeconds(); // Returns the time interval used to set the session end timer. -double GetFeedSessionEndTimerTimeoutInSeconds(); +double GetFeedRefreshTimerTimeoutInSeconds(); // Returns the refresh threshold (aka feed expiration) for a feed that has been // seen.
diff --git a/ios/chrome/browser/ntp/features.mm b/ios/chrome/browser/ntp/features.mm index dcd43e2..c6dc3e2d 100644 --- a/ios/chrome/browser/ntp/features.mm +++ b/ios/chrome/browser/ntp/features.mm
@@ -73,7 +73,6 @@ "BackgroundRefreshIntervalInSeconds"; const char kBackgroundRefreshMaxAgeInSeconds[] = "BackgroundRefreshMaxAgeInSeconds"; - const char kEnableFeedSessionCloseForegroundRefresh[] = "EnableFeedSessionCloseForegroundRefresh"; const char kEnableFeedAppCloseForegroundRefresh[] = @@ -82,8 +81,8 @@ "EnableFeedAppCloseBackgroundRefresh"; const char kAppCloseBackgroundRefreshIntervalInSeconds[] = "AppCloseBackgroundRefreshIntervalInSeconds"; -const char kFeedSessionEndTimerTimeoutInSeconds[] = - "FeedSessionEndTimerTimeoutInSeconds"; +const char kFeedRefreshTimerTimeoutInSeconds[] = + "FeedRefreshTimerTimeoutInSeconds"; const char kFeedSeenRefreshThresholdInSeconds[] = "FeedSeenRefreshThresholdInSeconds"; const char kFeedUnseenRefreshThresholdInSeconds[] = @@ -234,15 +233,14 @@ /*default=*/base::Minutes(5).InSecondsF()); } -double GetFeedSessionEndTimerTimeoutInSeconds() { +double GetFeedRefreshTimerTimeoutInSeconds() { double override_value = [[NSUserDefaults standardUserDefaults] - doubleForKey:@"FeedSessionEndTimerTimeoutInSeconds"]; + doubleForKey:@"FeedRefreshTimerTimeoutInSeconds"]; if (override_value > 0.0) { return override_value; } return base::GetFieldTrialParamByFeatureAsDouble( - kEnableFeedInvisibleForegroundRefresh, - kFeedSessionEndTimerTimeoutInSeconds, + kEnableFeedInvisibleForegroundRefresh, kFeedRefreshTimerTimeoutInSeconds, /*default=*/base::Minutes(5).InSecondsF()); }
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h index 15a302b..57dce5e3 100644 --- a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h +++ b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.h
@@ -37,6 +37,8 @@ // The banner type. BOOL is_update_banner() const { return is_update_banner_; } + BOOL is_migration_to_account() const { return is_migration_to_account_; } + private: OVERLAY_USER_DATA_SETUP(SaveAddressProfileBannerRequestConfig); explicit SaveAddressProfileBannerRequestConfig(infobars::InfoBar* infobar); @@ -53,6 +55,9 @@ std::u16string button_label_text_; NSString* icon_image_name_ = nil; + // Denotes that the profile will be saved to Google Account. + bool is_migration_to_account_ = false; + // Determines the type of the banner, true for save and false for the update. bool is_update_banner_ = false; };
diff --git a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.mm b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.mm index 36e85a9..9bdf1c8 100644 --- a/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.mm +++ b/ios/chrome/browser/overlays/public/infobar_banner/save_address_profile_infobar_banner_overlay_request_config.mm
@@ -37,6 +37,7 @@ description_ = delegate->GetDescription(); is_update_banner_ = delegate->GetOriginalProfile() ? true : false; icon_image_name_ = kIconImageName; + is_migration_to_account_ = delegate->IsMigrationToAccount(); } SaveAddressProfileBannerRequestConfig::
diff --git a/ios/chrome/browser/policy/configuration_policy_handler_list_factory.mm b/ios/chrome/browser/policy/configuration_policy_handler_list_factory.mm index 4ea75f0a..ee312e46 100644 --- a/ios/chrome/browser/policy/configuration_policy_handler_list_factory.mm +++ b/ios/chrome/browser/policy/configuration_policy_handler_list_factory.mm
@@ -81,7 +81,7 @@ prefs::kManagedDefaultPopupsSetting, base::Value::Type::INTEGER }, { policy::key::kIncognitoModeAvailability, - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, base::Value::Type::INTEGER }, { policy::key::kNTPContentSuggestionsEnabled, prefs::kNTPContentSuggestionsEnabled,
diff --git a/ios/chrome/browser/policy/policy_util.mm b/ios/chrome/browser/policy/policy_util.mm index c242c9a8..fb806ee 100644 --- a/ios/chrome/browser/policy/policy_util.mm +++ b/ios/chrome/browser/policy/policy_util.mm
@@ -5,8 +5,8 @@ #import "ios/chrome/browser/policy/policy_util.h" #import "components/policy/core/common/policy_loader_ios_constants.h" +#import "components/policy/core/common/policy_pref_names.h" #import "components/prefs/pref_service.h" -#import "ios/chrome/browser/prefs/pref_names.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -15,18 +15,21 @@ bool IsIncognitoPolicyApplied(PrefService* pref_service) { if (!pref_service) return NO; - return pref_service->IsManagedPreference(prefs::kIncognitoModeAvailability); + return pref_service->IsManagedPreference( + policy::policy_prefs::kIncognitoModeAvailability); } bool IsIncognitoModeDisabled(PrefService* pref_service) { return IsIncognitoPolicyApplied(pref_service) && - pref_service->GetInteger(prefs::kIncognitoModeAvailability) == + pref_service->GetInteger( + policy::policy_prefs::kIncognitoModeAvailability) == static_cast<int>(IncognitoModePrefs::kDisabled); } bool IsIncognitoModeForced(PrefService* pref_service) { return IsIncognitoPolicyApplied(pref_service) && - pref_service->GetInteger(prefs::kIncognitoModeAvailability) == + pref_service->GetInteger( + policy::policy_prefs::kIncognitoModeAvailability) == static_cast<int>(IncognitoModePrefs::kForced); }
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm index fd58e11..e9fc1df 100644 --- a/ios/chrome/browser/prefs/browser_prefs.mm +++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -372,8 +372,9 @@ registry->RegisterStringPref(prefs::kNewTabPageLocationOverride, std::string()); - registry->RegisterIntegerPref(prefs::kIncognitoModeAvailability, - static_cast<int>(IncognitoModePrefs::kEnabled)); + registry->RegisterIntegerPref( + policy::policy_prefs::kIncognitoModeAvailability, + static_cast<int>(IncognitoModePrefs::kEnabled)); registry->RegisterBooleanPref(prefs::kPrintingEnabled, true);
diff --git a/ios/chrome/browser/prefs/pref_names.cc b/ios/chrome/browser/prefs/pref_names.cc index ff1ba55..b81462e 100644 --- a/ios/chrome/browser/prefs/pref_names.cc +++ b/ios/chrome/browser/prefs/pref_names.cc
@@ -68,12 +68,6 @@ // * Otherwise: Default value driven by Finch config. const char kInactiveTabsTimeThreshold[] = "ios.inactive_tabs.time_threshold"; -// Integer that specifies whether Incognito mode is: -// 0 - Enabled. Default behaviour. Default mode is available on demand. -// 1 - Disabled. User cannot browse pages in Incognito mode. -// 2 - Forced. All pages/sessions are forced into Incognito. -const char kIncognitoModeAvailability[] = "incognito.mode_availability"; - // Boolean that is true when the Incognito interstitial for third-party intents // is enabled. const char kIncognitoInterstitialEnabled[] =
diff --git a/ios/chrome/browser/prefs/pref_names.h b/ios/chrome/browser/prefs/pref_names.h index 40bb93e0..0eb9ffe 100644 --- a/ios/chrome/browser/prefs/pref_names.h +++ b/ios/chrome/browser/prefs/pref_names.h
@@ -23,7 +23,6 @@ extern const char kFirstFollowUIShownCount[]; extern const char kHttpServerProperties[]; extern const char kInactiveTabsTimeThreshold[]; -extern const char kIncognitoModeAvailability[]; extern const char kIncognitoInterstitialEnabled[]; extern const char kIosCredentialProviderPromoPolicyEnabled[]; extern const char kIosCredentialProviderPromoStopPromo[];
diff --git a/ios/chrome/browser/resources/Settings.bundle/ExperimentalFeedRefresh.plist b/ios/chrome/browser/resources/Settings.bundle/ExperimentalFeedRefresh.plist index 2cf0493..65ffbf5 100644 --- a/ios/chrome/browser/resources/Settings.bundle/ExperimentalFeedRefresh.plist +++ b/ios/chrome/browser/resources/Settings.bundle/ExperimentalFeedRefresh.plist
@@ -90,9 +90,9 @@ <key>Type</key> <string>PSTextFieldSpecifier</string> <key>Title</key> - <string>Session end timeout in seconds</string> + <string>Refresh timer timeout in seconds</string> <key>Key</key> - <string>FeedSessionEndTimerTimeoutInSeconds</string> + <string>FeedRefreshTimerTimeoutInSeconds</string> <key>DefaultValue</key> <string></string> <key>KeyboardType</key>
diff --git a/ios/chrome/browser/tabs/inactive_tabs/BUILD.gn b/ios/chrome/browser/tabs/inactive_tabs/BUILD.gn index 1ed537aa..367bf27 100644 --- a/ios/chrome/browser/tabs/inactive_tabs/BUILD.gn +++ b/ios/chrome/browser/tabs/inactive_tabs/BUILD.gn
@@ -44,12 +44,16 @@ "//base/test:test_support", "//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/main:test_support", + "//ios/chrome/browser/ntp", "//ios/chrome/browser/snapshots", "//ios/chrome/browser/tabs:features", + "//ios/chrome/browser/url:constants", + "//ios/chrome/browser/web", "//ios/chrome/browser/web_state_list", "//ios/chrome/browser/web_state_list:test_support", "//ios/chrome/test:test_support", "//ios/web/public/test", "//ios/web/public/test/fakes", + "//third_party/ocmock", ] }
diff --git a/ios/chrome/browser/tabs/inactive_tabs/utils_unittest.mm b/ios/chrome/browser/tabs/inactive_tabs/utils_unittest.mm index f211a65..e5af7b6 100644 --- a/ios/chrome/browser/tabs/inactive_tabs/utils_unittest.mm +++ b/ios/chrome/browser/tabs/inactive_tabs/utils_unittest.mm
@@ -8,18 +8,24 @@ #import "base/test/task_environment.h" #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #import "ios/chrome/browser/main/test_browser.h" +#import "ios/chrome/browser/ntp/new_tab_page_tab_helper.h" +#import "ios/chrome/browser/ntp/new_tab_page_tab_helper_delegate.h" #import "ios/chrome/browser/snapshots/snapshot_browser_agent.h" #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" #import "ios/chrome/browser/tabs/features.h" #import "ios/chrome/browser/tabs/inactive_tabs/features.h" #import "ios/chrome/browser/tabs/inactive_tabs/utils.h" +#import "ios/chrome/browser/url/chrome_url_constants.h" +#import "ios/chrome/browser/web/web_navigation_util.h" #import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" #import "ios/chrome/browser/web_state_list/web_state_opener.h" #import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" +#import "ios/web/public/test/fakes/fake_navigation_manager.h" #import "ios/web/public/test/fakes/fake_web_state.h" #import "ios/web/public/test/web_task_environment.h" #import "testing/platform_test.h" +#import "third_party/ocmock/OCMock/OCMock.h" #import "ui/base/device_form_factor.h" #if !defined(__has_feature) || !__has_feature(objc_arc) @@ -391,3 +397,60 @@ std::vector<int> expected_last_activity_order = {18, 0, 10, 30, 2, 16, 0, 0}; CheckOrder(active_web_state_list, expected_last_activity_order); } + +TEST_F(InactiveTabsUtilsTest, DoNotMoveNTPInInactive) { + // No inactive tabs on iPad. + if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) { + return; + } + base::test::ScopedFeatureList feature_list; + std::map<std::string, std::string> parameters; + parameters[kTabInactivityThresholdParameterName] = + kTabInactivityThresholdOneWeekParam; + feature_list.InitAndEnableFeatureWithParameters(kTabInactivityThreshold, + parameters); + + // Needed to use the NewTabPageTabHelper and ensure that the tab is an NTP. + std::unique_ptr<web::FakeNavigationManager> fake_navigation_manager = + std::make_unique<web::FakeNavigationManager>(); + + std::unique_ptr<web::NavigationItem> pending_item = + web::NavigationItem::Create(); + pending_item->SetURL(GURL(kChromeUIAboutNewTabURL)); + fake_navigation_manager->SetPendingItem(pending_item.get()); + + // Create a New Tab Page (NTP) tab with the last activity at 30 days ago. + std::unique_ptr<web::FakeWebState> fake_web_state = + std::make_unique<web::FakeWebState>(); + GURL url(kChromeUINewTabURL); + fake_web_state->SetVisibleURL(url); + fake_web_state->SetNavigationManager(std::move(fake_navigation_manager)); + fake_web_state->SetLastActiveTime(base::Time::Now() - base::Days(30)); + + // Ensure this is an ntp web state. + id delegate = OCMProtocolMock(@protocol(NewTabPageTabHelperDelegate)); + NewTabPageTabHelper::CreateForWebState(fake_web_state.get()); + NewTabPageTabHelper* ntp_helper = + NewTabPageTabHelper::FromWebState(fake_web_state.get()); + ntp_helper->SetDelegate(delegate); + ASSERT_TRUE(ntp_helper->IsActive()); + + WebStateList* active_web_state_list = browser_active_->GetWebStateList(); + WebStateList* inactive_web_state_list = browser_inactive_->GetWebStateList(); + + EXPECT_EQ(active_web_state_list->count(), 0); + EXPECT_EQ(inactive_web_state_list->count(), 0); + + // Add the created ntp in the active browser. + active_web_state_list->InsertWebState(0, std::move(fake_web_state), + WebStateList::INSERT_ACTIVATE, + WebStateOpener()); + + EXPECT_EQ(active_web_state_list->count(), 1); + EXPECT_EQ(inactive_web_state_list->count(), 0); + + MoveTabsFromActiveToInactive(browser_active_.get(), browser_inactive_.get()); + + EXPECT_EQ(active_web_state_list->count(), 1); + EXPECT_EQ(inactive_web_state_list->count(), 0); +}
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_view_controller.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_view_controller.mm index f3bee55e..4a2bd92 100644 --- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_view_controller.mm +++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_default_account/consistency_default_account_view_controller.mm
@@ -116,10 +116,11 @@ NSString* skipButtonTitle; if (self.accessPoint == - signin_metrics::AccessPoint::ACCESS_POINT_SEND_TAB_TO_SELF_PROMO || - self.accessPoint == - signin_metrics::AccessPoint::ACCESS_POINT_NTP_FEED_CARD_MENU_PROMO) { + signin_metrics::AccessPoint::ACCESS_POINT_SEND_TAB_TO_SELF_PROMO) { skipButtonTitle = l10n_util::GetNSString(IDS_CANCEL); + } else if (self.accessPoint == signin_metrics::AccessPoint:: + ACCESS_POINT_NTP_FEED_CARD_MENU_PROMO) { + skipButtonTitle = l10n_util::GetNSString(IDS_CLOSE); } else { skipButtonTitle = l10n_util::GetNSString(IDS_IOS_CONSISTENCY_PROMO_SKIP); }
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm index bc2395cbb..d3105e5 100644 --- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm +++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
@@ -201,19 +201,12 @@ DCHECK(completionInfo); [self.consistencyPromoSigninMediator systemIdentityAdded:completionInfo.identity]; + self.defaultAccountCoordinator.selectedIdentity = completionInfo.identity; if (!startSignin) { return; } - AuthenticationFlow* authenticationFlow = - [[AuthenticationFlow alloc] initWithBrowser:self.browser - identity:completionInfo.identity - postSignInAction:POST_SIGNIN_ACTION_NONE - presentingViewController:self.navigationController]; - authenticationFlow.dispatcher = HandlerForProtocol( - self.browser->GetCommandDispatcher(), BrowsingDataCommands); - [self.consistencyPromoSigninMediator - signinWithAuthenticationFlow:authenticationFlow]; + [self startSignIn]; } // Opens an AddAccountSigninCoordinator to add an account to the device. If @@ -267,6 +260,19 @@ completionInfo:completionInfo]; } +// Starts the sign-in flow. +- (void)startSignIn { + AuthenticationFlow* authenticationFlow = + [[AuthenticationFlow alloc] initWithBrowser:self.browser + identity:self.selectedIdentity + postSignInAction:POST_SIGNIN_ACTION_NONE + presentingViewController:self.navigationController]; + authenticationFlow.dispatcher = HandlerForProtocol( + self.browser->GetCommandDispatcher(), BrowsingDataCommands); + [self.consistencyPromoSigninMediator + signinWithAuthenticationFlow:authenticationFlow]; +} + #pragma mark - ConsistencyAccountChooserCoordinatorDelegate - (void)consistencyAccountChooserCoordinatorIdentitySelected: @@ -333,15 +339,7 @@ - (void)consistencyDefaultAccountCoordinatorSignin: (ConsistencyDefaultAccountCoordinator*)coordinator { DCHECK_EQ(coordinator, self.defaultAccountCoordinator); - AuthenticationFlow* authenticationFlow = - [[AuthenticationFlow alloc] initWithBrowser:self.browser - identity:self.selectedIdentity - postSignInAction:POST_SIGNIN_ACTION_NONE - presentingViewController:self.navigationController]; - authenticationFlow.dispatcher = HandlerForProtocol( - self.browser->GetCommandDispatcher(), BrowsingDataCommands); - [self.consistencyPromoSigninMediator - signinWithAuthenticationFlow:authenticationFlow]; + [self startSignIn]; } - (void)consistencyDefaultAccountCoordinatorOpenAddAccount:
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h index 66d06064..607d50ca 100644 --- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h +++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.h
@@ -156,6 +156,9 @@ base::OnceCallback<void(const std::string&)> callback) override; private: + // Returns the account email if the account is syncing. + absl::optional<std::u16string> SyncingUserEmail(); + PrefService* pref_service_; syncer::SyncService* sync_service_; std::unique_ptr<AutofillDownloadManager> download_manager_;
diff --git a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm index 9e30bff..981af8b 100644 --- a/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm +++ b/ios/chrome/browser/ui/autofill/chrome_autofill_client_ios.mm
@@ -49,8 +49,12 @@ #import "ios/chrome/browser/infobars/infobar_ios.h" #import "ios/chrome/browser/infobars/infobar_utils.h" #import "ios/chrome/browser/passwords/password_tab_helper.h" +#import "ios/chrome/browser/signin/authentication_service.h" +#import "ios/chrome/browser/signin/authentication_service_factory.h" #import "ios/chrome/browser/signin/identity_manager_factory.h" #import "ios/chrome/browser/sync/sync_service_factory.h" +#import "ios/chrome/browser/sync/sync_setup_service.h" +#import "ios/chrome/browser/sync/sync_setup_service_factory.h" #import "ios/chrome/browser/translate/chrome_ios_translate_client.h" #import "ios/chrome/browser/ui/autofill/card_expiration_date_fix_flow_view_bridge.h" #import "ios/chrome/browser/ui/autofill/card_name_fix_flow_view_bridge.h" @@ -380,8 +384,9 @@ } auto delegate = std::make_unique<AutofillSaveUpdateAddressProfileDelegateIOS>( - profile, original_profile, - GetApplicationContext()->GetApplicationLocale(), std::move(callback)); + profile, original_profile, SyncingUserEmail(), + GetApplicationContext()->GetApplicationLocale(), options, + std::move(callback)); infobar_manager_->AddInfoBar(std::make_unique<InfoBarIOS>( InfobarType::kInfobarTypeSaveAutofillAddressProfile, @@ -532,4 +537,20 @@ base::SysNSStringToUTF8(ios::provider::GetRiskData())); } +absl::optional<std::u16string> ChromeAutofillClientIOS::SyncingUserEmail() { + AuthenticationService* authenticationService = + AuthenticationServiceFactory::GetForBrowserState(browser_state_); + DCHECK(authenticationService); + id<SystemIdentity> identity = + authenticationService->GetPrimaryIdentity(signin::ConsentLevel::kSync); + if (identity) { + SyncSetupService* syncSetupService = + SyncSetupServiceFactory::GetForBrowserState(browser_state_); + if (syncSetupService->IsDataTypeActive(syncer::AUTOFILL)) { + return base::SysNSStringToUTF16(identity.userEmail); + } + } + return absl::nullopt; +} + } // namespace autofill
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm index 83d50da7b..598dbc7 100644 --- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm +++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -868,6 +868,10 @@ IdentityManagerFactory::GetForBrowserState( self.browser->GetBrowserState()); _viewControllerDependencies.voiceSearchController = _voiceSearchController; + _viewControllerDependencies.secondaryToolbarContainerCoordinator = + [[ToolbarContainerCoordinator alloc] + initWithBrowser:self.browser + type:ToolbarContainerType::kSecondary]; } - (void)updateViewControllerDependencies { @@ -928,6 +932,7 @@ _viewControllerDependencies.readingModel = nil; _viewControllerDependencies.identityManager = nil; _viewControllerDependencies.voiceSearchController = nil; + _viewControllerDependencies.secondaryToolbarContainerCoordinator = nil; [_bookmarksCoordinator shutdown]; _bookmarksCoordinator = nil;
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.h b/ios/chrome/browser/ui/browser_view/browser_view_controller.h index ef2f823..47f943c 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.h +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.h
@@ -26,6 +26,7 @@ #import "ios/chrome/browser/ui/page_info/requirements/page_info_presentation.h" #import "ios/chrome/browser/ui/settings/sync/utils/sync_presenter.h" #import "ios/chrome/browser/ui/thumb_strip/thumb_strip_supporting.h" +#import "ios/chrome/browser/ui/toolbar_container/toolbar_container_coordinator.h" #import "ios/chrome/browser/url_loading/url_loading_browser_agent.h" #import "ios/chrome/browser/url_loading/url_loading_notifier_browser_agent.h" #import "ios/chrome/browser/web/web_navigation_browser_agent.h" @@ -65,6 +66,7 @@ @protocol TextZoomCommands; @class ToolbarAccessoryPresenter; @protocol ToolbarCommands; +@class ToolbarContainerCoordinator; @protocol IncognitoReauthCommands; @class LayoutGuideCenter; @protocol LoadQueryCommands; @@ -113,6 +115,7 @@ TabUsageRecorderBrowserAgent* tabUsageRecorderBrowserAgent; WebNavigationBrowserAgent* webNavigationBrowserAgent; base::WeakPtr<WebStateList> webStateList; + ToolbarContainerCoordinator* secondaryToolbarContainerCoordinator; } BrowserViewControllerDependencies; // The top-level view controller for the browser UI. Manages other controllers
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm index 4960b96..c8f0bd2 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -504,6 +504,8 @@ _readingModel = dependencies.readingModel; _identityManager = dependencies.identityManager; _voiceSearchController = dependencies.voiceSearchController; + self.secondaryToolbarContainerCoordinator = + dependencies.secondaryToolbarContainerCoordinator; dependencies.lensCoordinator.delegate = self; @@ -1512,10 +1514,6 @@ // TODO(crbug.com/880672): Finish ToolbarContainer work. if (base::FeatureList::IsEnabled( toolbar_container::kToolbarContainerEnabled)) { - self.secondaryToolbarContainerCoordinator = - [[ToolbarContainerCoordinator alloc] - initWithBrowser:self.browser - type:ToolbarContainerType::kSecondary]; self.secondaryToolbarContainerCoordinator.toolbarCoordinators = @[ self.secondaryToolbarCoordinator ]; [self.secondaryToolbarContainerCoordinator start];
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm index 6d344a1..22cc5c1 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
@@ -281,6 +281,10 @@ browser_.get()->GetBrowserState()); dependencies.identityManager = IdentityManagerFactory::GetForBrowserState( browser_.get()->GetBrowserState()); + dependencies.secondaryToolbarContainerCoordinator = + [[ToolbarContainerCoordinator alloc] + initWithBrowser:browser_.get() + type:ToolbarContainerType::kSecondary]; bvc_ = [[BrowserViewController alloc] initWithBrowser:browser_.get() browserContainerViewController:container_
diff --git a/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn b/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn index b83961f..eaa8ddd5 100644 --- a/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn +++ b/ios/chrome/browser/ui/credential_provider_promo/BUILD.gn
@@ -70,7 +70,10 @@ source_set("unit_tests") { testonly = true - sources = [ "credential_provider_promo_mediator_unittest.mm" ] + sources = [ + "credential_provider_promo_coordinator_unittest.mm", + "credential_provider_promo_mediator_unittest.mm", + ] configs += [ "//build/config/compiler:enable_arc" ] deps = [ ":credential_provider_promo", @@ -79,13 +82,17 @@ "//components/password_manager/core/common", "//components/prefs:test_support", "//ios/chrome/app/strings", + "//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/credential_provider_promo:features", + "//ios/chrome/browser/main:test_support", "//ios/chrome/browser/prefs:pref_names", "//ios/chrome/browser/promos_manager", "//ios/chrome/browser/promos_manager:test_support", "//ios/chrome/browser/shared/public/commands", + "//ios/chrome/common/ui/confirmation_alert", "//ios/chrome/test:test_support", "//ios/public/provider/chrome/browser/branded_images:branded_images_api", + "//ios/web/public/test", "//testing/gtest", "//third_party/ocmock", "//ui/base",
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator_unittest.mm b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator_unittest.mm new file mode 100644 index 0000000..82bc1abe --- /dev/null +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator_unittest.mm
@@ -0,0 +1,197 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.h" + +#import "base/test/metrics/histogram_tester.h" +#import "base/test/scoped_feature_list.h" +#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h" +#import "ios/chrome/browser/credential_provider_promo/features.h" +#import "ios/chrome/browser/main/test_browser.h" +#import "ios/chrome/browser/prefs/pref_names.h" +#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" +#import "ios/chrome/browser/shared/public/commands/credential_provider_promo_commands.h" +#import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_constants.h" +#import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_coordinator.h" +#import "ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.h" +#import "ios/chrome/common/ui/confirmation_alert/confirmation_alert_action_handler.h" +#import "ios/chrome/test/ios_chrome_scoped_testing_local_state.h" +#import "ios/web/public/test/web_task_environment.h" +#import "testing/platform_test.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +// Test fixture for testing the CredentialProviderPromoCoordinator class. +class CredentialProviderPromoCoordinatorTest : public PlatformTest { + public: + CredentialProviderPromoCoordinatorTest() + : browser_state_(TestChromeBrowserState::Builder().Build()), + browser_(std::make_unique<TestBrowser>(browser_state_.get())), + scoped_feature_list_(std::make_unique<base::test::ScopedFeatureList>()), + histogram_tester_(std::make_unique<base::HistogramTester>()) { + scoped_feature_list_->InitAndEnableFeature( + kCredentialProviderExtensionPromo); + + coordinator_ = [[CredentialProviderPromoCoordinator alloc] + initWithBaseViewController:nil + browser:browser_.get()]; + [coordinator_ start]; + + credential_provider_promo_command_handler_ = HandlerForProtocol( + browser_->GetCommandDispatcher(), CredentialProviderPromoCommands); + } + ~CredentialProviderPromoCoordinatorTest() override { [coordinator_ stop]; } + + protected: + web::WebTaskEnvironment task_environment_; + IOSChromeScopedTestingLocalState local_state_; + std::unique_ptr<TestChromeBrowserState> browser_state_; + std::unique_ptr<TestBrowser> browser_; + std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_; + std::unique_ptr<base::HistogramTester> histogram_tester_; + + CredentialProviderPromoCoordinator* coordinator_; + id<CredentialProviderPromoCommands> + credential_provider_promo_command_handler_; +}; + +#pragma mark - Tests + +// Tests that impression is recorded with the correct source. +TEST_F(CredentialProviderPromoCoordinatorTest, + CredentialProviderPromoImpressionRecorded) { + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoImpressionHistogram, + IOSCredentialProviderPromoSource::kPasswordCopied, 0); + + // Coordinator will show the promo with PasswordCopied as source. + [credential_provider_promo_command_handler_ + showCredentialProviderPromoWithTrigger:CredentialProviderPromoTrigger:: + PasswordCopied]; + + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoImpressionHistogram, + IOSCredentialProviderPromoSource::kPasswordCopied, 1); +} + +// Tests that the remind-me-later promo's impression is recorded with the +// correct original source. +TEST_F(CredentialProviderPromoCoordinatorTest, + CredentialProviderPromoImpressionFromReminderRecorded) { + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoImpressionIsReminderHistogram, + IOSCredentialProviderPromoSource::kPasswordCopied, 0); + + // Coordinator will show the promo with PasswordCopied as source, and update + // `prefs::kIosCredentialProviderPromoSource`. + [credential_provider_promo_command_handler_ + showCredentialProviderPromoWithTrigger:CredentialProviderPromoTrigger:: + PasswordCopied]; + + // Coordinator is called to again to show the promo as reminder. + // `kPasswordCopied` will be used as the original source when recording + // metric. + [credential_provider_promo_command_handler_ + showCredentialProviderPromoWithTrigger:CredentialProviderPromoTrigger:: + RemindMeLater]; + + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoImpressionIsReminderHistogram, + IOSCredentialProviderPromoSource::kPasswordCopied, 1); +} + +// Tests that tapping the primary CTA in both the first and second step of the +// promo will result in two primary actions being recorded correctly. +TEST_F(CredentialProviderPromoCoordinatorTest, + CredentialProviderPromoTwoStepPrimaryActionRecorded) { + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoOnPasswordSavedHistogram, + credential_provider_promo::IOSCredentialProviderPromoAction::kLearnMore, + 0); + // Trigger the promo with PasswordSaved. + // The primary CTA on the first step of the promo is 'learn more'. + [credential_provider_promo_command_handler_ + showCredentialProviderPromoWithTrigger:CredentialProviderPromoTrigger:: + PasswordSaved]; + + // Perform the action. Coordinator will record the action and set. + // `promoContext` to 'learn more' + ASSERT_TRUE([coordinator_ + conformsToProtocol:@protocol(ConfirmationAlertActionHandler)]); + [(id<ConfirmationAlertActionHandler>) + coordinator_ confirmationAlertPrimaryAction]; + + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoOnPasswordSavedHistogram, + credential_provider_promo::IOSCredentialProviderPromoAction::kLearnMore, + 1); + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoOnPasswordSavedHistogram, + credential_provider_promo::IOSCredentialProviderPromoAction:: + kGoToSettings, + 0); + + // When the `promoContext` is 'learn more', the primary CTA is 'go to + // settings'. + [(id<ConfirmationAlertActionHandler>) + coordinator_ confirmationAlertPrimaryAction]; + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoOnPasswordSavedHistogram, + credential_provider_promo::IOSCredentialProviderPromoAction:: + kGoToSettings, + 1); +} + +// Tests that tapping the secondary CTA is recorded correctly when the promo is +// shown from autofill. +TEST_F(CredentialProviderPromoCoordinatorTest, + CredentialProviderPromoSecondaryActionRecorded) { + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoOnAutofillUsedHistogram, + credential_provider_promo::IOSCredentialProviderPromoAction::kNo, 0); + + // Trigger the promo with SuccessfulLoginUsingExistingPassword. + [credential_provider_promo_command_handler_ + showCredentialProviderPromoWithTrigger: + CredentialProviderPromoTrigger::SuccessfulLoginUsingExistingPassword]; + + EXPECT_TRUE([coordinator_ + conformsToProtocol:@protocol(ConfirmationAlertActionHandler)]); + // Perform the action, Coordinator will record the action. + [(id<ConfirmationAlertActionHandler>) + coordinator_ confirmationAlertSecondaryAction]; + + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoOnAutofillUsedHistogram, + credential_provider_promo::IOSCredentialProviderPromoAction::kNo, 1); +} + +// Tests that tapping the tertiary CTA is recorded correctly when the promo is +// shown from password copied. +TEST_F(CredentialProviderPromoCoordinatorTest, + CredentialProviderPromoTertiaryActionRecorded) { + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoOnPasswordCopiedHistogram, + credential_provider_promo::IOSCredentialProviderPromoAction:: + kRemindMeLater, + 0); + + // Trigger the promo with PasswordCopied. + [credential_provider_promo_command_handler_ + showCredentialProviderPromoWithTrigger:CredentialProviderPromoTrigger:: + PasswordCopied]; + // Perform the action, Coordinator will record the action. + EXPECT_TRUE([coordinator_ + conformsToProtocol:@protocol(ConfirmationAlertActionHandler)]); + [(id<ConfirmationAlertActionHandler>) + coordinator_ confirmationAlertTertiaryAction]; + + histogram_tester_->ExpectBucketCount( + kIOSCredentialProviderPromoOnPasswordCopiedHistogram, + credential_provider_promo::IOSCredentialProviderPromoAction:: + kRemindMeLater, + 1); +}
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.h b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.h index c601c11..7f366d04 100644 --- a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.h +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.h
@@ -6,6 +6,18 @@ #ifndef IOS_CHROME_BROWSER_UI_CREDENTIAL_PROVIDER_PROMO_CREDENTIAL_PROVIDER_PROMO_METRICS_H_ #define IOS_CHROME_BROWSER_UI_CREDENTIAL_PROVIDER_PROMO_CREDENTIAL_PROVIDER_PROMO_METRICS_H_ +extern const char kIOSCredentialProviderPromoImpressionHistogram[]; +extern const char kIOSCredentialProviderPromoImpressionIsReminderHistogram[]; +extern const char kIOSCredentialProviderPromoOnPasswordSavedHistogram[]; +extern const char + kIOSCredentialProviderPromoOnPasswordSavedIsReminderHistogram[]; +extern const char kIOSCredentialProviderPromoOnPasswordCopiedHistogram[]; +extern const char + kIOSCredentialProviderPromoOnPasswordCopiedIsReminderHistogram[]; +extern const char kIOSCredentialProviderPromoOnAutofillUsedHistogram[]; +extern const char + kIOSCredentialProviderPromoOnAutofillUsedIsReminderHistogram[]; + namespace credential_provider_promo { // Enum for histograms like
diff --git a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.mm b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.mm index 7692534..cb8cb84 100644 --- a/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.mm +++ b/ios/chrome/browser/ui/credential_provider_promo/credential_provider_promo_metrics.mm
@@ -11,16 +11,35 @@ #error "This file requires ARC support." #endif +const char kIOSCredentialProviderPromoImpressionHistogram[] = + "IOS.CredentialProviderExtension.Promo.Impression"; +const char kIOSCredentialProviderPromoImpressionIsReminderHistogram[] = + "IOS.CredentialProviderExtension.Promo.Impression.IsReminder"; +const char kIOSCredentialProviderPromoOnPasswordSavedHistogram[] = + "IOS.CredentialProviderExtension.Promo.OnPasswordSaved"; +const char kIOSCredentialProviderPromoOnPasswordSavedIsReminderHistogram[] = + "IOS.CredentialProviderExtension.Promo.OnPasswordSaved.IsReminder"; +const char kIOSCredentialProviderPromoOnPasswordCopiedHistogram[] = + "IOS.CredentialProviderExtension.Promo.OnPasswordCopied"; +const char kIOSCredentialProviderPromoOnPasswordCopiedIsReminderHistogram[] = + "IOS.CredentialProviderExtension.Promo.OnPasswordCopied.IsReminder"; +const char kIOSCredentialProviderPromoOnAutofillUsedHistogram[] = + "IOS.CredentialProviderExtension.Promo." + "OnSuccessfulLoginWithAutofilledPassword"; +const char kIOSCredentialProviderPromoOnAutofillUsedIsReminderHistogram[] = + "IOS.CredentialProviderExtension.Promo." + "OnSuccessfulLoginWithAutofilledPassword.IsReminder"; + namespace credential_provider_promo { void RecordImpression(IOSCredentialProviderPromoSource source, bool is_reminder) { if (is_reminder) { base::UmaHistogramEnumeration( - "IOS.CredentialProviderExtension.Promo.Impression.IsReminder", source); + kIOSCredentialProviderPromoImpressionIsReminderHistogram, source); } else { base::UmaHistogramEnumeration( - "IOS.CredentialProviderExtension.Promo.Impression", source); + kIOSCredentialProviderPromoImpressionHistogram, source); } } @@ -30,22 +49,20 @@ std::string name; switch (source) { case IOSCredentialProviderPromoSource::kPasswordCopied: - name = is_reminder - ? "IOS.CredentialProviderExtension.Promo.OnPasswordCopied." - "IsReminder" - : "IOS.CredentialProviderExtension.Promo.OnPasswordCopied"; + name = + is_reminder + ? kIOSCredentialProviderPromoOnPasswordCopiedIsReminderHistogram + : kIOSCredentialProviderPromoOnPasswordCopiedHistogram; break; case IOSCredentialProviderPromoSource::kPasswordSaved: name = is_reminder - ? "IOS.CredentialProviderExtension.Promo.OnPasswordSaved." - "IsReminder" - : "IOS.CredentialProviderExtension.Promo.OnPasswordSaved"; + ? kIOSCredentialProviderPromoOnPasswordSavedIsReminderHistogram + : kIOSCredentialProviderPromoOnPasswordSavedHistogram; break; case IOSCredentialProviderPromoSource::kAutofillUsed: - name = is_reminder ? "IOS.CredentialProviderExtension.Promo." - "OnSuccessfulLoginWithAutofilledPassword.IsReminder" - : "IOS.CredentialProviderExtension.Promo." - "OnSuccessfulLoginWithAutofilledPassword"; + name = is_reminder + ? kIOSCredentialProviderPromoOnAutofillUsedIsReminderHistogram + : kIOSCredentialProviderPromoOnAutofillUsedHistogram; break; case IOSCredentialProviderPromoSource::kUnknown: NOTREACHED();
diff --git a/ios/chrome/browser/ui/menu/BUILD.gn b/ios/chrome/browser/ui/menu/BUILD.gn index 0503e158..e483210 100644 --- a/ios/chrome/browser/ui/menu/BUILD.gn +++ b/ios/chrome/browser/ui/menu/BUILD.gn
@@ -59,6 +59,7 @@ "resources:move_folder", "//base", "//base/test:test_support", + "//components/policy/core/common:common_constants", "//components/sync_preferences:test_support", "//ios/chrome/app/strings", "//ios/chrome/browser/browser_state:test_support",
diff --git a/ios/chrome/browser/ui/menu/browser_action_factory_unittest.mm b/ios/chrome/browser/ui/menu/browser_action_factory_unittest.mm index c7105852..d6cc0cc 100644 --- a/ios/chrome/browser/ui/menu/browser_action_factory_unittest.mm +++ b/ios/chrome/browser/ui/menu/browser_action_factory_unittest.mm
@@ -7,6 +7,7 @@ #import "base/test/metrics/histogram_tester.h" #import "base/test/scoped_feature_list.h" #import "base/test/task_environment.h" +#import "components/policy/core/common/policy_pref_names.h" #import "components/sync_preferences/testing_pref_service_syncable.h" #import "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #import "ios/chrome/browser/main/test_browser.h" @@ -248,7 +249,7 @@ EXPECT_EQ(0U, action.attributes); chrome_browser_state_->GetTestingPrefService()->SetManagedPref( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, std::make_unique<base::Value>( static_cast<int>(IncognitoModePrefs::kForced))); @@ -274,7 +275,7 @@ EXPECT_EQ(0U, action.attributes); chrome_browser_state_->GetTestingPrefService()->SetManagedPref( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, std::make_unique<base::Value>( static_cast<int>(IncognitoModePrefs::kDisabled))); @@ -352,7 +353,7 @@ EXPECT_EQ(0U, action.attributes); chrome_browser_state_->GetTestingPrefService()->SetManagedPref( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, std::make_unique<base::Value>( static_cast<int>(IncognitoModePrefs::kForced))); @@ -378,7 +379,7 @@ EXPECT_EQ(0U, action.attributes); chrome_browser_state_->GetTestingPrefService()->SetManagedPref( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, std::make_unique<base::Value>( static_cast<int>(IncognitoModePrefs::kDisabled)));
diff --git a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm index 6b66800..bfac4b4 100644 --- a/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm +++ b/ios/chrome/browser/ui/ntp/metrics/feed_metrics_recorder.mm
@@ -81,8 +81,8 @@ // `ContentSuggestions.Feed.TimeSpentInFeed` @property(nonatomic, assign) base::TimeDelta timeSpentInFeed; -// Timer to signal end of session. -@property(nonatomic, strong) NSTimer* sessionEndTimer; +// Timer to refresh the feed. +@property(nonatomic, strong) NSTimer* refreshTimer; // YES if the NTP is visible. @property(nonatomic, assign) BOOL isNTPVisible; @@ -106,8 +106,8 @@ #pragma mark - Public - (void)dealloc { - [self.sessionEndTimer invalidate]; - self.sessionEndTimer = nil; + [self.refreshTimer invalidate]; + self.refreshTimer = nil; } + (void)recordFeedRefreshTrigger:(FeedRefreshTrigger)trigger { @@ -166,7 +166,7 @@ // Invalidate the timer when the user returns to the feed since the feed // should not be refreshed when the user is viewing it. if (visible) { - [self.sessionEndTimer invalidate]; + [self.refreshTimer invalidate]; [self recordDiscoverFeedUserActionHistogram:FeedUserActionType:: kOpenedFeedSurface asInteraction:NO]; @@ -909,7 +909,7 @@ // engagement criteria. For example, setting `engagedSimpleReportedDiscover` // must happen before this call. if (IsFeedSessionCloseForegroundRefreshEnabled()) { - [self setOrExtendSessionEndTimer]; + [self setOrExtendRefreshTimer]; } } @@ -1278,22 +1278,22 @@ } } -// Sets or extends the session end timer. -- (void)setOrExtendSessionEndTimer { - [self.sessionEndTimer invalidate]; +// Sets or extends the refresh timer. +- (void)setOrExtendRefreshTimer { + [self.refreshTimer invalidate]; __weak FeedMetricsRecorder* weakSelf = self; - self.sessionEndTimer = [NSTimer - scheduledTimerWithTimeInterval:GetFeedSessionEndTimerTimeoutInSeconds() + self.refreshTimer = [NSTimer + scheduledTimerWithTimeInterval:GetFeedRefreshTimerTimeoutInSeconds() target:weakSelf - selector:@selector(sessionEndTimerEnded) + selector:@selector(refreshTimerEnded) userInfo:nil repeats:NO]; } -// Signals that the session end timer ended. -- (void)sessionEndTimerEnded { - [self.sessionEndTimer invalidate]; - self.sessionEndTimer = nil; +// Signals that the refresh timer ended. +- (void)refreshTimerEnded { + [self.refreshTimer invalidate]; + self.refreshTimer = nil; if (![self isNTPAndFeedVisible]) { // The feed refresher checks feed engagement criteria. self.feedRefresher->RefreshFeed(
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator.mm b/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator.mm index df44197..f0abffd3 100644 --- a/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator.mm +++ b/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator.mm
@@ -65,7 +65,10 @@ setTitleText:base::SysUTF16ToNSString(self.config->message_text())]; [self.consumer setSubtitleText:base::SysUTF16ToNSString(self.config->description())]; - [self.consumer setRestrictSubtitleTextToSingleLine:YES]; + + if (!self.config->is_migration_to_account()) { + [self.consumer setRestrictSubtitleTextToSingleLine:YES]; + } [self.consumer setIconImage:CustomSymbolWithPointSize(kLocationFillSymbol,
diff --git a/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator_unittest.mm b/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator_unittest.mm index c19a8cf..4e404d1 100644 --- a/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator_unittest.mm +++ b/ios/chrome/browser/ui/overlays/infobar_banner/autofill_address_profile/save_address_profile_infobar_banner_overlay_mediator_unittest.mm
@@ -50,7 +50,10 @@ std::unique_ptr<autofill::AutofillSaveUpdateAddressProfileDelegateIOS> passed_delegate = std::make_unique< autofill::AutofillSaveUpdateAddressProfileDelegateIOS>( - profile, /*original_profile=*/nullptr, /*locale=*/"en-US", + profile, /*original_profile=*/nullptr, + /*syncing_user_email=*/absl::nullopt, + /*locale=*/"en-US", + autofill::AutofillClient::SaveAddressProfilePromptOptions{}, base::DoNothing()); autofill::AutofillSaveUpdateAddressProfileDelegateIOS* delegate = passed_delegate.get(); @@ -88,7 +91,10 @@ std::unique_ptr<autofill::AutofillSaveUpdateAddressProfileDelegateIOS> passed_delegate = std::make_unique< autofill::AutofillSaveUpdateAddressProfileDelegateIOS>( - profile, /*original_profile=*/nullptr, /*locale=*/"en-US", + profile, /*original_profile=*/nullptr, + /*syncing_user_email=*/absl::nullopt, + /*locale=*/"en-US", + autofill::AutofillClient::SaveAddressProfilePromptOptions{}, base::DoNothing()); InfoBarIOS infobar(InfobarType::kInfobarTypeSaveAutofillAddressProfile, std::move(passed_delegate));
diff --git a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm index 142b0ad..a202681d 100644 --- a/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm +++ b/ios/chrome/browser/ui/overlays/infobar_modal/autofill_address_profile/save_address_profile_infobar_modal_overlay_mediator_unittest.mm
@@ -47,7 +47,10 @@ std::unique_ptr<autofill::AutofillSaveUpdateAddressProfileDelegateIOS> delegate = std::make_unique< autofill::AutofillSaveUpdateAddressProfileDelegateIOS>( - profile, /*original_profile=*/nullptr, /*locale=*/"en-US", + profile, /*original_profile=*/nullptr, + /*syncing_user_email=*/absl::nullopt, + /*locale=*/"en-US", + autofill::AutofillClient::SaveAddressProfilePromptOptions{}, base::DoNothing()); delegate_ = delegate.get(); infobar_ = std::make_unique<InfoBarIOS>(
diff --git a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_consumer.h b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_consumer.h index a0610c1c..4e1c7b8 100644 --- a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_consumer.h +++ b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_consumer.h
@@ -47,6 +47,10 @@ // Indicates the state of the account storage switch. - (void)setAccountStorageState:(PasswordSettingsAccountStorageState)state; +// Whether the account storage switch (if displayed) should show an icon that +// highlights it as a new feature. This doesn't mean the switch itself is shown. +- (void)setShowAccountStorageNewFeatureIcon:(BOOL)show; + // Indicates the signed-in account. - (void)setSignedInAccount:(NSString*)account;
diff --git a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_delegate.h b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_delegate.h index c1d82d8..3255a95a 100644 --- a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_delegate.h +++ b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_delegate.h
@@ -15,6 +15,9 @@ // Indicates whether or not the account storage switch is set to enabled. - (void)accountStorageSwitchDidChange:(BOOL)enabled; +// Indicates the new feature icon was shown for the account storage switch. +- (void)accountStorageNewFeatureIconDidShow; + @end #endif // IOS_CHROME_BROWSER_UI_SETTINGS_PASSWORD_PASSWORD_SETTINGS_PASSWORD_SETTINGS_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_mediator.mm b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_mediator.mm index 6a7426b..a126cce 100644 --- a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_mediator.mm +++ b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_mediator.mm
@@ -65,6 +65,10 @@ // Sync observer. std::unique_ptr<SyncObserverBridge> _syncObserver; + + // Flag to avoid incrementing the number of impressions of the icon more than + // once through the lifetime of the UI. + BOOL _accountStorageNewFeatureIconImpressionsIncremented; } // Helper object which maintains state about the "Export Passwords..." flow, and @@ -137,6 +141,15 @@ [self.consumer setAccountStorageState:[self computeAccountStorageState]]; + // < and not <= below, because the next impression must be counted. + const int impressionCount = _prefService->GetInteger( + password_manager::prefs::kAccountStorageNewFeatureIconImpressions); + const int maxImpressionCount = + password_manager::features::kMaxAccountStorageNewFeatureIconImpressions + .Get(); + [self.consumer + setShowAccountStorageNewFeatureIcon:impressionCount < maxImpressionCount]; + // TODO(crbug.com/1082827): In addition to setting this value here, we should // observe for changes (i.e., if policy changes while the screen is open) and // push that to the consumer. @@ -227,6 +240,17 @@ types); } +- (void)accountStorageNewFeatureIconDidShow { + if (!_accountStorageNewFeatureIconImpressionsIncremented) { + _accountStorageNewFeatureIconImpressionsIncremented = YES; + _prefService->SetInteger( + password_manager::prefs::kAccountStorageNewFeatureIconImpressions, + 1 + _prefService->GetInteger( + password_manager::prefs:: + kAccountStorageNewFeatureIconImpressions)); + } +} + #pragma mark - SavedPasswordsPresenterObserver - (void)savedPasswordsDidChange {
diff --git a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_view_controller.mm index d4c0dbb6..1c99d15 100644 --- a/ios/chrome/browser/ui/settings/password/password_settings/password_settings_view_controller.mm +++ b/ios/chrome/browser/ui/settings/password/password_settings/password_settings_view_controller.mm
@@ -98,6 +98,10 @@ @property(nonatomic, assign) PasswordSettingsAccountStorageState accountStorageState; +// Indicates whether the account storage switch should contain an icon +// indicating a new feature. This doesn't mean the switch itself is shown. +@property(nonatomic, assign) BOOL showAccountStorageNewFeatureIcon; + // Indicates the signed in account. @property(nonatomic, copy) NSString* signedInAccount; @@ -242,8 +246,12 @@ action:@selector(accountStorageSwitchChanged:) forControlEvents:UIControlEventValueChanged]; + if (!_showAccountStorageNewFeatureIcon) { + break; + } + // Add new feature icon, vertically centered with the text. - // TODO(crbug.com/1377384): Limit impressions of the icon. + [self.delegate accountStorageNewFeatureIconDidShow]; NSTextAttachment* iconAttachment = [[NSTextAttachment alloc] init]; iconAttachment.image = [PasswordSettingsViewController newFeatureIcon]; CGSize iconSize = iconAttachment.image.size; @@ -541,6 +549,10 @@ } } +- (void)setShowAccountStorageNewFeatureIcon:(BOOL)show { + _showAccountStorageNewFeatureIcon = show; +} + - (void)setPasswordsInOtherAppsEnabled:(BOOL)enabled { if (_passwordsInOtherAppsEnabled.has_value() && _passwordsInOtherAppsEnabled.value() == enabled) {
diff --git a/ios/chrome/browser/ui/settings/privacy/BUILD.gn b/ios/chrome/browser/ui/settings/privacy/BUILD.gn index cff714e3..51370a83 100644 --- a/ios/chrome/browser/ui/settings/privacy/BUILD.gn +++ b/ios/chrome/browser/ui/settings/privacy/BUILD.gn
@@ -121,6 +121,7 @@ deps = [ "//base/test:test_support", "//components/handoff", + "//components/policy/core/common:common_constants", "//components/prefs", "//components/prefs:test_support", "//components/prefs/ios",
diff --git a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm index 34a1b1c..062b731 100644 --- a/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm +++ b/ios/chrome/browser/ui/settings/privacy/privacy_table_view_controller_unittest.mm
@@ -13,6 +13,7 @@ #import "base/test/scoped_feature_list.h" #import "components/content_settings/core/common/features.h" #import "components/handoff/pref_names_ios.h" +#import "components/policy/core/common/policy_pref_names.h" #import "components/prefs/pref_service.h" #import "components/safe_browsing/core/common/features.h" #import "components/safe_browsing/core/common/safe_browsing_prefs.h" @@ -86,7 +87,7 @@ // Set Incognito Mode availability depending on test config. chrome_browser_state_->GetTestingPrefService()->SetManagedPref( - prefs::kIncognitoModeAvailability, + policy::policy_prefs::kIncognitoModeAvailability, std::make_unique<base::Value>( static_cast<int>(GetParam().incognitoModeAvailability))); }
diff --git a/ios/chrome/browser/ui/settings/sync/utils/sync_error_infobar_delegate.h b/ios/chrome/browser/ui/settings/sync/utils/sync_error_infobar_delegate.h index 4598d3ab..d7baec28 100644 --- a/ios/chrome/browser/ui/settings/sync/utils/sync_error_infobar_delegate.h +++ b/ios/chrome/browser/ui/settings/sync/utils/sync_error_infobar_delegate.h
@@ -48,6 +48,7 @@ // ConfirmInfoBarDelegate implementation. std::u16string GetMessageText() const override; + std::u16string GetTitleText() const override; int GetButtons() const override; std::u16string GetButtonLabel(InfoBarButton button) const override; bool UseIconBackgroundTint() const override; @@ -64,6 +65,7 @@ gfx::Image icon_; ChromeBrowserState* browser_state_; syncer::SyncService::UserActionableError error_state_; + std::u16string title_; std::u16string message_; std::u16string button_text_; id<SyncPresenter> presenter_;
diff --git a/ios/chrome/browser/ui/settings/sync/utils/sync_error_infobar_delegate.mm b/ios/chrome/browser/ui/settings/sync/utils/sync_error_infobar_delegate.mm index 4e5c732..0cfec128 100644 --- a/ios/chrome/browser/ui/settings/sync/utils/sync_error_infobar_delegate.mm +++ b/ios/chrome/browser/ui/settings/sync/utils/sync_error_infobar_delegate.mm
@@ -79,6 +79,7 @@ // Set all of the UI based on the sync state at the same time to ensure // they all correspond to the same sync error. error_state_ = sync_service->GetUserActionableError(); + title_ = GetSyncErrorInfoBarTitleForBrowserState(browser_state_); message_ = base::SysNSStringToUTF16( GetSyncErrorMessageForBrowserState(browser_state_)); button_text_ = base::SysNSStringToUTF16( @@ -103,6 +104,10 @@ return message_; } +std::u16string SyncErrorInfoBarDelegate::GetTitleText() const { + return title_; +} + int SyncErrorInfoBarDelegate::GetButtons() const { return button_text_.empty() ? BUTTON_NONE : BUTTON_OK; }
diff --git a/ios/chrome/browser/ui/settings/sync/utils/sync_util.h b/ios/chrome/browser/ui/settings/sync/utils/sync_util.h index 210b89a6..650a871 100644 --- a/ios/chrome/browser/ui/settings/sync/utils/sync_util.h +++ b/ios/chrome/browser/ui/settings/sync/utils/sync_util.h
@@ -23,6 +23,10 @@ NSString* GetSyncErrorDescriptionForSyncService( syncer::SyncService* syncService); +// Gets the title of the Sync error info bar. +std::u16string GetSyncErrorInfoBarTitleForBrowserState( + ChromeBrowserState* browserState); + // Gets the string message associated with the sync error state of // `browserState`. The returned error message does not contain any links. // Returns nil if there is no sync error.
diff --git a/ios/chrome/browser/ui/settings/sync/utils/sync_util.mm b/ios/chrome/browser/ui/settings/sync/utils/sync_util.mm index 8f3dfc7..2d3adac 100644 --- a/ios/chrome/browser/ui/settings/sync/utils/sync_util.mm +++ b/ios/chrome/browser/ui/settings/sync/utils/sync_util.mm
@@ -6,6 +6,7 @@ #import "base/feature_list.h" #import "base/metrics/histogram_macros.h" +#import "base/notreached.h" #import "components/infobars/core/infobar_manager.h" #import "components/signin/public/identity_manager/identity_manager.h" #import "components/strings/grit/components_strings.h" @@ -22,6 +23,7 @@ #import "ios/chrome/browser/sync/sync_service_factory.h" #import "ios/chrome/browser/ui/settings/settings_root_view_controlling.h" #import "ios/chrome/browser/ui/settings/sync/utils/account_error_ui_info.h" +#import "ios/chrome/browser/ui/settings/sync/utils/identity_error_util.h" #import "ios/chrome/browser/ui/settings/sync/utils/sync_error_infobar_delegate.h" #import "ios/chrome/grit/ios_chromium_strings.h" #import "ios/chrome/grit/ios_strings.h" @@ -51,6 +53,95 @@ kMaxValue = SYNC_TRUSTED_VAULT_RECOVERABILITY_DEGRADED, }; +// Returns true if the identity error info bar should be used instead of the +// Sync error info bar. Returns false for the case where +// SyncService::IsSyncFeatureEnabled() returns true, because +// GetAccountErrorUIInfo() is guaranteed to return nil. +bool UseIdentityErrorInfobar(syncer::SyncService* sync_service) { + DCHECK(sync_service); + + // TODO(crbug.com/1426861): Consider changing the way we detect that the Sync + // feature is enabled in GetAccountErrorUIInfo(). + return GetAccountErrorUIInfo(sync_service) != nil; +} + +// Gets the the title of the identity error info bar for the given `error`. +std::u16string GetIdentityErrorInfoBarTitle( + syncer::SyncService::UserActionableError error) { + switch (error) { + case syncer::SyncService::UserActionableError::kNeedsPassphrase: + return l10n_util::GetStringUTF16( + IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_PASSPHRASE_TITLE); + case syncer::SyncService::UserActionableError:: + kNeedsTrustedVaultKeyForPasswords: + case syncer::SyncService::UserActionableError:: + kNeedsTrustedVaultKeyForEverything: + case syncer::SyncService::UserActionableError:: + kTrustedVaultRecoverabilityDegradedForPasswords: + case syncer::SyncService::UserActionableError:: + kTrustedVaultRecoverabilityDegradedForEverything: + return l10n_util::GetStringUTF16( + IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_ITS_YOU_TITLE); + case syncer::SyncService::UserActionableError::kNone: + case syncer::SyncService::UserActionableError::kSignInNeedsUpdate: + case syncer::SyncService::UserActionableError::kGenericUnrecoverableError: + NOTREACHED_NORETURN(); + } +} + +// Gets the message of the identity error info bar. +NSString* GetIdentityErrorInfoBarMessage( + syncer::SyncService::UserActionableError error) { + switch (error) { + case syncer::SyncService::UserActionableError::kNeedsPassphrase: + return l10n_util::GetNSString( + IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE); + case syncer::SyncService::UserActionableError:: + kNeedsTrustedVaultKeyForPasswords: + return l10n_util::GetNSString( + IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_PASSWORDS_MESSAGE); + case syncer::SyncService::UserActionableError:: + kNeedsTrustedVaultKeyForEverything: + return l10n_util::GetNSString( + IDS_IOS_IDENTITY_ERROR_INFOBAR_KEEP_USING_YOUR_CHROME_DATA_MESSAGE); + case syncer::SyncService::UserActionableError:: + kTrustedVaultRecoverabilityDegradedForPasswords: + return l10n_util::GetNSString( + IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_PASSWORDS_MESSAGE); + case syncer::SyncService::UserActionableError:: + kTrustedVaultRecoverabilityDegradedForEverything: + return l10n_util::GetNSString( + IDS_IOS_IDENTITY_ERROR_INFOBAR_MAKE_SURE_YOU_CAN_ALWAYS_USE_CHROME_DATA_MESSAGE); + case syncer::SyncService::UserActionableError::kNone: + case syncer::SyncService::UserActionableError::kSignInNeedsUpdate: + case syncer::SyncService::UserActionableError::kGenericUnrecoverableError: + NOTREACHED_NORETURN(); + } +} + +NSString* GetIdentityErrorInfoBarButtonLabel( + syncer::SyncService::UserActionableError error) { + switch (error) { + case syncer::SyncService::UserActionableError::kNeedsPassphrase: + return l10n_util::GetNSString( + IDS_IOS_IDENTITY_ERROR_INFOBAR_ENTER_BUTTON_LABEL); + case syncer::SyncService::UserActionableError:: + kNeedsTrustedVaultKeyForPasswords: + case syncer::SyncService::UserActionableError:: + kNeedsTrustedVaultKeyForEverything: + case syncer::SyncService::UserActionableError:: + kTrustedVaultRecoverabilityDegradedForPasswords: + case syncer::SyncService::UserActionableError:: + kTrustedVaultRecoverabilityDegradedForEverything: + return l10n_util::GetNSString( + IDS_IOS_IDENTITY_ERROR_INFOBAR_VERIFY_BUTTON_LABEL); + case syncer::SyncService::UserActionableError::kNone: + case syncer::SyncService::UserActionableError::kSignInNeedsUpdate: + case syncer::SyncService::UserActionableError::kGenericUnrecoverableError: + NOTREACHED_NORETURN(); + } +} + } // namespace NSString* GetSyncErrorDescriptionForSyncService( @@ -86,11 +177,37 @@ } } +std::u16string GetSyncErrorInfoBarTitleForBrowserState( + ChromeBrowserState* browser_state) { + DCHECK(browser_state); + + syncer::SyncService* sync_service = + SyncServiceFactory::GetForBrowserState(browser_state); + DCHECK(sync_service); + + if (UseIdentityErrorInfobar(sync_service)) { + DCHECK(!sync_service->IsSyncFeatureEnabled()); + return GetIdentityErrorInfoBarTitle(sync_service->GetUserActionableError()); + } else { + // There is no title in Sync error info bar. + return std::u16string(); + } +} + NSString* GetSyncErrorMessageForBrowserState(ChromeBrowserState* browserState) { syncer::SyncService* syncService = SyncServiceFactory::GetForBrowserState(browserState); DCHECK(syncService); - switch (syncService->GetUserActionableError()) { + + const syncer::SyncService::UserActionableError error = + syncService->GetUserActionableError(); + + if (UseIdentityErrorInfobar(syncService)) { + DCHECK(!syncService->IsSyncFeatureEnabled()); + return GetIdentityErrorInfoBarMessage(error); + } + + switch (error) { case syncer::SyncService::UserActionableError::kNone: return nil; case syncer::SyncService::UserActionableError::kSignInNeedsUpdate: @@ -113,10 +230,21 @@ NSString* GetSyncErrorButtonTitleForBrowserState( ChromeBrowserState* browserState) { + DCHECK(browserState); + syncer::SyncService* syncService = SyncServiceFactory::GetForBrowserState(browserState); DCHECK(syncService); - switch (syncService->GetUserActionableError()) { + + const syncer::SyncService::UserActionableError error = + syncService->GetUserActionableError(); + + if (UseIdentityErrorInfobar(syncService)) { + DCHECK(!syncService->IsSyncFeatureEnabled()); + return GetIdentityErrorInfoBarButtonLabel(error); + } + + switch (error) { case syncer::SyncService::UserActionableError::kSignInNeedsUpdate: return l10n_util::GetNSString(IDS_IOS_SYNC_UPDATE_CREDENTIALS_BUTTON); case syncer::SyncService::UserActionableError::kNeedsPassphrase: @@ -169,18 +297,24 @@ return false; } - // Avoid showing the sync error inforbar when sync changes are still pending. - // This is particularely requires during first run when the advanced sign-in - // settings are being presented on the NTP before sync changes being - // committed. - if (syncService->IsSetupInProgress()) { - return false; - } + if (!UseIdentityErrorInfobar(syncService)) { + // If the identity error info bar isn't used, fallback to the Sync error + // info bar. - signin::IdentityManager* identityManager = - IdentityManagerFactory::GetForBrowserState(browser_state); - if (!identityManager->HasPrimaryAccount(signin::ConsentLevel::kSync)) - return false; + // Avoid showing the sync error info bar when sync changes are still + // pending. This is particularely requires during first run when the + // advanced sign-in settings are being presented on the NTP before sync + // changes being committed. + if (syncService->IsSetupInProgress()) { + return false; + } + + signin::IdentityManager* identityManager = + IdentityManagerFactory::GetForBrowserState(browser_state); + if (!identityManager->HasPrimaryAccount(signin::ConsentLevel::kSync)) { + return false; + } + } // Logs when an infobar is shown to user. See crbug/265352. InfobarSyncError loggedErrorState;
diff --git a/media/DEPS b/media/DEPS index b4998ce..88da8ba 100644 --- a/media/DEPS +++ b/media/DEPS
@@ -4,6 +4,7 @@ "+cc/paint", "+components/crash/core/common/crash_key.h", "+components/system_media_controls/linux/buildflags", + "+components/viz/common/resources", "+crypto", "+device/udev_linux", "+gpu",
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 2f0c13c2..6173b83 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -508,6 +508,12 @@ "MemoryPressureBasedSourceBufferGC", base::FEATURE_DISABLED_BY_DEFAULT); +// Enables creating single shared image and mailbox for multi-planar formats for +// hardware video decoders. +BASE_FEATURE(kUseMultiPlaneFormatForHardwareVideo, + "UseMultiPlaneFormatForHardwareVideo", + base::FEATURE_DISABLED_BY_DEFAULT); + // Enables binding software video NV12/P010 GMBs as separate shared images. BASE_FEATURE(kMultiPlaneSoftwareVideoSharedImages, "MultiPlaneSoftwareVideoSharedImages",
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index 51a5916..b482800 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -243,6 +243,7 @@ MEDIA_EXPORT BASE_DECLARE_FEATURE(kMediaOptimizer); MEDIA_EXPORT BASE_DECLARE_FEATURE(kMediaPowerExperiment); MEDIA_EXPORT BASE_DECLARE_FEATURE(kMemoryPressureBasedSourceBufferGC); +MEDIA_EXPORT BASE_DECLARE_FEATURE(kUseMultiPlaneFormatForHardwareVideo); MEDIA_EXPORT BASE_DECLARE_FEATURE(kMultiPlaneSoftwareVideoSharedImages); MEDIA_EXPORT BASE_DECLARE_FEATURE(kMultiPlaneVideoCaptureSharedImages); MEDIA_EXPORT BASE_DECLARE_FEATURE(kOpenscreenCastStreamingSession);
diff --git a/media/gpu/ipc/service/picture_buffer_manager.cc b/media/gpu/ipc/service/picture_buffer_manager.cc index 5e96015e..0d76f42 100644 --- a/media/gpu/ipc/service/picture_buffer_manager.cc +++ b/media/gpu/ipc/service/picture_buffer_manager.cc
@@ -320,6 +320,8 @@ frame->set_color_space(picture.color_space()); + frame->set_shared_image_format_type(picture.shared_image_format_type()); + frame->metadata().allow_overlay = picture.allow_overlay(); frame->metadata().read_lock_fences_enabled = picture.read_lock_fences_enabled();
diff --git a/media/gpu/mac/BUILD.gn b/media/gpu/mac/BUILD.gn index 33b29e5..0b6717f0 100644 --- a/media/gpu/mac/BUILD.gn +++ b/media/gpu/mac/BUILD.gn
@@ -40,6 +40,7 @@ deps = [ "//base", "//components/crash/core/common:crash_key", + "//components/viz/common:resource_format", "//gpu/command_buffer/service:gles2", "//gpu/ipc/service", "//media",
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.cc b/media/gpu/mac/vt_video_decode_accelerator_mac.cc index 715d5dc..16a8fce9 100644 --- a/media/gpu/mac/vt_video_decode_accelerator_mac.cc +++ b/media/gpu/mac/vt_video_decode_accelerator_mac.cc
@@ -40,11 +40,11 @@ #include "base/trace_event/process_memory_dump.h" #include "base/version.h" #include "components/crash/core/common/crash_key.h" -#include "components/viz/common/resources/resource_format_utils.h" #include "gpu/command_buffer/common/gpu_memory_buffer_support.h" #include "gpu/command_buffer/common/mailbox.h" #include "gpu/command_buffer/common/shared_image_usage.h" #include "gpu/command_buffer/service/shared_image/shared_image_factory.h" +#include "gpu/config/gpu_finch_features.h" #include "gpu/ipc/service/shared_image_stub.h" #include "media/base/limits.h" #include "media/base/mac/color_space_util_mac.h" @@ -521,6 +521,29 @@ vda->Output(source_frame_refcon, status, image_buffer); } +gfx::BufferFormat ToBufferFormat(viz::SharedImageFormat format) { + DCHECK(format.is_multi_plane()); + if (format == viz::MultiPlaneFormat::kYVU_420) { + return gfx::BufferFormat::YVU_420; + } + if (format == viz::MultiPlaneFormat::kYUV_420_BIPLANAR) { + return gfx::BufferFormat::YUV_420_BIPLANAR; + } + if (format == viz::MultiPlaneFormat::kYUVA_420_TRIPLANAR) { + return gfx::BufferFormat::YUVA_420_TRIPLANAR; + } + if (format == viz::MultiPlaneFormat::kP010) { + return gfx::BufferFormat::P010; + } + NOTREACHED(); + return gfx::BufferFormat::RGBA_8888; +} + +bool MultiPlaneFormatForHardwareVideoEnabled() { + return base::FeatureList::IsEnabled(features::kPassthroughYuvRgbConversion) && + base::FeatureList::IsEnabled(kUseMultiPlaneFormatForHardwareVideo); +} + } // namespace // Detects coded size and color space changes. Also indicates when a frame won't @@ -2173,15 +2196,15 @@ picture_size_ = frame.image_size; if (has_alpha_) { - buffer_format_ = gfx::BufferFormat::YUVA_420_TRIPLANAR; + si_format_ = viz::MultiPlaneFormat::kYUVA_420_TRIPLANAR; picture_format_ = PIXEL_FORMAT_NV12A; } else if (config_.profile == VP9PROFILE_PROFILE2 || config_.profile == HEVCPROFILE_MAIN10 || config_.profile == HEVCPROFILE_REXT) { - buffer_format_ = gfx::BufferFormat::P010; + si_format_ = viz::MultiPlaneFormat::kP010; picture_format_ = PIXEL_FORMAT_P016LE; } else { - buffer_format_ = gfx::BufferFormat::YUV_420_BIPLANAR; + si_format_ = viz::MultiPlaneFormat::kYUV_420_BIPLANAR; picture_format_ = PIXEL_FORMAT_NV12; } @@ -2212,20 +2235,24 @@ const gfx::ColorSpace color_space = GetImageBufferColorSpace(frame.image); std::vector<gfx::BufferPlane> planes; - switch (picture_format_) { - case PIXEL_FORMAT_NV12: - case PIXEL_FORMAT_P016LE: - planes.push_back(gfx::BufferPlane::Y); - planes.push_back(gfx::BufferPlane::UV); - break; - case PIXEL_FORMAT_NV12A: - planes.push_back(gfx::BufferPlane::Y); - planes.push_back(gfx::BufferPlane::UV); - planes.push_back(gfx::BufferPlane::A); - break; - default: - NOTREACHED(); - break; + if (MultiPlaneFormatForHardwareVideoEnabled()) { + planes.push_back(gfx::BufferPlane::DEFAULT); + } else { + switch (picture_format_) { + case PIXEL_FORMAT_NV12: + case PIXEL_FORMAT_P016LE: + planes.push_back(gfx::BufferPlane::Y); + planes.push_back(gfx::BufferPlane::UV); + break; + case PIXEL_FORMAT_NV12A: + planes.push_back(gfx::BufferPlane::Y); + planes.push_back(gfx::BufferPlane::UV); + planes.push_back(gfx::BufferPlane::A); + break; + default: + NOTREACHED(); + break; + } } for (size_t plane = 0; plane < planes.size(); ++plane) { if (picture_info->uses_shared_images) { @@ -2254,10 +2281,17 @@ base::scoped_policy::RETAIN); gpu::Mailbox mailbox = gpu::Mailbox::GenerateForSharedImage(); - bool success = shared_image_stub->CreateSharedImage( - mailbox, std::move(handle), buffer_format_, planes[plane], frame_size, - color_space, kTopLeft_GrSurfaceOrigin, kOpaque_SkAlphaType, - shared_image_usage); + bool success; + if (MultiPlaneFormatForHardwareVideoEnabled()) { + success = shared_image_stub->CreateSharedImage( + mailbox, std::move(handle), si_format_, frame_size, color_space, + kTopLeft_GrSurfaceOrigin, kOpaque_SkAlphaType, shared_image_usage); + } else { + success = shared_image_stub->CreateSharedImage( + mailbox, std::move(handle), ToBufferFormat(si_format_), + planes[plane], frame_size, color_space, kTopLeft_GrSurfaceOrigin, + kOpaque_SkAlphaType, shared_image_usage); + } if (!success) { DLOG(ERROR) << "Failed to create shared image"; NotifyError(PLATFORM_FAILURE, SFT_PLATFORM_ERROR); @@ -2287,7 +2321,7 @@ CVPixelBufferGetWidthOfPlane(frame.image.get(), plane), CVPixelBufferGetHeightOfPlane(frame.image.get(), plane)); gfx::BufferFormat plane_buffer_format = - gpu::GetPlaneBufferFormat(planes[plane], buffer_format_); + gpu::GetPlaneBufferFormat(planes[plane], ToBufferFormat(si_format_)); scoped_refptr<GLImageIOSurface> gl_image( GLImageIOSurface::Create(plane_size)); @@ -2328,7 +2362,12 @@ picture.set_read_lock_fences_enabled(true); if (frame.hdr_metadata) picture.set_hdr_metadata(frame.hdr_metadata); + if (MultiPlaneFormatForHardwareVideoEnabled()) { + picture.set_shared_image_format_type( + SharedImageFormatType::kSharedImageFormat); + } if (picture_info->uses_shared_images) { + // For multiplanar shared images, planes.size() is 1. for (size_t plane = 0; plane < planes.size(); ++plane) { picture.set_scoped_shared_image(picture_info->scoped_shared_images[plane], plane);
diff --git a/media/gpu/mac/vt_video_decode_accelerator_mac.h b/media/gpu/mac/vt_video_decode_accelerator_mac.h index de5b59a8..0ebf7086 100644 --- a/media/gpu/mac/vt_video_decode_accelerator_mac.h +++ b/media/gpu/mac/vt_video_decode_accelerator_mac.h
@@ -23,6 +23,7 @@ #include "base/task/single_thread_task_runner.h" #include "base/threading/thread_checker.h" #include "base/trace_event/memory_dump_provider.h" +#include "components/viz/common/resources/shared_image_format.h" #include "gpu/config/gpu_driver_bug_workarounds.h" #include "media/base/media_log.h" #include "media/gpu/gpu_video_decode_accelerator_helpers.h" @@ -275,8 +276,8 @@ // Format of the assigned picture buffers. VideoPixelFormat picture_format_ = PIXEL_FORMAT_UNKNOWN; - // Corresponding GpuMemoryBuffer format. - gfx::BufferFormat buffer_format_ = gfx::BufferFormat::YUV_420_BIPLANAR; + // Corresponding SharedImageFormat. + viz::SharedImageFormat si_format_ = viz::MultiPlaneFormat::kYUV_420_BIPLANAR; // Frames that have not yet been decoded, keyed by bitstream ID; maintains // ownership of Frame objects while they flow through VideoToolbox.
diff --git a/media/video/picture.h b/media/video/picture.h index 4f3bf02..f97a0a1 100644 --- a/media/video/picture.h +++ b/media/video/picture.h
@@ -186,6 +186,14 @@ bool is_webgpu_compatible() { return is_webgpu_compatible_; } + SharedImageFormatType shared_image_format_type() const { + return shared_image_format_type_; + } + + void set_shared_image_format_type(SharedImageFormatType type) { + shared_image_format_type_ = type; + } + private: int32_t picture_buffer_id_; int32_t bitstream_buffer_id_; @@ -198,6 +206,8 @@ bool texture_owner_; bool wants_promotion_hint_; bool is_webgpu_compatible_; + SharedImageFormatType shared_image_format_type_ = + SharedImageFormatType::kLegacy; std::array<scoped_refptr<ScopedSharedImage>, VideoFrame::kMaxPlanes> scoped_shared_images_; };
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index 965f7df7..9b387c1 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -50745,7 +50745,6 @@ { "name": "iwantexchange.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jackassofalltrades.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jamesclark.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, - { "name": "janelauhomes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jclynne.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jeffrhinelander.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true }, { "name": "jennierobinson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
diff --git a/printing/backend/cups_printer.cc b/printing/backend/cups_printer.cc index 1e0707c..dc2d4d2 100644 --- a/printing/backend/cups_printer.cc +++ b/printing/backend/cups_printer.cc
@@ -30,10 +30,20 @@ DCHECK(cups_http_); DCHECK(destination_); - printer_uri_ = cupsGetOption(kCUPSOptPrinterUriSupported, - destination_.get()->num_options, - destination_.get()->options); - resource_path_ = std::string(GURL(printer_uri_).path_piece()); + const char* printer_uri = cupsGetOption(kCUPSOptPrinterUriSupported, + destination_.get()->num_options, + destination_.get()->options); + + // crbug.com/1418564: Every printer *should* have a "printer-uri-supported" + // attribute, but make sure Chromium doesn't crash if one doesn't for + // whatever reason. The printer in question won't actually work, but + // that's a better outcome than crashing here. + // TODO(crbug.com/1418564): filter such printers out before reaching this + // point + if (printer_uri) { + printer_uri_ = printer_uri; + resource_path_ = std::string(GURL(printer_uri_).path_piece()); + } } CupsPrinterImpl(const CupsPrinterImpl&) = delete;
diff --git a/services/network/public/mojom/trust_token_access_observer.mojom b/services/network/public/mojom/trust_token_access_observer.mojom index 82e04af..b6b08a7 100644 --- a/services/network/public/mojom/trust_token_access_observer.mojom +++ b/services/network/public/mojom/trust_token_access_observer.mojom
@@ -4,8 +4,6 @@ module network.mojom; -import "sandbox/policy/mojom/context.mojom"; -import "services/network/public/mojom/trust_tokens.mojom"; import "url/mojom/origin.mojom"; union TrustTokenAccessDetails {
diff --git a/services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h b/services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h index 27a6912..435783c 100644 --- a/services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h +++ b/services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h
@@ -5,6 +5,7 @@ #ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SHARED_QUAD_STATE_MOJOM_TRAITS_H_ #define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SHARED_QUAD_STATE_MOJOM_TRAITS_H_ +#include "base/check_op.h" #include "base/memory/raw_ptr.h" #include "components/viz/common/quads/shared_quad_state.h" #include "services/viz/public/mojom/compositing/shared_quad_state.mojom-shared.h" @@ -68,6 +69,10 @@ return input.sqs->sorting_context_id; } + static uint32_t layer_id(const OptSharedQuadState& input) { + return input.sqs->layer_id; + } + static bool is_fast_rounded_corner(const OptSharedQuadState& input) { return input.sqs->is_fast_rounded_corner; } @@ -113,6 +118,10 @@ return sqs.sorting_context_id; } + static uint32_t layer_id(const viz::SharedQuadState& sqs) { + return sqs.layer_id; + } + static bool is_fast_rounded_corner(const viz::SharedQuadState& sqs) { return sqs.is_fast_rounded_corner; } @@ -135,10 +144,12 @@ out->are_contents_opaque = data.are_contents_opaque(); out->opacity = data.opacity(); - if (data.blend_mode() > static_cast<int>(SkBlendMode::kLastMode)) + if (data.blend_mode() > static_cast<int>(SkBlendMode::kLastMode)) { return false; + } out->blend_mode = static_cast<SkBlendMode>(data.blend_mode()); out->sorting_context_id = data.sorting_context_id(); + out->layer_id = data.layer_id(); out->is_fast_rounded_corner = data.is_fast_rounded_corner(); return true;
diff --git a/services/viz/public/mojom/compositing/shared_quad_state.mojom b/services/viz/public/mojom/compositing/shared_quad_state.mojom index b143c88..5d76b47 100644 --- a/services/viz/public/mojom/compositing/shared_quad_state.mojom +++ b/services/viz/public/mojom/compositing/shared_quad_state.mojom
@@ -37,7 +37,7 @@ // supported. uint32 blend_mode; int32 sorting_context_id; + uint32 layer_id; bool is_fast_rounded_corner; - };
diff --git a/testing/buildbot/README.md b/testing/buildbot/README.md index 28ce834b..7ff51e2 100644 --- a/testing/buildbot/README.md +++ b/testing/buildbot/README.md
@@ -115,7 +115,7 @@ resource request. Depending on resources, the resource owners may not approve of the request. In which case, see step #5. 1. Calculate the amount of machine resources needed for the tests. Googlers - can use [this dashboard](http://shortn/_nyyTPgDJtF) to determine the + can use [this dashboard](http://shortn/_X75IFjffFk) to determine the amount of bots required by comparing it to a similar suite on the same builder. Do this for each CQ builder and each suite that's being added. 2. File a [resource request](http://go/file-chrome-resource-bug) for the @@ -130,8 +130,8 @@ explaining why. This can be revisited if things change. If your change doesn't affect the CQ but is expected to increase utilization in -the testing pools by any more than 5 VMs or 50 CPU cores, it will still need to -be approved via a resource request. Consult the +the testing pools by any more than 5 VMs or 50 CPU cores per hour, it will still +need to be approved via a resource request. Consult the [dashboard](http://shortn/_nyyTPgDJtF) linked above to calculate the resource usage of a test change. See http://go/i-need-hw for the steps involved in getting the approval.
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json index 043a544..48e0c87a 100644 --- a/testing/buildbot/chromium.android.fyi.json +++ b/testing/buildbot/chromium.android.fyi.json
@@ -154,7 +154,6 @@ "--avd-config=../../tools/android/avd/proto/generic_android28.textpb", "--use-upstream-wpt" ], - "experiment_percentage": 100, "isolate_name": "chrome_public_wpt", "merge": { "args": [ @@ -1313,7 +1312,6 @@ "--log-wptreport", "--use-upstream-wpt" ], - "experiment_percentage": 100, "isolate_name": "system_webview_wpt", "merge": { "args": [
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json index 782bf50..eead1de5 100644 --- a/testing/buildbot/chromium.chromiumos.json +++ b/testing/buildbot/chromium.chromiumos.json
@@ -5886,9 +5886,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "isolate_profile_data": true, "merge": { "args": [], @@ -5900,8 +5900,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -6057,9 +6057,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "isolate_profile_data": true, "merge": { "args": [], @@ -6071,8 +6071,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -6209,9 +6209,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "isolate_profile_data": true, "merge": { "args": [], @@ -6223,8 +6223,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.coverage.json b/testing/buildbot/chromium.coverage.json index d7b40f5..0729984 100644 --- a/testing/buildbot/chromium.coverage.json +++ b/testing/buildbot/chromium.coverage.json
@@ -25631,9 +25631,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "isolate_profile_data": true, "merge": { "args": [], @@ -25645,8 +25645,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -25802,9 +25802,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "isolate_profile_data": true, "merge": { "args": [], @@ -25816,8 +25816,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -25954,9 +25954,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "isolate_profile_data": true, "merge": { "args": [], @@ -25968,8 +25968,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 4d05af10..81aa77b9 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -50174,9 +50174,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -50187,8 +50187,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -50345,9 +50345,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -50358,8 +50358,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -50497,9 +50497,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -50510,8 +50510,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -52017,9 +52017,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -52030,8 +52030,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -52188,9 +52188,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -52201,8 +52201,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -52340,9 +52340,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -52353,8 +52353,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -53108,9 +53108,9 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome" + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "merge": { "args": [], "script": "//testing/merge_scripts/standard_gtest_merge.py" @@ -53121,8 +53121,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json index 97ddcb7..267ebea 100644 --- a/testing/buildbot/chromium.memory.json +++ b/testing/buildbot/chromium.memory.json
@@ -18414,12 +18414,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.filter;../../testing/buildbot/filters/linux-lacros.interactive_ui_tests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "isolate_profile_data": true, "merge": { "args": [], @@ -18431,8 +18431,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -18605,12 +18605,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "isolate_profile_data": true, "merge": { "args": [], @@ -18622,8 +18622,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [ @@ -18772,12 +18772,12 @@ { "args": [ "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter", - "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome", + "--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome", "--test-launcher-print-test-stdio=always", "--combine-ash-logs-on-bots", "--asan-symbolize-output" ], - "description": "Run with ash-chrome version 113.0.5668.0", + "description": "Run with ash-chrome version 113.0.5669.0", "isolate_profile_data": true, "merge": { "args": [], @@ -18789,8 +18789,8 @@ "cipd_packages": [ { "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip", - "location": "lacros_version_skew_tests_v113.0.5668.0", - "revision": "version:113.0.5668.0" + "location": "lacros_version_skew_tests_v113.0.5669.0", + "revision": "version:113.0.5669.0" } ], "dimension_sets": [
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 47d1f16..530af15 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -3693,6 +3693,9 @@ }, 'system_webview_wpt': { 'modifications': { + 'android-pie-arm64-wpt-rel-non-cq': { + 'experiment_percentage': 100, + }, 'android-webview-pie-x86-wpt-fyi-rel': { 'args': [ '--log-wptreport',
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl index 78f001da..c5e1bf6e 100644 --- a/testing/buildbot/test_suites.pyl +++ b/testing/buildbot/test_suites.pyl
@@ -546,7 +546,6 @@ 'expiration': 18000, 'hard_timeout': 14400, }, - 'experiment_percentage': 100, 'merge': { 'args': [ '--verbose', @@ -5105,7 +5104,6 @@ 'expiration': 18000, 'hard_timeout': 14400, }, - 'experiment_percentage': 100, 'merge': { 'args': [ '--verbose',
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl index 4a55d72d..cbf2fba12 100644 --- a/testing/buildbot/variants.pyl +++ b/testing/buildbot/variants.pyl
@@ -22,16 +22,16 @@ }, 'LACROS_VERSION_SKEW_CANARY': { 'args': [ - '--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5668.0/test_ash_chrome', + '--ash-chrome-path-override=../../lacros_version_skew_tests_v113.0.5669.0/test_ash_chrome', ], - 'description': 'Run with ash-chrome version 113.0.5668.0', + 'description': 'Run with ash-chrome version 113.0.5669.0', 'identifier': 'Lacros version skew testing ash canary', 'swarming': { 'cipd_packages': [ { 'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip', - 'location': 'lacros_version_skew_tests_v113.0.5668.0', - 'revision': 'version:113.0.5668.0', + 'location': 'lacros_version_skew_tests_v113.0.5669.0', + 'revision': 'version:113.0.5669.0', }, ], },
diff --git a/testing/libfuzzer/OWNERS b/testing/libfuzzer/OWNERS index e9c93c89..6d21130 100644 --- a/testing/libfuzzer/OWNERS +++ b/testing/libfuzzer/OWNERS
@@ -1,3 +1,4 @@ -metzman@chromium.org +adetaylor@chromium.org bookholt@chromium.org +metzman@chromium.org tiszka@chromium.org
diff --git a/testing/libfuzzer/README.md b/testing/libfuzzer/README.md index 1222e2dc..9b3b62b 100644 --- a/testing/libfuzzer/README.md +++ b/testing/libfuzzer/README.md
@@ -44,6 +44,7 @@ * [AFL integration] with Chromium and ClusterFuzz. * [Detailed references] for other integration parts. * Writing fuzzers for the [non-browser parts of Chrome OS]. +* [Fuzzing browsertests] if you need to fuzz multiple Chrome subsystems. ## Trophies * [Issues automatically filed] by ClusterFuzz. @@ -66,6 +67,7 @@ [Creating a fuzz target that expects a protobuf]: libprotobuf-mutator.md [Detailed references]: reference.md [Fuzzing]: https://en.wikipedia.org/wiki/Fuzzing +[Fuzzing browsertests]: fuzzing_browsertests.md [Fuzzing mojo interfaces]: ../../mojo/docs/mojolpm.md [Getting Started Guide]: getting_started.md [Guided in-process fuzzing of Chrome components]: https://security.googleblog.com/2016/08/guided-in-process-fuzzing-of-chrome.html
diff --git a/testing/libfuzzer/fuzzer_test.gni b/testing/libfuzzer/fuzzer_test.gni index 59737d24..f9ab5fe 100644 --- a/testing/libfuzzer/fuzzer_test.gni +++ b/testing/libfuzzer/fuzzer_test.gni
@@ -26,6 +26,7 @@ # - seed_corpus - a directory with seed corpus. # - seed_corpus_deps - dependencies for generating the seed corpus. # - grammar_options - defines a grammar used by a grammar based mutator. +# - exclude_main - if you're going to provide your own 'main' function # # If use_libfuzzer gn flag is defined, then proper fuzzer would be build. # Without use_libfuzzer or use_afl a unit-test style binary would be built on @@ -39,7 +40,12 @@ if (!disable_libfuzzer && use_fuzzing_engine) { assert(defined(invoker.sources), "Need sources in $target_name.") - test_deps = [ "//testing/libfuzzer:fuzzing_engine_main" ] + test_deps = [] + if (defined(invoker.exclude_main) && invoker.exclude_main) { + test_deps += [ "//testing/libfuzzer:fuzzing_engine_no_main" ] + } else { + test_deps += [ "//testing/libfuzzer:fuzzing_engine_main" ] + } test_data_deps = [] if (defined(invoker.deps)) {
diff --git a/testing/libfuzzer/fuzzing_browsertests.md b/testing/libfuzzer/fuzzing_browsertests.md new file mode 100644 index 0000000..8eca6706 --- /dev/null +++ b/testing/libfuzzer/fuzzing_browsertests.md
@@ -0,0 +1,52 @@ +# Fuzzing browsertests + +Fuzzing is effective if either: + +* it's guided by code coverage, and can execute incredible numbers of test cases + per second to explore the codebase (thousands); or +* it has a smart mutator of some kind (out of scope here). + +If you have an API to be fuzzed, make a simple libfuzzer fuzzer for just that +API, to get the speed required to explore its attack surface. If however we want +to fuzz a larger, more complex set of Chromium code, we usually need an entire +browser process environment around us. The browser process takes seconds to +start, preventing coverage guided fuzzing from being effective. + +We now have an experimental 'in process fuzz test' framework which attempts to: +* Start the browser process _once_ +* Execute lots of fuzz cases in that pre-existing browser. +This _may_ amortize the start up cost sufficiently to make such coverage-guided +fuzzing plausible. We don't yet know. But this document shows how to use it, +just in case. + +# Writing an in process fuzz case + +* Use the template `chrome/test/in_process_fuzz_test.gni` +* Provide a source code file which inherits from `InProcessFuzzTest`. This + must override the `Fuzz` method. You'll find that your base class inherits + from the full browser test infrastructure, so you can do anything you'd + do in a normal Chrome browser test. +* In your `cc` file, also use the macro `REGISTER_IN_PROCESS_FUZZER` to + declare that this is the one and only such fuzzer in your executable. + +# Running such an in process fuzz case + +These cases can be run either with libfuzzer or centipede. + +For libfuzzer, provide gn arguments `use_sanitizer_coverage = true`, +`use_libfuzzer = true`, `is_component_build = false` and `is_asan = true` +(other permutations may work). + +This will give you a single binary you can run like this: +`my_fuzzer /tmp/corpus -rss_limit_mb=81920` + +However, you'll more likely want to use +[centipede](https://github.com/google/centipede) which has an +out-of-process co-ordinator. + +To use centipede, specify `use_centipede = true` instead of `use_libfuzzer = +true`. You'll then want to run centipede using some command like: + +``` +export ASAN_OPTIONS=detect_odr_violations=0 $BIN_DIR/centipede --binary=~/chromium/src/out/ASAN/html_in_process_fuzz_tests --workdir=$WD --shmem_size_mb 4096 --rss_limit_mb 0 --batch_size 100 --log_features_shards 2 --exit_on_crash 1 +```
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index a3393c9..8cd1a7ae 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -14744,5 +14744,20 @@ } ] } + ], + "ZeroCopyTabCaptureStudyWin": [ + { + "platforms": [ + "windows" + ], + "experiments": [ + { + "name": "Enabled_20230222", + "enable_features": [ + "ZeroCopyTabCapture" + ] + } + ] + } ] }
diff --git a/third_party/androidx_javascriptengine/BUILD.gn b/third_party/androidx_javascriptengine/BUILD.gn index 2977dc7..204eead7 100644 --- a/third_party/androidx_javascriptengine/BUILD.gn +++ b/third_party/androidx_javascriptengine/BUILD.gn
@@ -13,6 +13,7 @@ android_aidl("js_sandbox_aidl") { import_include = [ "src/main/aidl" ] sources = [ + "src/main/aidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxConsoleCallback.aidl", "src/main/aidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolate.aidl", "src/main/aidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateCallback.aidl", "src/main/aidl/org/chromium/android_webview/js_sandbox/common/IJsSandboxIsolateSyncCallback.aidl", @@ -38,6 +39,7 @@ "src/main/java/androidx/javascriptengine/ExecutionErrorTypes.java", "src/main/java/androidx/javascriptengine/IsolateStartupParameters.java", "src/main/java/androidx/javascriptengine/IsolateTerminatedException.java", + "src/main/java/androidx/javascriptengine/JavaScriptConsoleCallback.java", "src/main/java/androidx/javascriptengine/JavaScriptException.java", "src/main/java/androidx/javascriptengine/JavaScriptIsolate.java", "src/main/java/androidx/javascriptengine/JavaScriptSandbox.java",
diff --git a/third_party/blink/common/DEPS b/third_party/blink/common/DEPS index 40bf560cf..56a66d24 100644 --- a/third_party/blink/common/DEPS +++ b/third_party/blink/common/DEPS
@@ -17,6 +17,7 @@ "+services/metrics/public/mojom/ukm_interface.mojom.h", "+services/network/public/cpp", "+services/network/public/mojom/content_security_policy.mojom.h", + "+services/network/public/mojom/content_security_policy.mojom-forward.h", "+services/network/public/mojom/fetch_api.mojom-shared.h", "+services/network/public/mojom/parsed_headers.mojom.h", "+services/network/public/mojom/referrer_policy.mojom.h",
diff --git a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc index 7ad2f84e..feecdca75 100644 --- a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc +++ b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards.cc
@@ -17,8 +17,8 @@ const url::Origin& origin, bool has_subdomain_wildcard) : origin(origin), has_subdomain_wildcard(has_subdomain_wildcard) { - // Origins that do have wildcards cannot be opaque. - DCHECK(!origin.opaque() || !has_subdomain_wildcard); + // Origins cannot be opaque. + DCHECK(!origin.opaque()); } OriginWithPossibleWildcards::OriginWithPossibleWildcards( @@ -30,7 +30,7 @@ OriginWithPossibleWildcards::~OriginWithPossibleWildcards() = default; // static -OriginWithPossibleWildcards OriginWithPossibleWildcards::Parse( +absl::optional<OriginWithPossibleWildcards> OriginWithPossibleWildcards::Parse( const std::string& allowlist_entry, const NodeType type) { auto wildcard_pos = std::string::npos; @@ -50,7 +50,7 @@ if (parsed_origin.opaque()) { // We early return here assuming even with the `*.` the origin parses // opaque. - return OriginWithPossibleWildcards(); + return absl::nullopt; } else if ( net::registry_controlled_domains::HostHasRegistryControlledDomain( parsed_origin.host(), @@ -64,7 +64,7 @@ // valid. Invalid strings will produce an opaque origin. const auto parsed_origin = url::Origin::Create(GURL(allowlist_entry)); if (parsed_origin.opaque()) { - return OriginWithPossibleWildcards(); + return absl::nullopt; } else { return OriginWithPossibleWildcards(parsed_origin, /*has_subdomain_wildcard=*/false); @@ -72,6 +72,7 @@ } std::string OriginWithPossibleWildcards::Serialize() const { + DCHECK(!origin.opaque()); auto wildcard_pos = std::string::npos; auto serialized_origin = origin.Serialize(); if (has_subdomain_wildcard && @@ -86,6 +87,7 @@ bool OriginWithPossibleWildcards::DoesMatchOrigin( const url::Origin& match_origin) const { + DCHECK(!origin.opaque()); if (has_subdomain_wildcard) { // This function won't match https://*.foo.com with https://foo.com. if (origin == match_origin) {
diff --git a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards_unittest.cc b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards_unittest.cc index 404f0b6..afdb4d29 100644 --- a/third_party/blink/common/permissions_policy/origin_with_possible_wildcards_unittest.cc +++ b/third_party/blink/common/permissions_policy/origin_with_possible_wildcards_unittest.cc
@@ -6,9 +6,9 @@ #include "base/test/gtest_util.h" #include "mojo/public/cpp/test_support/test_utils.h" +#include "services/network/public/mojom/content_security_policy.mojom.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.h" -#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom.h" #include "url/gurl.h" #include "url/origin.h" @@ -33,14 +33,9 @@ std::make_tuple(url::Origin::Create(GURL("https://foo.com")), url::Origin::Create(GURL("https://bar.foo.com")), false, false, "Different subdomain, no wildcard"), - std::make_tuple(url::Origin::Create(GURL("https://foo.com")), - url::Origin(), false, false, - "Origin to opaque, no wildcard"), std::make_tuple(url::Origin(), url::Origin::Create(GURL("https://foo.com")), false, false, "Opaque to origin, no wildcard"), - std::make_tuple(url::Origin(), url::Origin(), false, false, - "Opaque to opaque, no wildcard"), std::make_tuple(url::Origin::Create(GURL("file:///test")), url::Origin::Create(GURL("file:///test")), false, true, "File, no wildcard"), @@ -119,10 +114,10 @@ "https://%2A.foo.com", false, "Origin with subdomain wildcard in attribute"), std::make_tuple("*://foo.com", - OriginWithPossibleWildcards::NodeType::kHeader, "null", - false, "Origin with scheme wildcard in header"), + OriginWithPossibleWildcards::NodeType::kHeader, "", false, + "Origin with scheme wildcard in header"), std::make_tuple("*://foo.com", - OriginWithPossibleWildcards::NodeType::kAttribute, "null", + OriginWithPossibleWildcards::NodeType::kAttribute, "", false, "Origin with scheme wildcard in attribute"), std::make_tuple( "https://*", OriginWithPossibleWildcards::NodeType::kHeader, @@ -164,10 +159,10 @@ "https://%2A.example.test", false, "Origin with unknown tld host wildcard in attribute"), std::make_tuple("https://foo.com:*", - OriginWithPossibleWildcards::NodeType::kHeader, "null", - false, "Origin with port wildcard in header"), + OriginWithPossibleWildcards::NodeType::kHeader, "", false, + "Origin with port wildcard in header"), std::make_tuple("https://foo.com:*", - OriginWithPossibleWildcards::NodeType::kAttribute, "null", + OriginWithPossibleWildcards::NodeType::kAttribute, "", false, "Origin with port wildcard in attribute"), std::make_tuple("https://bar.*.foo.com", OriginWithPossibleWildcards::NodeType::kHeader, @@ -191,10 +186,14 @@ OriginWithPossibleWildcards::Parse(std::get<0>(value), std::get<1>(value)); SCOPED_TRACE(std::get<4>(value)); - EXPECT_EQ(std::get<2>(value), - origin_with_possible_wildcards.origin.Serialize()); - EXPECT_EQ(std::get<3>(value), - origin_with_possible_wildcards.has_subdomain_wildcard); + if (strlen(std::get<2>(value))) { + EXPECT_EQ(std::get<2>(value), + origin_with_possible_wildcards->origin.Serialize()); + EXPECT_EQ(std::get<3>(value), + origin_with_possible_wildcards->has_subdomain_wildcard); + } else { + EXPECT_FALSE(origin_with_possible_wildcards); + } } } @@ -209,7 +208,6 @@ "Origin with improper subdomain wildcard"), std::make_tuple("https://%2A.com", false, "https://%2A.com", "Origin with non-registerable subdomain wildcard"), - std::make_tuple("null", false, "null", "Opaque origin"), }; for (const auto& value : values) { const auto& origin_with_possible_wildcards = OriginWithPossibleWildcards( @@ -220,25 +218,28 @@ } TEST(OriginWithPossibleWildcardsTest, Constructors) { - OriginWithPossibleWildcards a; - OriginWithPossibleWildcards b(url::Origin(), false); - OriginWithPossibleWildcards c(b); + OriginWithPossibleWildcards a(url::Origin::Create(GURL("https://google.com")), + false); + OriginWithPossibleWildcards b( + url::Origin::Create(GURL("https://google.com:443")), false); + OriginWithPossibleWildcards c(url::Origin::Create(GURL("https://google.com")), + true); OriginWithPossibleWildcards d = c; - EXPECT_NE(a, b); - EXPECT_EQ(b, c); + EXPECT_EQ(a, b); + EXPECT_NE(b, c); EXPECT_EQ(c, d); - mojo::test::SerializeAndDeserialize<mojom::OriginWithPossibleWildcards>(a, b); + EXPECT_TRUE( + mojo::test::SerializeAndDeserialize<network::mojom::CSPSource>(a, b)); EXPECT_EQ(a, b); } TEST(OriginWithPossibleWildcardsTest, Opaque) { EXPECT_DCHECK_DEATH(OriginWithPossibleWildcards(url::Origin(), true)); - OriginWithPossibleWildcards original(url::Origin(), false); - original.has_subdomain_wildcard = true; + EXPECT_DCHECK_DEATH(OriginWithPossibleWildcards(url::Origin(), false)); + OriginWithPossibleWildcards original; OriginWithPossibleWildcards copy; - EXPECT_FALSE( - mojo::test::SerializeAndDeserialize<mojom::OriginWithPossibleWildcards>( - original, copy)); + EXPECT_FALSE(mojo::test::SerializeAndDeserialize<network::mojom::CSPSource>( + original, copy)); } } // namespace blink
diff --git a/third_party/blink/common/permissions_policy/permissions_policy.cc b/third_party/blink/common/permissions_policy/permissions_policy.cc index 6a369c2..b07a2a6 100644 --- a/third_party/blink/common/permissions_policy/permissions_policy.cc +++ b/third_party/blink/common/permissions_policy/permissions_policy.cc
@@ -20,9 +20,11 @@ // Extracts an Allowlist from a ParsedPermissionsPolicyDeclaration. PermissionsPolicy::Allowlist AllowlistFromDeclaration( - const ParsedPermissionsPolicyDeclaration& parsed_declaration, - const PermissionsPolicyFeatureList& feature_list) { + const ParsedPermissionsPolicyDeclaration& parsed_declaration) { auto result = PermissionsPolicy::Allowlist(); + if (parsed_declaration.self_if_matches) { + result.AddSelf(parsed_declaration.self_if_matches); + } if (parsed_declaration.matches_all_origins) result.AddAll(); if (parsed_declaration.matches_opaque_src) @@ -46,6 +48,10 @@ allowed_origins_.push_back(origin); } +void PermissionsPolicy::Allowlist::AddSelf(absl::optional<url::Origin> self) { + self_if_matches_ = std::move(self); +} + void PermissionsPolicy::Allowlist::AddAll() { matches_all_origins_ = true; } @@ -55,6 +61,9 @@ } bool PermissionsPolicy::Allowlist::Contains(const url::Origin& origin) const { + if (origin == self_if_matches_) { + return true; + } for (const auto& allowed_origin : allowed_origins_) { if (allowed_origin.DoesMatchOrigin(origin)) return true; @@ -64,6 +73,11 @@ return matches_all_origins_; } +const absl::optional<url::Origin>& PermissionsPolicy::Allowlist::SelfIfMatches() + const { + return self_if_matches_; +} + bool PermissionsPolicy::Allowlist::MatchesAll() const { return matches_all_origins_; } @@ -254,8 +268,7 @@ parsed_header) { mojom::PermissionsPolicyFeature feature = parsed_declaration.feature; DCHECK(feature != mojom::PermissionsPolicyFeature::kNotFound); - allowlists_.emplace( - feature, AllowlistFromDeclaration(parsed_declaration, *feature_list_)); + allowlists_.emplace(feature, AllowlistFromDeclaration(parsed_declaration)); } } @@ -266,8 +279,7 @@ parsed_header) { mojom::PermissionsPolicyFeature feature = parsed_declaration.feature; DCHECK(feature != mojom::PermissionsPolicyFeature::kNotFound); - const auto header_allowlist = - AllowlistFromDeclaration(parsed_declaration, *feature_list_); + const auto header_allowlist = AllowlistFromDeclaration(parsed_declaration); auto& isolated_app_allowlist = allowlists_.at(feature); // If the header does not specify further restrictions we do not need to @@ -283,6 +295,7 @@ // clone() is implemented. isolated_app_allowlist.SetAllowedOrigins(header_allowed_origins); isolated_app_allowlist.RemoveMatchesAll(); + isolated_app_allowlist.AddSelf(header_allowlist.SelfIfMatches()); continue; } @@ -306,8 +319,7 @@ parsed_header) { mojom::PermissionsPolicyFeature feature = parsed_declaration.feature; DCHECK(GetPolicyFeatureToClientHintMap().contains(feature)); - allowlists_[feature] = - AllowlistFromDeclaration(parsed_declaration, *feature_list_); + allowlists_[feature] = AllowlistFromDeclaration(parsed_declaration); } } @@ -450,7 +462,7 @@ // 9.8 5.1: If the allowlist for feature in container policy matches // origin, return "Enabled". // 9.8 5.2: Otherwise return "Disabled". - return AllowlistFromDeclaration(decl, *feature_list_).Contains(origin_); + return AllowlistFromDeclaration(decl).Contains(origin_); } } // 9.8 6: If feature’s default allowlist is *, return "Enabled".
diff --git a/third_party/blink/common/permissions_policy/permissions_policy_declaration.cc b/third_party/blink/common/permissions_policy/permissions_policy_declaration.cc index 6a2f2261..6dc6dba6 100644 --- a/third_party/blink/common/permissions_policy/permissions_policy_declaration.cc +++ b/third_party/blink/common/permissions_policy/permissions_policy_declaration.cc
@@ -22,10 +22,12 @@ ParsedPermissionsPolicyDeclaration::ParsedPermissionsPolicyDeclaration( mojom::PermissionsPolicyFeature feature, const std::vector<blink::OriginWithPossibleWildcards>& allowed_origins, + const absl::optional<url::Origin>& self_if_matches, bool matches_all_origins, bool matches_opaque_src) : feature(feature), - allowed_origins(allowed_origins), + allowed_origins(std::move(allowed_origins)), + self_if_matches(std::move(self_if_matches)), matches_all_origins(matches_all_origins), matches_opaque_src(matches_opaque_src) {} @@ -41,6 +43,9 @@ if (matches_all_origins || (matches_opaque_src && origin.opaque())) { return true; } + if (origin == self_if_matches) { + return true; + } for (const auto& origin_with_possible_wildcards : allowed_origins) { if (origin_with_possible_wildcards.DoesMatchOrigin(origin)) { return true;
diff --git a/third_party/blink/common/permissions_policy/permissions_policy_declaration_unittest.cc b/third_party/blink/common/permissions_policy/permissions_policy_declaration_unittest.cc index 493fd64..c28394d 100644 --- a/third_party/blink/common/permissions_policy/permissions_policy_declaration_unittest.cc +++ b/third_party/blink/common/permissions_policy/permissions_policy_declaration_unittest.cc
@@ -48,6 +48,19 @@ /*has_subdomain_wildcard=*/false); EXPECT_TRUE(match_decl.Contains(kTestOrigin)); EXPECT_FALSE(match_decl.Contains(kOpaqueOrigin)); + + // Self match. + ParsedPermissionsPolicyDeclaration self_decl; + self_decl.self_if_matches = + url::Origin::Create(GURL("https://example.test/")); + EXPECT_TRUE(self_decl.Contains(kTestOrigin)); + EXPECT_FALSE(self_decl.Contains(kOpaqueOrigin)); + + // Opaque self match. + ParsedPermissionsPolicyDeclaration opaque_self_decl; + opaque_self_decl.self_if_matches = kOpaqueOrigin; + EXPECT_FALSE(opaque_self_decl.Contains(kTestOrigin)); + EXPECT_TRUE(opaque_self_decl.Contains(kOpaqueOrigin)); } } // namespace blink
diff --git a/third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.cc b/third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.cc index aa462f9..7482e891 100644 --- a/third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.cc +++ b/third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.cc
@@ -4,20 +4,34 @@ #include "third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.h" +#include "services/network/public/mojom/content_security_policy.mojom.h" #include "url/mojom/origin_mojom_traits.h" +#include "url/origin.h" namespace mojo { -bool StructTraits<blink::mojom::OriginWithPossibleWildcardsDataView, +bool StructTraits<network::mojom::CSPSourceDataView, blink::OriginWithPossibleWildcards>:: - Read(blink::mojom::OriginWithPossibleWildcardsDataView in, + Read(network::mojom::CSPSourceDataView in, blink::OriginWithPossibleWildcards* out) { - out->has_subdomain_wildcard = in.has_subdomain_wildcard(); - if (!in.ReadOrigin(&out->origin)) + // We do not support any wildcard types besides host + // based ones for now. + out->has_subdomain_wildcard = in.is_host_wildcard(); + std::string scheme; + std::string host; + if (!in.ReadScheme(&scheme) || !in.ReadHost(&host)) { return false; + } + absl::optional<url::Origin> maybe_origin = + url::Origin::UnsafelyCreateTupleOriginWithoutNormalization(scheme, host, + in.port()); + if (!maybe_origin) { + return false; + } + out->origin = *maybe_origin; - // An opaque origin cannot have a wildcard. - return !out->origin.opaque() || !out->has_subdomain_wildcard; + // Origins cannot be opaque. + return !out->origin.opaque(); } bool StructTraits<blink::mojom::ParsedPermissionsPolicyDeclarationDataView, @@ -27,7 +41,8 @@ out->matches_all_origins = in.matches_all_origins(); out->matches_opaque_src = in.matches_opaque_src(); return in.ReadFeature(&out->feature) && - in.ReadAllowedOrigins(&out->allowed_origins); + in.ReadAllowedOrigins(&out->allowed_origins) && + in.ReadSelfIfMatches(&out->self_if_matches); } } // namespace mojo
diff --git a/third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.h b/third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.h index 01cf2e4..a2188cb 100644 --- a/third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.h +++ b/third_party/blink/common/permissions_policy/permissions_policy_mojom_traits.h
@@ -8,6 +8,7 @@ #include <map> #include "mojo/public/cpp/bindings/enum_traits.h" +#include "services/network/public/mojom/content_security_policy.mojom-forward.h" #include "third_party/blink/common/permissions_policy/policy_value_mojom_traits.h" #include "third_party/blink/public/common/common_export.h" #include "third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h" @@ -18,20 +19,35 @@ namespace mojo { template <> -class BLINK_COMMON_EXPORT - StructTraits<blink::mojom::OriginWithPossibleWildcardsDataView, - blink::OriginWithPossibleWildcards> { +class BLINK_COMMON_EXPORT StructTraits<network::mojom::CSPSourceDataView, + blink::OriginWithPossibleWildcards> { public: - static const url::Origin& origin(const blink::OriginWithPossibleWildcards& + static const std::string& scheme(const blink::OriginWithPossibleWildcards& origin_with_possible_wildcards) { - return origin_with_possible_wildcards.origin; + return origin_with_possible_wildcards.origin.scheme(); } - static bool has_subdomain_wildcard(const blink::OriginWithPossibleWildcards& - origin_with_possible_wildcards) { + static const std::string& host(const blink::OriginWithPossibleWildcards& + origin_with_possible_wildcards) { + return origin_with_possible_wildcards.origin.host(); + } + static int port(const blink::OriginWithPossibleWildcards& + origin_with_possible_wildcards) { + return origin_with_possible_wildcards.origin.port(); + } + static const std::string path(const blink::OriginWithPossibleWildcards& + origin_with_possible_wildcards) { + return std::string(); + } + static bool is_host_wildcard(const blink::OriginWithPossibleWildcards& + origin_with_possible_wildcards) { return origin_with_possible_wildcards.has_subdomain_wildcard; } + static bool is_port_wildcard(const blink::OriginWithPossibleWildcards& + origin_with_possible_wildcards) { + return false; + } - static bool Read(blink::mojom::OriginWithPossibleWildcardsDataView in, + static bool Read(network::mojom::CSPSourceDataView in, blink::OriginWithPossibleWildcards* out); }; @@ -48,6 +64,10 @@ const blink::ParsedPermissionsPolicyDeclaration& policy) { return policy.allowed_origins; } + static const absl::optional<url::Origin>& self_if_matches( + const blink::ParsedPermissionsPolicyDeclaration& policy) { + return policy.self_if_matches; + } static bool matches_all_origins( const blink::ParsedPermissionsPolicyDeclaration& policy) { return policy.matches_all_origins;
diff --git a/third_party/blink/common/permissions_policy/permissions_policy_unittest.cc b/third_party/blink/common/permissions_policy/permissions_policy_unittest.cc index ec12c0e..b28a197b 100644 --- a/third_party/blink/common/permissions_policy/permissions_policy_unittest.cc +++ b/third_party/blink/common/permissions_policy/permissions_policy_unittest.cc
@@ -163,12 +163,11 @@ CreateFromParentPolicy(nullptr, origin_a_); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); - policy2->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_b_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + policy2->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/ + /*allowed_origins=*/{}, + /*self_if_matches=*/origin_b_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultSelfFeature)); } @@ -190,12 +189,11 @@ // they are at a different origin. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/ + /*allowed_origins=*/{}, + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_a_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -227,12 +225,40 @@ // it is embedded by frame 2, for which the feature is not enabled. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/ + /*allowed_origins=*/{}, + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); + std::unique_ptr<PermissionsPolicy> policy2 = + CreateFromParentPolicy(policy1.get(), origin_b_); + std::unique_ptr<PermissionsPolicy> policy3 = + CreateFromParentPolicy(policy2.get(), origin_a_); + EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultSelfFeature)); + EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature)); +} + +TEST_F(PermissionsPolicyTest, TestReflexiveFrameOriginAInheritance) { + // +-------------------------------------------+ + // |(1) Origin A | + // |Permissions-Policy: default-self="OriginA" | + // | +-----------------+ | + // | |(2) Origin B | | + // | |No Policy | | + // | | +-------------+ | | + // | | |(3)Origin A | | | + // | | |No Policy | | | + // | | +-------------+ | | + // | +-----------------+ | + // +-------------------------------------------+ + // Feature which is enabled at top-level should be disabled in frame 3, as + // it is embedded by frame 2, for which the feature is not enabled. + std::unique_ptr<PermissionsPolicy> policy1 = + CreateFromParentPolicy(nullptr, origin_a_); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -263,8 +289,9 @@ {{{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -300,14 +327,16 @@ {{{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); ParsedPermissionsPolicy frame_policy = { {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -327,8 +356,10 @@ // Default-on feature should be disabled in top-level frame. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultOnFeature, /*allowed_origins=*/{}, false, false}}}); + policy1->SetHeaderPolicy({{{kDefaultOnFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); EXPECT_FALSE(policy1->IsFeatureEnabled(kDefaultOnFeature)); } @@ -344,8 +375,10 @@ // Feature should be disabled in child frame. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultOnFeature, /*allowed_origins=*/{}, false, false}}}); + policy1->SetHeaderPolicy({{{kDefaultOnFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_a_); EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultOnFeature)); @@ -365,8 +398,10 @@ CreateFromParentPolicy(nullptr, origin_a_); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); - policy2->SetHeaderPolicy( - {{{kDefaultOnFeature, /*allowed_origins=*/{}, false, false}}}); + policy2->SetHeaderPolicy({{{kDefaultOnFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultOnFeature)); } @@ -389,12 +424,11 @@ CreateFromParentPolicy(nullptr, origin_a_); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); - policy2->SetHeaderPolicy( - {{{kDefaultOnFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_b_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + policy2->SetHeaderPolicy({{{kDefaultOnFeature, /*allowed_origins=*/ + /*allowed_origins=*/{}, + /*self_if_matches=*/origin_b_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentPolicy(policy2.get(), origin_c_); EXPECT_TRUE(policy2->IsFeatureEnabled(kDefaultOnFeature)); @@ -413,8 +447,10 @@ // Default-on feature should be disabled in cross-origin child frame. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultOnFeature, /*allowed_origins=*/{}, false, false}}}); + policy1->SetHeaderPolicy({{{kDefaultOnFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultOnFeature)); @@ -436,8 +472,10 @@ // Feature should be enabled in top level; disabled in frame 2 and 3. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -464,14 +502,17 @@ // Feature should be enabled in top and second level; disabled in frame 3. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}); ParsedPermissionsPolicy frame_policy = { {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -501,8 +542,9 @@ {{{kDefaultOnFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -533,12 +575,11 @@ CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy( {{{kDefaultOnFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -571,8 +612,9 @@ {{{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -604,18 +646,16 @@ CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy( {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); ParsedPermissionsPolicy frame_policy = { - {{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_b_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/origin_b_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -646,10 +686,15 @@ // not explicitly delegated. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}); ParsedPermissionsPolicy frame_policy = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, true}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -675,16 +720,17 @@ // Feature should be enabled at the top level; disabled in all other frames. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/ + /*allowed_origins=*/{}, + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); - policy2->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}); + policy2->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentPolicy(policy2.get(), origin_a_); std::unique_ptr<PermissionsPolicy> policy4 = @@ -714,19 +760,17 @@ std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); ParsedPermissionsPolicy frame_policy = { - {{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_b_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/origin_b_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_); ParsedPermissionsPolicy frame_policy2 = { - {{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_c_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/origin_c_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy(policy2.get(), frame_policy2, origin_c_); EXPECT_TRUE(policy1->IsFeatureEnabled(kDefaultSelfFeature)); @@ -752,12 +796,11 @@ CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy({{ {kDefaultOnFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}, + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, }}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); @@ -790,12 +833,11 @@ CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy( {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_b_); std::unique_ptr<PermissionsPolicy> policy3 = @@ -831,45 +873,40 @@ CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy( {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}, + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, {kDefaultOnFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*allowed_origins=*/{}, + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); ParsedPermissionsPolicy frame_policy = { {{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}, - {kDefaultOnFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, + {kDefaultOnFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_); ParsedPermissionsPolicy frame_policy2 = { {{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_c_, + {blink::OriginWithPossibleWildcards(origin_c_, /*has_subdomain_wildcard=*/false)}, - false, - false}, - {kDefaultOnFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_b_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, + {kDefaultOnFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/origin_b_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy(policy2.get(), frame_policy2, origin_c_); EXPECT_TRUE(policy1->IsFeatureEnabled(kDefaultSelfFeature)); @@ -903,8 +940,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_); EXPECT_TRUE( @@ -931,7 +969,10 @@ std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); ParsedPermissionsPolicy frame_policy = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_); EXPECT_TRUE( @@ -972,8 +1013,9 @@ {kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, }}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_); @@ -981,8 +1023,9 @@ {kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_c_, /*has_subdomain_wildcard=*/false)}, - false, - false}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, }}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy(policy2.get(), frame_policy2, origin_c_); @@ -1020,11 +1063,17 @@ std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); ParsedPermissionsPolicy frame_policy1 = { - {{kDefaultOnFeature, /*allowed_origins=*/{}, false, false}}}; + {{kDefaultOnFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_a_); ParsedPermissionsPolicy frame_policy2 = { - {{kDefaultOnFeature, /*allowed_origins=*/{}, false, false}}}; + {{kDefaultOnFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_b_); EXPECT_TRUE(policy1->IsFeatureEnabledForOrigin(kDefaultOnFeature, origin_a_)); @@ -1069,28 +1118,32 @@ CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy({{ {kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}, + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, }}); ParsedPermissionsPolicy frame_policy1 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, false, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_); ParsedPermissionsPolicy frame_policy2 = {{ - {kDefaultSelfFeature, /*allowed_origins=*/{}, false, false}, + {kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, }}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_b_); policy3->SetHeaderPolicy({{ - {kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_b_, - /*has_subdomain_wildcard=*/false)}, - false, - false}, + {kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/origin_b_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, }}); EXPECT_FALSE( policy2->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_b_)); @@ -1129,14 +1182,20 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_); - policy2->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}); + policy2->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}); ParsedPermissionsPolicy frame_policy2 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, false, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy(policy2.get(), frame_policy2, origin_c_); std::unique_ptr<PermissionsPolicy> policy4 = @@ -1170,19 +1229,26 @@ std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy({{ - {kDefaultSelfFeature, /*allowed_origins=*/{}, false, false}, + {kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, }}); ParsedPermissionsPolicy frame_policy1 = {{ {kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, }}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_); ParsedPermissionsPolicy frame_policy2 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_a_); EXPECT_FALSE( @@ -1222,30 +1288,34 @@ CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy( {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); ParsedPermissionsPolicy frame_policy1 = { {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy1, origin_b_); ParsedPermissionsPolicy frame_policy2 = { {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy2, origin_b_); ParsedPermissionsPolicy frame_policy3 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy4 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy3, origin_b_); EXPECT_TRUE( @@ -1307,7 +1377,42 @@ CreateFromParentPolicy(nullptr, origin_a_); url::Origin sandboxed_origin = url::Origin(); ParsedPermissionsPolicy frame_policy = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, true}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/true}}}; + std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy( + policy1.get(), frame_policy, sandboxed_origin); + EXPECT_TRUE(policy2->IsFeatureEnabledForOrigin(kDefaultOnFeature, origin_a_)); + EXPECT_TRUE( + policy2->IsFeatureEnabledForOrigin(kDefaultOnFeature, sandboxed_origin)); + EXPECT_TRUE(policy2->IsFeatureEnabled(kDefaultSelfFeature)); + EXPECT_TRUE(policy2->IsFeatureEnabledForOrigin(kDefaultSelfFeature, + sandboxed_origin)); +} + +TEST_F(PermissionsPolicyTest, TestSandboxedFramePolicyForSelf) { + // +-------------------------------------------+ + // |(1)Origin A | + // |No Policy | + // | | + // |<iframe sandbox allow="default-self self"> | + // | +-------------+ | + // | |(2)Sandboxed | | + // | |No Policy | | + // | +-------------+ | + // +-------------------------------------------+ + // Default-self feature should be enabled in child frame with opaque origin, + // only for that origin, because container policy matches all origins. + // However, it will not pass that on to any other origin + std::unique_ptr<PermissionsPolicy> policy1 = + CreateFromParentPolicy(nullptr, origin_a_); + url::Origin sandboxed_origin = url::Origin(); + ParsedPermissionsPolicy frame_policy = { + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/sandboxed_origin, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/true}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy( policy1.get(), frame_policy, sandboxed_origin); EXPECT_TRUE(policy2->IsFeatureEnabledForOrigin(kDefaultOnFeature, origin_a_)); @@ -1336,7 +1441,10 @@ CreateFromParentPolicy(nullptr, origin_a_); url::Origin sandboxed_origin = url::Origin(); ParsedPermissionsPolicy frame_policy = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, false, true}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/true}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy( policy1.get(), frame_policy, sandboxed_origin); EXPECT_TRUE(policy2->IsFeatureEnabledForOrigin(kDefaultOnFeature, origin_a_)); @@ -1362,11 +1470,16 @@ // policy. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}); url::Origin sandboxed_origin = url::Origin(); ParsedPermissionsPolicy frame_policy = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, false, true}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/true}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy( policy1.get(), frame_policy, sandboxed_origin); EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1397,7 +1510,10 @@ url::Origin sandboxed_origin_1 = url::Origin(); url::Origin sandboxed_origin_2 = url::Origin(); ParsedPermissionsPolicy frame_policy = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy( policy1.get(), frame_policy, sandboxed_origin_1); std::unique_ptr<PermissionsPolicy> policy3 = @@ -1441,11 +1557,17 @@ url::Origin sandboxed_origin_1 = origin_a_.DeriveNewOpaqueOrigin(); url::Origin sandboxed_origin_2 = sandboxed_origin_1.DeriveNewOpaqueOrigin(); ParsedPermissionsPolicy frame_policy_1 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, true}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/true}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy( policy1.get(), frame_policy_1, sandboxed_origin_1); ParsedPermissionsPolicy frame_policy_2 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, true}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/true}}}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy( policy2.get(), frame_policy_2, sandboxed_origin_2); EXPECT_TRUE(policy3->IsFeatureEnabledForOrigin(kDefaultOnFeature, origin_a_)); @@ -1473,8 +1595,13 @@ CreateFromParentPolicy(nullptr, origin_a_); ParsedPermissionsPolicy frame_policy = { {{mojom::PermissionsPolicyFeature::kNotFound, /*allowed_origins=*/{}, - false, true}, - {kUnavailableFeature, /*allowed_origins=*/{}, false, true}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/true}, + {kUnavailableFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/true}}}; std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy, origin_b_); EXPECT_FALSE(PolicyContainsInheritedValue( @@ -1540,11 +1667,9 @@ std::unique_ptr<PermissionsPolicy> policy = CreateFromParentPolicy(nullptr, origin_a_); - policy->SetHeaderPolicy({{{mojom::PermissionsPolicyFeature:: - kBrowsingTopics, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards( - origin_a_, - /*has_subdomain_wildcard=*/false)}, + policy->SetHeaderPolicy({{{mojom::PermissionsPolicyFeature::kBrowsingTopics, + /*allowed_origins=*/{}, + /*self_if_matches=*/origin_a_, /*matches_all_origins=*/false, /*matches_opaque_src=*/false}}}); @@ -1572,9 +1697,9 @@ std::unique_ptr<PermissionsPolicy> policy = CreateFromParentPolicy(nullptr, origin_a_); - policy->SetHeaderPolicy({{{mojom::PermissionsPolicyFeature:: - kBrowsingTopics, /*allowed_origins=*/ - {}, + policy->SetHeaderPolicy({{{mojom::PermissionsPolicyFeature::kBrowsingTopics, + /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false}}}); @@ -1602,9 +1727,9 @@ std::unique_ptr<PermissionsPolicy> policy = CreateFromParentPolicy(nullptr, origin_a_); - policy->SetHeaderPolicy({{{mojom::PermissionsPolicyFeature:: - kBrowsingTopics, /*allowed_origins=*/ - {}, + policy->SetHeaderPolicy({{{mojom::PermissionsPolicyFeature::kBrowsingTopics, + /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/true, /*matches_opaque_src=*/false}}}); @@ -1638,6 +1763,7 @@ {blink::OriginWithPossibleWildcards( origin_b_, /*has_subdomain_wildcard=*/false)}, + /*self_if_matches=*/absl::nullopt, /*matches_all_origins=*/false, /*matches_opaque_src=*/false}}}); @@ -1728,8 +1854,10 @@ // all child frames, regardless of any declared frame policies. std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/{}, false, false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_a_); EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1739,7 +1867,10 @@ EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature)); ParsedPermissionsPolicy frame_policy4 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy4 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy4, origin_b_); EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1748,8 +1879,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy5 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy5, origin_b_); EXPECT_FALSE(policy5->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1758,8 +1890,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_c_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy6 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy6, origin_b_); EXPECT_FALSE(policy6->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1795,12 +1928,10 @@ // the frame policy declares that the feature should be allowed.) std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_a_); @@ -1812,7 +1943,10 @@ // This is a critical change from the existing semantics. ParsedPermissionsPolicy frame_policy4 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy4 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy4, origin_b_); EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1822,8 +1956,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy5 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy5, origin_b_); EXPECT_FALSE(policy5->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1832,8 +1967,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_c_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy6 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy6, origin_b_); EXPECT_FALSE(policy6->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1872,12 +2008,11 @@ CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy( {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_a_); @@ -1889,7 +2024,10 @@ EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature)); ParsedPermissionsPolicy frame_policy4 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy4 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy4, origin_b_); EXPECT_TRUE(policy4->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1898,8 +2036,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy5 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy5, origin_b_); EXPECT_TRUE(policy5->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1908,8 +2047,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_c_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy6 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy6, origin_b_); EXPECT_FALSE(policy6->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1946,8 +2086,10 @@ // feature explicitly.) std::unique_ptr<PermissionsPolicy> policy1 = CreateFromParentPolicy(nullptr, origin_a_); - policy1->SetHeaderPolicy( - {{{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}); + policy1->SetHeaderPolicy({{{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}); std::unique_ptr<PermissionsPolicy> policy2 = CreateFromParentPolicy(policy1.get(), origin_a_); @@ -1959,7 +2101,10 @@ EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature)); ParsedPermissionsPolicy frame_policy4 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy4 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy4, origin_b_); EXPECT_TRUE(policy4->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1968,8 +2113,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy5 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy5, origin_b_); EXPECT_TRUE(policy5->IsFeatureEnabled(kDefaultSelfFeature)); @@ -1978,8 +2124,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_c_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy6 = CreateFromParentWithFramePolicy(policy1.get(), frame_policy6, origin_b_); EXPECT_FALSE(policy6->IsFeatureEnabled(kDefaultSelfFeature)); @@ -2006,12 +2153,11 @@ CreateFromParentPolicy(nullptr, origin_a_); policy1->SetHeaderPolicy( {{{kDefaultSelfFeature, /*allowed_origins=*/ - {blink::OriginWithPossibleWildcards(origin_a_, - /*has_subdomain_wildcard=*/false), - blink::OriginWithPossibleWildcards(origin_b_, + {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/origin_a_, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); // This is where the change first occurs. std::unique_ptr<PermissionsPolicy> policy2 = @@ -2020,7 +2166,10 @@ // The proposed value in frame 2 should affect the proposed value in frame 3. ParsedPermissionsPolicy frame_policy3 = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, true, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/true, + /*matches_opaque_src=*/false}}}; std::unique_ptr<PermissionsPolicy> policy3 = CreateFromParentWithFramePolicy(policy2.get(), frame_policy3, origin_b_); EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature)); @@ -2055,8 +2204,9 @@ /*has_subdomain_wildcard=*/false), blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; auto policy = CreateFromParsedPolicy(parsed_policy, origin_a_); EXPECT_TRUE( policy->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_a_)); @@ -2069,8 +2219,9 @@ {{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; auto policy = CreateFromParsedPolicy(parsed_policy, origin_a_); EXPECT_FALSE( policy->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_a_)); @@ -2080,7 +2231,10 @@ TEST_F(PermissionsPolicyTest, CreateFromParsedPolicyWithEmptyAllowlist) { ParsedPermissionsPolicy parsed_policy = { - {{kDefaultSelfFeature, /*allowed_origins=*/{}, false, false}}}; + {{kDefaultSelfFeature, /*allowed_origins=*/{}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}; auto policy = CreateFromParsedPolicy(parsed_policy, origin_a_); EXPECT_FALSE(policy->IsFeatureEnabled(kDefaultSelfFeature)); } @@ -2092,8 +2246,9 @@ {{{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); EXPECT_TRUE(policy1->IsFeatureEnabled(kDefaultSelfFeature)); // We can't construct a policy, check, then set headers. @@ -2103,8 +2258,9 @@ {{{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}})); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}})); // We can't construct a policy, set headers, then set the header. auto policy3 = CreateFromParentPolicy(nullptr, origin_a_); @@ -2112,19 +2268,25 @@ {{{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); EXPECT_DCHECK_DEATH(policy3->SetHeaderPolicy( {{{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}})); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}})); // We can't construct a policy, then set headers for kNotFound. auto policy4 = CreateFromParentPolicy(nullptr, origin_a_); - EXPECT_DCHECK_DEATH(policy4->SetHeaderPolicy( - {{{mojom::PermissionsPolicyFeature::kNotFound, {}, false, false}}})); + EXPECT_DCHECK_DEATH( + policy4->SetHeaderPolicy({{{mojom::PermissionsPolicyFeature::kNotFound, + {}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}})); } TEST_F(PermissionsPolicyTest, OverwriteHeaderPolicyForClientHints) { @@ -2135,15 +2297,17 @@ /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); policy1->OverwriteHeaderPolicyForClientHints( {{{mojom::PermissionsPolicyFeature::kClientHintDPR, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); EXPECT_TRUE(policy1->IsFeatureEnabled( mojom::PermissionsPolicyFeature::kClientHintDPR)); @@ -2154,15 +2318,17 @@ /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); policy2->OverwriteHeaderPolicyForClientHints( {{{mojom::PermissionsPolicyFeature::kClientHintDPR, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); EXPECT_FALSE(policy2->IsFeatureEnabled( mojom::PermissionsPolicyFeature::kClientHintDPR)); @@ -2172,15 +2338,17 @@ {{{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); policy3->OverwriteHeaderPolicyForClientHints( {{{mojom::PermissionsPolicyFeature::kClientHintDPR, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); EXPECT_TRUE(policy3->IsFeatureEnabled( mojom::PermissionsPolicyFeature::kClientHintDPR)); @@ -2190,8 +2358,9 @@ {{{kDefaultSelfFeature, /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}})); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}})); // We can't construct a policy, set headers, check, then overwrite the header. auto policy5 = CreateFromParentPolicy(nullptr, origin_a_); @@ -2200,8 +2369,9 @@ /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}}); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); EXPECT_TRUE(policy5->IsFeatureEnabled( mojom::PermissionsPolicyFeature::kClientHintDPR)); EXPECT_DCHECK_DEATH(policy5->OverwriteHeaderPolicyForClientHints( @@ -2209,8 +2379,9 @@ /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}})); + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}})); } TEST_F(PermissionsPolicyTest, GetAllowlistForFeatureIfExists) { @@ -2220,7 +2391,9 @@ {blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}); policy1->SetHeaderPolicy({{{mojom::PermissionsPolicyFeature::kClientHintDPR, - origins1, false, false}}}); + origins1, /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); const auto& maybe_allow_list1 = policy1->GetAllowlistForFeatureIfExists( mojom::PermissionsPolicyFeature::kClientHintDPR); EXPECT_TRUE(maybe_allow_list1.has_value()); @@ -2240,11 +2413,16 @@ const std::vector<blink::OriginWithPossibleWildcards> origins3( {blink::OriginWithPossibleWildcards(origin_a_, /*has_subdomain_wildcard=*/false)}); - policy3->SetHeaderPolicy( - {{{mojom::PermissionsPolicyFeature::kClientHintDPR, {}, false, false}}}); + policy3->SetHeaderPolicy({{{mojom::PermissionsPolicyFeature::kClientHintDPR, + {}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); policy3->OverwriteHeaderPolicyForClientHints( - {{{mojom::PermissionsPolicyFeature::kClientHintDPR, origins3, false, - false}}}); + {{{mojom::PermissionsPolicyFeature::kClientHintDPR, origins3, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); const auto& maybe_allow_list3 = policy3->GetAllowlistForFeatureIfExists( mojom::PermissionsPolicyFeature::kClientHintDPR); EXPECT_TRUE(maybe_allow_list3.has_value()); @@ -2261,8 +2439,10 @@ blink::OriginWithPossibleWildcards(origin_b_, /*has_subdomain_wildcard=*/false)}); policy4->OverwriteHeaderPolicyForClientHints( - {{{mojom::PermissionsPolicyFeature::kClientHintDPR, origins4, false, - false}}}); + {{{mojom::PermissionsPolicyFeature::kClientHintDPR, origins4, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}}); const auto& maybe_allow_list4 = policy4->GetAllowlistForFeatureIfExists( mojom::PermissionsPolicyFeature::kClientHintDPR); EXPECT_TRUE(maybe_allow_list4.has_value());
diff --git a/third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h b/third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h index a1d1285..a3b2eb2 100644 --- a/third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h +++ b/third_party/blink/public/common/permissions_policy/origin_with_possible_wildcards.h
@@ -33,8 +33,10 @@ // This constructs a OriginWithPossibleWildcards from an allowlist_entry which // might or might not have a subdomain wildcard (only if the type is kHeader). // This does not support special types like *, 'self', 'src', or 'none'. - static OriginWithPossibleWildcards Parse(const std::string& allowlist_entry, - const NodeType type); + // If the entry cannot be parsed then absl::nullopt is returned. + static absl::optional<OriginWithPossibleWildcards> Parse( + const std::string& allowlist_entry, + const NodeType type); // This should neatly undo the work of Parse, which is to say it // serializes the origin and inserts a *. back into the front of the host
diff --git a/third_party/blink/public/common/permissions_policy/permissions_policy.h b/third_party/blink/public/common/permissions_policy/permissions_policy.h index 2871e741..5e817dc 100644 --- a/third_party/blink/public/common/permissions_policy/permissions_policy.h +++ b/third_party/blink/public/common/permissions_policy/permissions_policy.h
@@ -112,6 +112,9 @@ // Adds a single origin with possible wildcards to the allowlist. void Add(const blink::OriginWithPossibleWildcards& origin); + // Add an origin representing self to the allowlist. + void AddSelf(absl::optional<url::Origin> self); + // Adds all origins to the allowlist. void AddAll(); @@ -122,6 +125,9 @@ // Returns true if the given origin has been added to the allowlist. bool Contains(const url::Origin& origin) const; + // Returns the origin for self if included in the allowlist. + const absl::optional<url::Origin>& SelfIfMatches() const; + // Returns true if the allowlist matches all origins. bool MatchesAll() const; @@ -148,6 +154,7 @@ private: std::vector<OriginWithPossibleWildcards> allowed_origins_; + absl::optional<url::Origin> self_if_matches_; bool matches_all_origins_{false}; bool matches_opaque_src_{false}; };
diff --git a/third_party/blink/public/common/permissions_policy/permissions_policy_declaration.h b/third_party/blink/public/common/permissions_policy/permissions_policy_declaration.h index 1817082..13be54ca6 100644 --- a/third_party/blink/public/common/permissions_policy/permissions_policy_declaration.h +++ b/third_party/blink/public/common/permissions_policy/permissions_policy_declaration.h
@@ -26,6 +26,7 @@ ParsedPermissionsPolicyDeclaration( mojom::PermissionsPolicyFeature feature, const std::vector<OriginWithPossibleWildcards>& allowed_origins, + const absl::optional<url::Origin>& self_if_matches, bool matches_all_origins, bool matches_opaque_src); ParsedPermissionsPolicyDeclaration( @@ -43,8 +44,10 @@ mojom::PermissionsPolicyFeature feature; - // An list of all the origins/wildcards allowed. + // An list of all the origins/wildcards allowed (none can be opaque). std::vector<OriginWithPossibleWildcards> allowed_origins; + // An origin that matches self if 'self' is in the allowlist. + absl::optional<url::Origin> self_if_matches; // Fallback value is used when feature is enabled for all or disabled for all. bool matches_all_origins{false}; // This flag is set true for a declared policy on an <iframe sandbox> @@ -52,6 +55,7 @@ // document. Usually, the 'src' keyword in a declaration will cause the origin // of the iframe to be present in |origins|, but for sandboxed iframes, this // flag is set instead. + // TODO(crbug.com/1418009): Consider merging into `self_if_matches`. bool matches_opaque_src{false}; // Indicates that the parsed policy is deprecated.
diff --git a/third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom b/third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom index d88101c..d3ddb6c 100644 --- a/third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom +++ b/third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom
@@ -4,18 +4,9 @@ module blink.mojom; -import "url/mojom/origin.mojom"; +import "services/network/public/mojom/content_security_policy.mojom"; import "third_party/blink/public/mojom/permissions_policy/permissions_policy_feature.mojom"; - -// This struct can represent an origin like https://foo.com/ or like -// https://*.foo.com/. The wildcard can only represent a subdomain. -// Note that https://*.foo.com/ matches domains like https://example.foo.com/ -// or https://test.example.foo.com/ but does not match https://foo.com/. -// Origins that do have wildcards cannot be opaque. -struct OriginWithPossibleWildcards { - url.mojom.Origin origin; - bool has_subdomain_wildcard; -}; +import "url/mojom/origin.mojom"; // This struct holds permissions policy allowlist data that needs to be replicated // between a RenderFrame and any of its associated RenderFrameProxies. A list of @@ -23,7 +14,8 @@ // NOTE: These types are used for replication frame state between processes. struct ParsedPermissionsPolicyDeclaration { PermissionsPolicyFeature feature; - array<OriginWithPossibleWildcards> allowed_origins; + array<network.mojom.CSPSource> allowed_origins; + url.mojom.Origin? self_if_matches; bool matches_all_origins; bool matches_opaque_src; };
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc index 7a135ff..c1a2b686 100644 --- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc +++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -12,6 +12,7 @@ #include "third_party/blink/renderer/core/css/css_border_image_slice_value.h" #include "third_party/blink/renderer/core/css/css_bracketed_value_list.h" #include "third_party/blink/renderer/core/css/css_color.h" +#include "third_party/blink/renderer/core/css/css_content_distribution_value.h" #include "third_party/blink/renderer/core/css/css_counter_value.h" #include "third_party/blink/renderer/core/css/css_custom_ident_value.h" #include "third_party/blink/renderer/core/css/css_font_family_value.h" @@ -701,44 +702,54 @@ return ZoomAdjustedPixelValueForLength(offset, style); } -CSSValueList* ComputedStyleUtils::ValueForItemPositionWithOverflowAlignment( +CSSValue* ComputedStyleUtils::ValueForItemPositionWithOverflowAlignment( const StyleSelfAlignmentData& data) { - CSSValueList* result = CSSValueList::CreateSpaceSeparated(); if (data.PositionType() == ItemPositionType::kLegacy) { - result->Append(*CSSIdentifierValue::Create(CSSValueID::kLegacy)); + // Legacy is only for justify-items and may only be created with the + // positions "left", "right", or "center". See + // JustifyItems::ParseSingleValue. + DCHECK(data.GetPosition() == ItemPosition::kLeft || + data.GetPosition() == ItemPosition::kRight || + data.GetPosition() == ItemPosition::kCenter) + << "Unexpected position: " << (unsigned)data.GetPosition(); + DCHECK_EQ(data.Overflow(), OverflowAlignment::kDefault); + return MakeGarbageCollected<CSSValuePair>( + CSSIdentifierValue::Create(CSSValueID::kLegacy), + CSSIdentifierValue::Create(data.GetPosition()), + CSSValuePair::kDropIdenticalValues); } + if (data.GetPosition() == ItemPosition::kBaseline) { - result->Append(*MakeGarbageCollected<CSSValuePair>( - CSSIdentifierValue::Create(CSSValueID::kBaseline), - CSSIdentifierValue::Create(CSSValueID::kBaseline), - CSSValuePair::kDropIdenticalValues)); + return CSSIdentifierValue::Create(CSSValueID::kBaseline); } else if (data.GetPosition() == ItemPosition::kLastBaseline) { - result->Append(*MakeGarbageCollected<CSSValuePair>( + return MakeGarbageCollected<CSSValuePair>( CSSIdentifierValue::Create(CSSValueID::kLast), CSSIdentifierValue::Create(CSSValueID::kBaseline), - CSSValuePair::kDropIdenticalValues)); + CSSValuePair::kDropIdenticalValues); } else { + auto* position = data.GetPosition() == ItemPosition::kLegacy + ? CSSIdentifierValue::Create(CSSValueID::kNormal) + : CSSIdentifierValue::Create(data.GetPosition()); if (data.GetPosition() >= ItemPosition::kCenter && data.Overflow() != OverflowAlignment::kDefault) { - result->Append(*CSSIdentifierValue::Create(data.Overflow())); + return MakeGarbageCollected<CSSValuePair>( + CSSIdentifierValue::Create(data.Overflow()), position, + CSSValuePair::kDropIdenticalValues); } - if (data.GetPosition() == ItemPosition::kLegacy) { - result->Append(*CSSIdentifierValue::Create(CSSValueID::kNormal)); - } else { - result->Append(*CSSIdentifierValue::Create(data.GetPosition())); - } + return position; } - DCHECK_LE(result->length(), 2u); - return result; } -CSSValueList* +cssvalue::CSSContentDistributionValue* ComputedStyleUtils::ValueForContentPositionAndDistributionWithOverflowAlignment( const StyleContentAlignmentData& data) { - CSSValueList* result = CSSValueList::CreateSpaceSeparated(); + CSSValueID distribution = CSSValueID::kInvalid; + CSSValueID position = CSSValueID::kInvalid; + CSSValueID overflow = CSSValueID::kInvalid; + // Handle content-distribution values if (data.Distribution() != ContentDistributionType::kDefault) { - result->Append(*CSSIdentifierValue::Create(data.Distribution())); + distribution = CSSIdentifierValue(data.Distribution()).GetValueID(); } // Handle content-position values (either as fallback or actual value) @@ -746,28 +757,24 @@ case ContentPosition::kNormal: // Handle 'normal' value, not valid as content-distribution fallback. if (data.Distribution() == ContentDistributionType::kDefault) { - result->Append(*CSSIdentifierValue::Create(CSSValueID::kNormal)); + position = CSSValueID::kNormal; } break; case ContentPosition::kLastBaseline: - result->Append(*MakeGarbageCollected<CSSValuePair>( - CSSIdentifierValue::Create(CSSValueID::kLast), - CSSIdentifierValue::Create(CSSValueID::kBaseline), - CSSValuePair::kDropIdenticalValues)); + position = CSSValueID::kLastBaseline; break; default: // Handle overflow-alignment (only allowed for content-position values) if ((data.GetPosition() >= ContentPosition::kCenter || data.Distribution() != ContentDistributionType::kDefault) && data.Overflow() != OverflowAlignment::kDefault) { - result->Append(*CSSIdentifierValue::Create(data.Overflow())); + overflow = CSSIdentifierValue::Create(data.Overflow())->GetValueID(); } - result->Append(*CSSIdentifierValue::Create(data.GetPosition())); + position = CSSIdentifierValue::Create(data.GetPosition())->GetValueID(); } - DCHECK_GT(result->length(), 0u); - DCHECK_LE(result->length(), 3u); - return result; + return MakeGarbageCollected<cssvalue::CSSContentDistributionValue>( + distribution, position, overflow); } CSSValue* ComputedStyleUtils::ValueForLineHeight(const ComputedStyle& style) {
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.h b/third_party/blink/renderer/core/css/properties/computed_style_utils.h index a754c08..a0510a2f 100644 --- a/third_party/blink/renderer/core/css/properties/computed_style_utils.h +++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
@@ -32,6 +32,10 @@ class StylePropertyShorthand; class StyleTimeline; +namespace cssvalue { +class CSSContentDistributionValue; +} + enum class CSSValuePhase { kComputedValue, kUsedValue }; class CORE_EXPORT ComputedStyleUtils { @@ -106,9 +110,9 @@ static CSSValue* ValueForPositionOffset(const ComputedStyle&, const CSSProperty&, const LayoutObject*); - static CSSValueList* ValueForItemPositionWithOverflowAlignment( + static CSSValue* ValueForItemPositionWithOverflowAlignment( const StyleSelfAlignmentData&); - static CSSValueList* + static cssvalue::CSSContentDistributionValue* ValueForContentPositionAndDistributionWithOverflowAlignment( const StyleContentAlignmentData&); static CSSValue* ValueForLineHeight(const ComputedStyle&);
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc index c2803d8c..0dcc039 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -8,6 +8,7 @@ #include "third_party/blink/renderer/core/css/css_axis_value.h" #include "third_party/blink/renderer/core/css/css_bracketed_value_list.h" #include "third_party/blink/renderer/core/css/css_color.h" +#include "third_party/blink/renderer/core/css/css_content_distribution_value.h" #include "third_party/blink/renderer/core/css/css_counter_value.h" #include "third_party/blink/renderer/core/css/css_cursor_image_value.h" #include "third_party/blink/renderer/core/css/css_custom_ident_value.h"
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h index 03356ba..931e213 100644 --- a/third_party/blink/renderer/core/frame/local_dom_window.h +++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -36,6 +36,7 @@ #include "third_party/blink/public/common/frame/delegated_capability_request_token.h" #include "third_party/blink/public/common/frame/history_user_activation_state.h" #include "third_party/blink/public/common/metrics/post_message_counter.h" +#include "third_party/blink/public/common/performance/performance_timeline_constants.h" #include "third_party/blink/public/common/scheduler/task_attribution_id.h" #include "third_party/blink/public/common/tokens/tokens.h" #include "third_party/blink/renderer/bindings/core/v8/script_value.h" @@ -661,7 +662,7 @@ // The navigation id of a document is to identify navigation of special types // like bfcache navigation or soft navigation. It increments when navigations // of these types occur. - uint32_t navigation_id_ = 1; + uint32_t navigation_id_ = kNavigationIdDefaultValue; // Records whether this window has obtained storage access. It cannot be // revoked once set to true.
diff --git a/third_party/blink/renderer/core/html/client_hints_util.cc b/third_party/blink/renderer/core/html/client_hints_util.cc index 67d6227..d7a4987 100644 --- a/third_party/blink/renderer/core/html/client_hints_util.cc +++ b/third_party/blink/renderer/core/html/client_hints_util.cc
@@ -78,7 +78,8 @@ policy_name, std::vector<blink::OriginWithPossibleWildcards>(origin_set.begin(), origin_set.end()), - allow_list.MatchesAll(), allow_list.MatchesOpaqueSrc()); + allow_list.SelfIfMatches(), allow_list.MatchesAll(), + allow_list.MatchesOpaqueSrc()); container_policy.push_back(declaration); } auto new_policy = PermissionsPolicy::CopyStateFrom(current_policy); @@ -137,6 +138,8 @@ // Now we apply the changes from the parent policy to ensure any changes // since it was set are respected; + merged_policy.self_if_matches = + maybe_window_allow_list.value().SelfIfMatches(); merged_policy.matches_all_origins |= maybe_window_allow_list.value().MatchesAll(); merged_policy.matches_opaque_src |=
diff --git a/third_party/blink/renderer/core/html/forms/input_type.cc b/third_party/blink/renderer/core/html/forms/input_type.cc index 4fcbacd0..3c8125e 100644 --- a/third_party/blink/renderer/core/html/forms/input_type.cc +++ b/third_party/blink/renderer/core/html/forms/input_type.cc
@@ -32,6 +32,7 @@ #include <memory> #include <utility> +#include "base/debug/crash_logging.h" #include "third_party/blink/public/strings/grit/blink_strings.h" #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h" #include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h" @@ -498,12 +499,26 @@ } String InputType::RangeOverflowText(const Decimal&) const { - NOTREACHED(); + static auto* input_type = base::debug::AllocateCrashKeyString( + "input-type", base::debug::CrashKeySize::Size32); + base::debug::SetCrashKeyString(input_type, + FormControlType().GetString().Utf8().c_str()); + NOTREACHED() << "This should not get called. Check if input type '" + << FormControlType() + << "' should have a RangeOverflowText implementation." + << "See crbug.com/1423280"; return String(); } String InputType::RangeUnderflowText(const Decimal&) const { - NOTREACHED(); + static auto* input_type = base::debug::AllocateCrashKeyString( + "input-type", base::debug::CrashKeySize::Size32); + base::debug::SetCrashKeyString(input_type, + FormControlType().GetString().Utf8().c_str()); + NOTREACHED() << "This should not get called. Check if input type '" + << FormControlType() + << "' should have a RangeUnderflowText implementation." + << "See crbug.com/1423280"; return String(); }
diff --git a/third_party/blink/renderer/core/html/forms/range_input_type.cc b/third_party/blink/renderer/core/html/forms/range_input_type.cc index 2cd86c9..8527ad3 100644 --- a/third_party/blink/renderer/core/html/forms/range_input_type.cc +++ b/third_party/blink/renderer/core/html/forms/range_input_type.cc
@@ -35,6 +35,7 @@ #include <limits> #include "third_party/blink/public/common/input/web_pointer_properties.h" +#include "third_party/blink/public/strings/grit/blink_strings.h" #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h" #include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h" #include "third_party/blink/renderer/core/dom/events/simulated_click_options.h" @@ -59,6 +60,7 @@ #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" +#include "third_party/blink/renderer/platform/text/platform_locale.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" namespace blink { @@ -322,6 +324,16 @@ "The specified value %s cannot be parsed, or is out of range.", value); } +String RangeInputType::RangeOverflowText(const Decimal& maximum) const { + return GetLocale().QueryString(IDS_FORM_VALIDATION_RANGE_OVERFLOW, + LocalizeValue(Serialize(maximum))); +} + +String RangeInputType::RangeUnderflowText(const Decimal& minimum) const { + return GetLocale().QueryString(IDS_FORM_VALIDATION_RANGE_UNDERFLOW, + LocalizeValue(Serialize(minimum))); +} + void RangeInputType::DisabledAttributeChanged() { if (!HasCreatedShadowSubtree()) { return;
diff --git a/third_party/blink/renderer/core/html/forms/range_input_type.h b/third_party/blink/renderer/core/html/forms/range_input_type.h index 42793bc3..75428d5 100644 --- a/third_party/blink/renderer/core/html/forms/range_input_type.h +++ b/third_party/blink/renderer/core/html/forms/range_input_type.h
@@ -70,6 +70,8 @@ void SanitizeValueInResponseToMinOrMaxAttributeChange() override; void StepAttributeChanged() override; void WarnIfValueIsInvalid(const String&) const override; + String RangeOverflowText(const Decimal& maxmum) const override; + String RangeUnderflowText(const Decimal& minimum) const override; void DidSetValue(const String&, bool value_changed) override; String SanitizeValue(const String& proposed_value) const override; bool ShouldRespectListAttribute() override;
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index bef2cb8..9ac7552 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -3318,6 +3318,11 @@ return *fragment_; } + bool IsFragmented() const { + NOT_DESTROYED(); + return !!FirstFragment().NextFragment(); + } + enum OverflowRecalcType { kOnlyVisualOverflowRecalc, kLayoutAndVisualOverflowRecalc,
diff --git a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc index a13b97c..16d5b82f 100644 --- a/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc +++ b/third_party/blink/renderer/core/mobile_metrics/mobile_friendliness_checker_test.cc
@@ -782,13 +782,7 @@ 20); } -#if BUILDFLAG(IS_IOS) -// TODO(crbug.com/1141478) -#define MAYBE_TextAbsolutePositioning DISABLED_TextAbsolutePositioning -#else -#define MAYBE_TextAbsolutePositioning TextAbsolutePositioning -#endif // BUILDFLAG(IS_IOS) -TEST_F(MobileFriendlinessCheckerTest, MAYBE_TextAbsolutePositioning) { +TEST_F(MobileFriendlinessCheckerTest, TextAbsolutePositioning) { ukm::mojom::UkmEntry ukm = CalculateMetricsForHTMLString( R"HTML( <html>
diff --git a/third_party/blink/renderer/core/permissions_policy/dom_feature_policy.cc b/third_party/blink/renderer/core/permissions_policy/dom_feature_policy.cc index 54c8f517..a751a35 100644 --- a/third_party/blink/renderer/core/permissions_policy/dom_feature_policy.cc +++ b/third_party/blink/renderer/core/permissions_policy/dom_feature_policy.cc
@@ -122,6 +122,13 @@ return Vector<String>({"*"}); } Vector<String> result; + result.reserve( + static_cast<wtf_size_t>(allowed_origins.size()) + + static_cast<wtf_size_t>(allowlist.SelfIfMatches().has_value())); + if (allowlist.SelfIfMatches()) { + result.push_back( + WTF::String::FromUTF8(allowlist.SelfIfMatches()->Serialize())); + } for (const auto& origin_with_possible_wildcards : allowed_origins) { result.push_back( WTF::String::FromUTF8(origin_with_possible_wildcards.Serialize()));
diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_parser.cc b/third_party/blink/renderer/core/permissions_policy/permissions_policy_parser.cc index 8d74e000..2c2eb775 100644 --- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_parser.cc +++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_parser.cc
@@ -120,6 +120,7 @@ struct ParsedAllowlist { std::vector<blink::OriginWithPossibleWildcards> allowed_origins ALLOW_DISCOURAGED_TYPE("Permission policy uses STL for code sharing"); + absl::optional<url::Origin> self_if_matches; bool matches_all_origins{false}; bool matches_opaque_src{false}; @@ -242,8 +243,7 @@ // |src_origin| is not null), |src_origin| is not opaque; or // c. the opaque origin of the frame, if |src_origin| is opaque. if (!src_origin_) { - allowlist.allowed_origins.emplace_back(self_origin_->ToUrlOrigin(), - /*has_subdomain_wildcard=*/false); + allowlist.self_if_matches = self_origin_->ToUrlOrigin(); } else if (!src_origin_->IsOpaque()) { allowlist.allowed_origins.emplace_back(src_origin_->ToUrlOrigin(), /*has_subdomain_wildcard=*/false); @@ -273,12 +273,13 @@ // adding an origin to the allowlist. bool target_is_opaque = false; bool target_is_all = false; + bool target_is_self = false; + url::Origin self; // 'self' origin is used if the origin is exactly 'self'. if (EqualIgnoringASCIICase(origin_string, "'self'")) { - origin_with_possible_wildcards = - OriginWithPossibleWildcards(self_origin_->ToUrlOrigin(), - /*has_subdomain_wildcard=*/false); + target_is_self = true; + self = self_origin_->ToUrlOrigin(); } // 'src' origin is used if |src_origin| is available and the // origin is a match for 'src'. |src_origin| is only set @@ -300,9 +301,13 @@ // valid. Invalid strings will produce an opaque origin, which will // result in an error message. else { - origin_with_possible_wildcards = - OriginWithPossibleWildcards::Parse(origin_string.Utf8(), type); - if (origin_with_possible_wildcards.origin.opaque()) { + absl::optional<OriginWithPossibleWildcards> + maybe_origin_with_possible_wildcards = + OriginWithPossibleWildcards::Parse(origin_string.Utf8(), type); + if (maybe_origin_with_possible_wildcards) { + origin_with_possible_wildcards = + *maybe_origin_with_possible_wildcards; + } else { logger_.Warn("Unrecognized origin: '" + origin_string + "'."); continue; } @@ -313,6 +318,8 @@ allowlist.matches_opaque_src = true; } else if (target_is_opaque) { allowlist.matches_opaque_src = true; + } else if (target_is_self) { + allowlist.self_if_matches = self; } else { allowlist.allowed_origins.emplace_back(origin_with_possible_wildcards); } @@ -349,6 +356,7 @@ ParsedPermissionsPolicyDeclaration parsed_feature(*feature); parsed_feature.allowed_origins = std::move(parsed_allowlist.allowed_origins); + parsed_feature.self_if_matches = parsed_allowlist.self_if_matches; parsed_feature.matches_all_origins = parsed_allowlist.matches_all_origins; parsed_feature.matches_opaque_src = parsed_allowlist.matches_opaque_src;
diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_test.cc b/third_party/blink/renderer/core/permissions_policy/permissions_policy_test.cc index 4222477..7c929b7 100644 --- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_test.cc +++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_test.cc
@@ -116,6 +116,7 @@ struct ParsedPolicyDeclarationForTest { mojom::blink::PermissionsPolicyFeature feature; + absl::optional<const char*> self_if_matches; bool matches_all_origins; bool matches_opaque_src; std::vector<OriginWithPossibleWildcardsForTest> allowed_origins; @@ -184,6 +185,12 @@ const auto& expected_declaration = expected[i]; EXPECT_EQ(actual_declaration.feature, expected_declaration.feature); + if (expected_declaration.self_if_matches) { + EXPECT_TRUE(actual_declaration.self_if_matches->IsSameOriginWith( + url::Origin::Create(GURL(*expected_declaration.self_if_matches)))); + } else { + EXPECT_FALSE(actual_declaration.self_if_matches); + } EXPECT_EQ(actual_declaration.matches_all_origins, expected_declaration.matches_all_origins); EXPECT_EQ(actual_declaration.matches_opaque_src, @@ -236,9 +243,10 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, }, }, @@ -252,9 +260,10 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, }, }, @@ -268,6 +277,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ true, /* matches_opaque_src */ true, {}, @@ -290,12 +300,14 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ true, /* matches_opaque_src */ true, {}, }, { mojom::blink::PermissionsPolicyFeature::kFullscreen, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {{ORIGIN_B, /*has_subdomain_wildcard=*/false}, @@ -303,9 +315,10 @@ }, { mojom::blink::PermissionsPolicyFeature::kPayment, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, }, }, @@ -325,12 +338,14 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ true, /* matches_opaque_src */ true, {}, }, { mojom::blink::PermissionsPolicyFeature::kFullscreen, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {{ORIGIN_B, /*has_subdomain_wildcard=*/false}, @@ -338,9 +353,10 @@ }, { mojom::blink::PermissionsPolicyFeature::kPayment, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, }, }, @@ -358,21 +374,24 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, { mojom::blink::PermissionsPolicyFeature::kFullscreen, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, { mojom::blink::PermissionsPolicyFeature::kPayment, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, }, }, @@ -394,6 +413,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ true, {}, @@ -410,6 +430,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ true, {}, @@ -426,6 +447,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ true, /* matches_opaque_src */ true, {}, @@ -443,6 +465,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {{ORIGIN_B, /*has_subdomain_wildcard=*/false}, @@ -461,6 +484,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ true, {{ORIGIN_B, /*has_subdomain_wildcard=*/false}}, @@ -478,6 +502,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {}, @@ -495,6 +520,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {}, @@ -512,6 +538,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {}, @@ -528,6 +555,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {}, @@ -545,6 +573,7 @@ { { mojom::blink::PermissionsPolicyFeature::kFullscreen, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {{ORIGIN_A_SUBDOMAIN_ESCAPED, @@ -563,6 +592,7 @@ { { mojom::blink::PermissionsPolicyFeature::kFullscreen, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {{ORIGIN_A, @@ -584,6 +614,7 @@ { { mojom::blink::PermissionsPolicyFeature::kFullscreen, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {{"https://%2A.%2A.example.com", @@ -643,6 +674,7 @@ { // allowlist value 'none' is expected. mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {}, @@ -666,9 +698,10 @@ { // allowlist value 'self' is expected. mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, }); @@ -692,21 +725,24 @@ // the value should be taken from permissions policy // header, which is 'self' here. mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, { mojom::blink::PermissionsPolicyFeature::kPayment, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ true, /* matches_opaque_src */ true, {}, }, { mojom::blink::PermissionsPolicyFeature::kFullscreen, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, }); } @@ -728,12 +764,14 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ true, /* matches_opaque_src */ true, {}, }, { mojom::blink::PermissionsPolicyFeature::kFullscreen, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ true, /* matches_opaque_src */ true, {}, @@ -771,6 +809,7 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ absl::nullopt, /* matches_all_origins */ false, /* matches_opaque_src */ false, {}, @@ -804,9 +843,10 @@ { { mojom::blink::PermissionsPolicyFeature::kGeolocation, + /* self_if_matches */ ORIGIN_A, /* matches_all_origins */ false, /* matches_opaque_src */ false, - {{ORIGIN_A, /*has_subdomain_wildcard=*/false}}, + {}, }, }); @@ -998,19 +1038,21 @@ ParsedPermissionsPolicy test_policy = { {mojom::blink::PermissionsPolicyFeature::kFullscreen, - /* allowed_origins */ + /*allowed_origins=*/ {blink::OriginWithPossibleWildcards(url_origin_a_, /*has_subdomain_wildcard=*/false), blink::OriginWithPossibleWildcards(url_origin_b_, /*has_subdomain_wildcard=*/false)}, - false, - false}, + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}, {mojom::blink::PermissionsPolicyFeature::kGeolocation, - /* allowed_origins */ + /*=allowed_origins*/ {blink::OriginWithPossibleWildcards(url_origin_a_, /*has_subdomain_wildcard=*/false)}, - false, - false}}; + /*self_if_matches=*/absl::nullopt, + /*matches_all_origins=*/false, + /*matches_opaque_src=*/false}}; ParsedPermissionsPolicy empty_policy = {}; };
diff --git a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc index fa3af85..1121040e 100644 --- a/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc +++ b/third_party/blink/renderer/core/view_transition/view_transition_style_tracker.cc
@@ -360,7 +360,7 @@ // (unless changed by something like z-index on the pseudo-elements). auto& root_object = root->GetLayoutObject(); auto& root_style = root_object.StyleRef(); - if (root_style.ViewTransitionName()) { + if (root_style.ViewTransitionName() && !root_object.IsFragmented()) { DCHECK(root_object.GetNode()); DCHECK(root_object.GetNode()->IsElementNode()); AddTransitionElement(DynamicTo<Element>(root_object.GetNode()), @@ -859,6 +859,13 @@ return false; } + // Check if the root element participates in a transition and has been + // fragmented. + if (new_root_data_ && + document_->documentElement()->GetLayoutObject()->IsFragmented()) { + return false; + } + for (auto& entry : element_data_map_) { auto& element_data = entry.value; if (!element_data->target_element) @@ -873,6 +880,11 @@ return false; } + // End the transition if any of the objects have become fragmented. + if (layout_object->IsFragmented()) { + return false; + } + // TODO(bokan): This doesn't account for the local offset of an inline // element within its container. The object-view-box inset will ensure the // snapshot is rendered in the correct place but the pseudo is positioned
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc index b7e7359..f1c3e6b 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
@@ -110,45 +110,43 @@ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"), "AudioWorkletHandler::Process"); - // Render and update the node state when the processor is ready with no error. - // We also need to check if the global scope is valid before we request - // the rendering in the AudioWorkletGlobalScope. - if (processor_ && !processor_->hasErrorOccurred()) { - // If the input is not connected, inform the processor with nullptr. - for (unsigned i = 0; i < NumberOfInputs(); ++i) { - inputs_[i] = Input(i).IsConnected() ? Input(i).Bus() : nullptr; - } - for (unsigned i = 0; i < NumberOfOutputs(); ++i) { - outputs_[i] = WrapRefCounted(Output(i).Bus()); - } - - for (const auto& param_name : param_value_map_.Keys()) { - auto* const param_handler = param_handler_map_.at(param_name); - AudioFloatArray* param_values = param_value_map_.at(param_name); - if (param_handler->HasSampleAccurateValues() && - param_handler->IsAudioRate()) { - param_handler->CalculateSampleAccurateValues( - param_values->Data(), static_cast<uint32_t>(frames_to_process)); - } else { - std::fill(param_values->Data(), - param_values->Data() + frames_to_process, - param_handler->FinalValue()); - } - } - - // Run the render code and check the state of processor. Finish the - // processor if needed. - if (!processor_->Process(inputs_, outputs_, param_value_map_) || - processor_->hasErrorOccurred()) { - FinishProcessorOnRenderThread(); - } - } else { - // The initialization of handler or the associated processor might not be - // ready yet or it is in the error state. If so, zero out the connected - // output. + // The associated processor is not ready, finished, or might be in an error + // state. If so, silence the connected outputs and return. + if (!processor_ || processor_->hasErrorOccurred()) { for (unsigned i = 0; i < NumberOfOutputs(); ++i) { Output(i).Bus()->Zero(); } + return; + } + + // If the input is not connected, inform the processor with nullptr. + for (unsigned i = 0; i < NumberOfInputs(); ++i) { + inputs_[i] = Input(i).IsConnected() ? Input(i).Bus() : nullptr; + } + for (unsigned i = 0; i < NumberOfOutputs(); ++i) { + outputs_[i] = WrapRefCounted(Output(i).Bus()); + } + + for (const auto& param_name : param_value_map_.Keys()) { + auto* const param_handler = param_handler_map_.at(param_name); + AudioFloatArray* param_values = param_value_map_.at(param_name); + if (param_handler->HasSampleAccurateValues() && + param_handler->IsAudioRate()) { + param_handler->CalculateSampleAccurateValues( + param_values->Data(), static_cast<uint32_t>(frames_to_process)); + } else { + std::fill(param_values->Data(), + param_values->Data() + frames_to_process, + param_handler->FinalValue()); + } + } + + // Run the render code and check the return value or the state of processor. + // If the return value is falsy, the processor's `Process()` function + // won't be called again. + if (!processor_->Process(inputs_, outputs_, param_value_map_) || + processor_->hasErrorOccurred()) { + FinishProcessorOnRenderThread(); } } @@ -238,6 +236,14 @@ Context()->NotifySourceNodeFinishedProcessing(this); processor_.Clear(); tail_time_ = 0; + + // The processor is cleared, so queue a task to mark this handler (and its + // associated AudioWorkletNode) is ready for GC. + PostCrossThreadTask( + *main_thread_task_runner_, FROM_HERE, + CrossThreadBindOnce( + &AudioWorkletHandler::MarkProcessorInactiveOnMainThread, + AsWeakPtr())); } void AudioWorkletHandler::NotifyProcessorError( @@ -250,4 +256,10 @@ static_cast<AudioWorkletNode*>(GetNode())->FireProcessorError(error_state); } +void AudioWorkletHandler::MarkProcessorInactiveOnMainThread() { + DCHECK(IsMainThread()); + + is_processor_active_ = false; +} + } // namespace blink
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.h b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.h index 844803c..b52f39f 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.h +++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.h
@@ -59,6 +59,9 @@ void NotifyProcessorError(AudioWorkletProcessorErrorState); + void MarkProcessorInactiveOnMainThread(); + bool IsProcessorActive() { return is_processor_active_; } + private: AudioWorkletHandler( AudioNode&, @@ -90,6 +93,11 @@ // Used only if number of inputs and outputs are 1. bool is_output_channel_count_given_ = false; + + // The active flag of the AudioWorkletProcessor is used to decide the + // lifecycle of an AudioWorkletNode and its handler. This flag becomes false + // when a processor stops invoking the user-defined `process()` callback. + bool is_processor_active_ = true; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc index 491ae5a5..d226460 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_node.cc
@@ -201,7 +201,7 @@ } bool AudioWorkletNode::HasPendingActivity() const { - return !context()->IsContextCleared(); + return GetWorkletHandler()->IsProcessorActive(); } AudioParamMap* AudioWorkletNode::parameters() const {
diff --git a/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc b/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc index 7af0b9f..6dddd16 100644 --- a/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc +++ b/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc
@@ -317,9 +317,9 @@ Bcp47Vector locales; locales.push_back(fallback_locale->LocaleForSkFontMgr()); - SkTypeface* typeface = font_manager_->matchFamilyStyleCharacter( + sk_sp<SkTypeface> typeface(font_manager_->matchFamilyStyleCharacter( family_name.c_str(), font_description.SkiaFontStyle(), locales.data(), - locales.size(), codepoint); + locales.size(), codepoint)); if (!typeface) return nullptr;
diff --git a/third_party/blink/tools/blinkpy/w3c/wpt_uploader.py b/third_party/blink/tools/blinkpy/w3c/wpt_uploader.py index 2d3398e..104b5d0 100644 --- a/third_party/blink/tools/blinkpy/w3c/wpt_uploader.py +++ b/third_party/blink/tools/blinkpy/w3c/wpt_uploader.py
@@ -65,12 +65,14 @@ initial_report, _, _ = body.partition(b'\n') reports.append(json.loads(initial_report)) merged_report = self.merge_reports(reports) - - with tempfile.TemporaryDirectory() as tmpdir: - path = os.path.join(tmpdir, "reports.json.gz") - with gzip.open(path, 'wt', encoding="utf-8") as zipfile: - json.dump(merged_report, zipfile) - rv = rv | self.upload_report(path) + if merged_report is None: + _log.error("No result to upload, skip...") + else: + with tempfile.TemporaryDirectory() as tmpdir: + path = os.path.join(tmpdir, "reports.json.gz") + with gzip.open(path, 'wt', encoding="utf-8") as zipfile: + json.dump(merged_report, zipfile) + rv = rv | self.upload_report(path) _log.info(" ") return rv @@ -164,7 +166,7 @@ def merge_reports(self, reports): if not reports: - return {} + return None merged_report = {} merged_report['run_info'] = reports[0]['run_info'] @@ -177,6 +179,8 @@ merged_report['results'].extend(report['results']) merged_report['time_end'] = max(merged_report['time_end'], report['time_end']) + if not merged_report['results']: + return None return merged_report def parse_args(self, argv):
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index b2585d48..029ec63 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -4011,7 +4011,7 @@ # Flaky devtools test for recalculating styles. crbug.com/1018177 http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.js [ Failure Pass ] -crbug.com/910979 http/tests/html/validation-bubble-oopif-clip.html [ Failure Pass ] +crbug.com/910979 http/tests/html/validation-bubble-oopif-clip.html [ Crash Failure Pass Timeout ] # Sheriff 2019-02-01, 2019-02-19 # These are crashy on Win10, and seem to leave processes lying around, causing the swarming
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/animation/align-no-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-align/animation/align-no-interpolation.html new file mode 100644 index 0000000..037743bd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-align/animation/align-no-interpolation.html
@@ -0,0 +1,27 @@ +<!DOCTYPE html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=help href="https://github.com/w3c/csswg-drafts/issues/4441"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/interpolation-testcommon.js"></script> + +<body> +<script> +test_no_interpolation({ + property: 'align-content', + from: 'initial', + to: 'baseline' +}); + +test_no_interpolation({ + property: 'align-items', + from: 'initial', + to: 'baseline' +}); + +test_no_interpolation({ + property: 'align-self', + from: 'initial', + to: 'baseline' +}); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-at-start-ignored-ref.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-at-start-ignored-ref.html new file mode 100644 index 0000000..626e03d0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-at-start-ignored-ref.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<title>View transitions: fragmented elements skipped (ref)</title> +<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/"> +<link rel="author" href="mailto:vmpstr@chromium.org"> + +<style> +body { background: pink } +#spacer { + width: 100px; + height: 950px; + background: lightgreen; +} +#container { + width: 500px; + columns: 2; + height: 500px; + visibility: hidden; +} +#target { + width: 200px; + height: 200px; + background: green; +} +#unrelated { + width: 100px; + height: 100px; + background: lightblue; +} +</style> +<div id=container> + <div id=spacer></div> + <div id=target></div> +</div> +<div id=unrelated></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-at-start-ignored.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-at-start-ignored.html new file mode 100644 index 0000000..3b8628c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-at-start-ignored.html
@@ -0,0 +1,56 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<title>View transitions: fragmented elements skipped</title> +<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/"> +<link rel="author" href="mailto:vmpstr@chromium.org"> +<link rel="match" href="fragmented-at-start-ignored-ref.html"> + +<script src="/common/reftest-wait.js"></script> +<style> +#spacer { + width: 100px; + height: 950px; + background: lightgreen; +} +#container { + width: 500px; + columns: 2; + height: 500px; +} +#target { + width: 200px; + height: 200px; + background: green; + view-transition-name: target; +} +#unrelated { + width: 100px; + height: 100px; + background: lightblue; + view-transition-name: unrelated; +} + +::view-transition { + background: pink; +} +::view-transition-group(root) { + animation-duration: 500s; + visibility: hidden; +} +::view-transition-group(target) { + border: 1px solid black; +} +</style> +<div id=container> + <div id=spacer></div> + <div id=target></div> +</div> +<div id=unrelated></div> + +<script> +function runTransition() { + document.startViewTransition().ready.then(takeScreenshot); +} + +requestAnimationFrame(() => requestAnimationFrame(runTransition)) +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-during-transition-skips-ref.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-during-transition-skips-ref.html new file mode 100644 index 0000000..269a6a2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-during-transition-skips-ref.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<title>View transitions: fragmented elements skipped</title> +<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/"> +<link rel="author" href="mailto:vmpstr@chromium.org"> + +<style> +#spacer { + width: 100px; + height: 950px; + background: lightgreen; +} +#container { + width: 500px; + height: 500px; + columns: 2; +} +#target { + width: 200px; + height: 200px; + background: green; +} +#unrelated { + width: 100px; + height: 100px; + background: lightblue; +} +</style> +<div id=container> + <div id=spacer></div> + <div id=target></div> +</div> +<div id=unrelated></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-during-transition-skips.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-during-transition-skips.html new file mode 100644 index 0000000..e872aa6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/fragmented-during-transition-skips.html
@@ -0,0 +1,62 @@ +<!DOCTYPE html> +<html class=reftest-wait> +<title>View transitions: fragmented elements skipped</title> +<link rel="help" href="https://www.w3.org/TR/css-view-transitions-1/"> +<link rel="author" href="mailto:vmpstr@chromium.org"> +<link rel="match" href="fragmented-during-transition-skips-ref.html"> + +<script src="/common/reftest-wait.js"></script> +<style> +#spacer { + width: 100px; + height: 950px; + background: lightgreen; +} +#container { + width: 500px; + height: 500px; +} +.fragment { + columns: 2; +} +#target { + width: 200px; + height: 200px; + background: green; + view-transition-name: target; +} +#unrelated { + width: 100px; + height: 100px; + background: lightblue; + view-transition-name: unrelated; +} + +::view-transition { + background: pink; +} +::view-transition-group(root) { + animation-duration: 500s; + visibility: hidden; +} +::view-transition-group(target) { + border: 1px solid black; +} +</style> +<div id=container> + <div id=spacer></div> + <div id=target></div> +</div> +<div id=unrelated></div> + +<script> +function runTransition() { + let t = document.startViewTransition(); + t.ready.then(() => { + requestAnimationFrame(() => container.classList.add("fragment")) + }); + t.finished.then(takeScreenshot); +} + +requestAnimationFrame(() => requestAnimationFrame(runTransition)) +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-ref.html b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-ref.html index c1159f8..a161cd8f 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-ref.html +++ b/third_party/blink/web_tests/external/wpt/css/css-view-transitions/named-element-with-fix-pos-child-ref.html
@@ -8,7 +8,6 @@ width: 100px; height: 100px; background: blue; - view-transition-name: target; } .child { width: 100px;
diff --git a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html index a5030f69..b0b07a8 100644 --- a/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html +++ b/third_party/blink/web_tests/external/wpt/speculation-rules/prefetch/document-rules.https.html
@@ -13,6 +13,8 @@ <meta name="variant" content="?include=not"> <meta name="variant" content="?include=invalidPredicate"> <meta name="variant" content="?include=linkInShadowTree"> +<meta name="variant" content="?include=linkHrefChanged"> +<meta name="variant" content="?include=newRuleSetAdded"> <body> <script> @@ -132,5 +134,37 @@ assert_equals(await isUrlPrefetched(url), 1); }, 'test that matching link in a shadow tree is prefetched'); + subsetTestByKey('linkHrefChanged', promise_test, async t => { + assert_implements(HTMLScriptElement.supports('speculationrules'), + 'Speculation Rules not supported'); + + insertDocumentRule({href_matches: "*\\?*foo=bar*"}); + + const url = getPrefetchUrl(); + const link = addLink(url); + await new Promise(resolve => t.step_timeout(resolve, 2000)); + assert_equals(await isUrlPrefetched(url), 0); + + const matching_url = getPrefetchUrl({foo: 'bar'}); + link.href = matching_url; + await new Promise(resolve => t.step_timeout(resolve, 2000)); + assert_equals(await isUrlPrefetched(matching_url), 1); + }, 'test that changing the href of an invalid link to a matching value triggers a prefetch'); + + subsetTestByKey('newRuleSetAdded', promise_test, async t => { + assert_implements(HTMLScriptElement.supports('speculationrules'), + 'Speculation Rules not supported'); + + insertDocumentRule({href_matches: "*\\?*foo=bar*"}); + const url = getPrefetchUrl({fizz: "buzz"}); + addLink(url); + await new Promise(resolve => t.step_timeout(resolve, 2000)); + assert_equals(await isUrlPrefetched(url), 0); + + insertDocumentRule({href_matches: "*\\?*fizz=buzz*"}); + await new Promise(resolve => t.step_timeout(resolve, 2000)); + assert_equals(await isUrlPrefetched(url), 1); + }, 'test that adding a second rule set triggers prefetch'); + </script> </body>
diff --git a/third_party/blink/web_tests/webaudio/internals/audioworkletnode-gc.https.html b/third_party/blink/web_tests/webaudio/internals/audioworkletnode-gc.https.html new file mode 100644 index 0000000..0682250 --- /dev/null +++ b/third_party/blink/web_tests/webaudio/internals/audioworkletnode-gc.https.html
@@ -0,0 +1,55 @@ +<!doctype html> +<html> +<head> + <title>Test GC of AudioWorkletNode</title> + <script src="../../resources/gc.js"></script> + <script src="../../resources/testharness.js"></script> + <script src="../../resources/testharnessreport.js"></script> +</head> +<body> + <script> + // Creates an AudioWorkletNode (and AudioWorkletProcessor) and destroy + // it immediately. Then manually trigger GC and check the number of + // living WebAudio objects. See: https://crbug.com/1298955 + promise_test(async () => { + // Check the pre-condition first. + assert_equals(internals.audioHandlerCount(), 0); + + const context = new AudioContext(); + const filePath = 'worklet-processors/falsy-processor.js'; + await context.audioWorklet.addModule(filePath); + + // Create a graph and start processing. + let workletNode = new AudioWorkletNode(context, 'falsy-processor'); + + return new Promise(resolve => { + // Prepare steps when the processor returns false. + workletNode.port.onmessage = async () => { + workletNode.port.onmessage = null; + workletNode.port.close(); + workletNode.disconnect(); + workletNode = null; + + // Assuming the "active flag" from the processor successfully marked + // the mathching AudioWorkletNode, this should collect the node. + await asyncGC(); + + // Force the WebAudio's deferred task handler to clean up + // deletable AudioHandlers. Without this, the deletable handlers + // will be deleted a bit later. + await context.close(); + + assert_equals(internals.audioHandlerCount(), 1); + resolve(); + }; + + // Start rendering the audio graph. + workletNode.connect(context.destination); + + // Two handlers: the destination node and a woklet node. + assert_equals(internals.audioHandlerCount(), 2); + }); + }, 'Test GC of AudioWorkletNode'); + </script> +</body> +</html>
diff --git a/third_party/blink/web_tests/webaudio/internals/worklet-processors/falsy-processor.js b/third_party/blink/web_tests/webaudio/internals/worklet-processors/falsy-processor.js new file mode 100644 index 0000000..691ae11 --- /dev/null +++ b/third_party/blink/web_tests/webaudio/internals/worklet-processors/falsy-processor.js
@@ -0,0 +1,18 @@ +class FalsyProcessor extends AudioWorkletProcessor { + constructor() { + super(); + } + + // Returns false immediately, and in turn this processor is going to end + // shortly and be marked for GC. See more information on + // AudioWorkletProcessor's return value: + // https://www.w3.org/TR/webaudio/#callback-audioworketprocess-callback + // https://www.w3.org/TR/webaudio/#rendering-a-graph + process() { + this.port.postMessage({}); + this.port.close(); + return false; + } +} + +registerProcessor('falsy-processor', FalsyProcessor); \ No newline at end of file
diff --git a/third_party/wayland-protocols/unstable/ui-controls/OWNERS b/third_party/wayland-protocols/unstable/ui-controls/OWNERS new file mode 100644 index 0000000..78058f5 --- /dev/null +++ b/third_party/wayland-protocols/unstable/ui-controls/OWNERS
@@ -0,0 +1 @@ +max@igalia.com
diff --git a/tools/binary_size/trybot_commit_size_checker.py b/tools/binary_size/trybot_commit_size_checker.py index aee2448..e01190b7 100755 --- a/tools/binary_size/trybot_commit_size_checker.py +++ b/tools/binary_size/trybot_commit_size_checker.py
@@ -21,8 +21,7 @@ --after-dir out/binary-size-results/$HASH2 \ --results-path output.json \ --staging-dir tmp \ - --local-test \ - -v + --local-test """ import argparse @@ -53,8 +52,6 @@ _HTML_REPORT_URL = ( 'https://chrome-supersize.firebaseapp.com/viewer.html?load_url={{' + _SIZEDIFF_FILENAME + '}}') -_MAX_DEX_METHOD_COUNT_INCREASE = 200 -_MAX_NORMALIZED_INCREASE = 16 * 1024 _MAX_PAK_INCREASE = 1024 _TRYBOT_MD_URL = ('https://chromium.googlesource.com/chromium/src/+/main/docs/' 'speed/binary_size/android_binary_size_trybot.md') @@ -99,6 +96,17 @@ return self.name < other.name +# See https://crbug.com/1426694 +def _MaxSizeIncrease(author, subject): + if 'AFDO' in subject: + return 1024 * 1024 + if 'Update V8' in subject: + return 100 * 1024 + if 'autoroll' in author: + return 50 * 1024 + return 16 * 1024 + + def _SymbolDiffHelper(title_fragment, symbols): added = symbols.WhereDiffStatusIs(models.DIFF_STATUS_ADDED) removed = symbols.WhereDiffStatusIs(models.DIFF_STATUS_REMOVED) @@ -129,7 +137,7 @@ return lines, _SizeDelta('Mutable Constants', 'symbols', 0, net_added) -def _CreateMethodCountDelta(symbols): +def _CreateMethodCountDelta(symbols, max_increase): symbols = symbols.WhereIsOnDemand(False) method_symbols = symbols.WhereInSection(models.SECTION_DEX_METHOD) method_lines, net_method_added = _SymbolDiffHelper('Methods', method_symbols) @@ -143,25 +151,25 @@ if method_lines: lines.extend(method_lines) - return lines, _SizeDelta('Dex Methods Count', 'methods', - _MAX_DEX_METHOD_COUNT_INCREASE, net_method_added) + return lines, _SizeDelta('Dex Methods Count', 'methods', max_increase, + net_method_added) -def _CreateResourceSizesDelta(before_dir, after_dir): +def _CreateResourceSizesDelta(before_dir, after_dir, max_increase): sizes_diff = diagnose_bloat.ResourceSizesDiff() sizes_diff.ProduceDiff(before_dir, after_dir) - return sizes_diff.Summary(), _SizeDelta( - 'Normalized APK Size', 'bytes', _MAX_NORMALIZED_INCREASE, - sizes_diff.summary_stat.value) + return sizes_diff.Summary(), _SizeDelta('Normalized APK Size', 'bytes', + max_increase, + sizes_diff.summary_stat.value) -def _CreateBaseModuleResourceSizesDelta(before_dir, after_dir): +def _CreateBaseModuleResourceSizesDelta(before_dir, after_dir, max_increase): sizes_diff = diagnose_bloat.ResourceSizesDiff(include_sections=['base']) sizes_diff.ProduceDiff(before_dir, after_dir) return sizes_diff.DetailedResults(), _SizeDelta( - 'Base Module Size', 'bytes', _MAX_NORMALIZED_INCREASE, + 'Base Module Size', 'bytes', max_increase, sizes_diff.CombinedSizeChangeForSection('base')) @@ -318,11 +326,10 @@ '--local-test', action='store_true', help='Allow input directories to be diagnose_bloat.py ones.') - parser.add_argument('-v', '--verbose', action='store_true') args = parser.parse_args() - if args.verbose: - logging.basicConfig(level=logging.INFO) + logging.basicConfig(level=logging.INFO, + format='%(levelname).1s %(relativeCreated)6d %(message)s') before_path = pathlib.Path(args.before_dir) after_path = pathlib.Path(args.after_dir) @@ -350,6 +357,11 @@ after_path_resolver(f) for f in config['mapping_files'] ] + max_size_increase = _MaxSizeIncrease(args.author, args.review_subject) + # We do not care as much about method count anymore, so this limit is set + # such that it is very unlikely to be hit. + max_methods_increase = 200 if '-autoroll' not in args.author else 800 + logging.info('Creating Supersize diff') supersize_diff_lines, delta_size_info = _CreateSupersizeDiff( before_path_resolver(size_filename), after_path_resolver(size_filename), @@ -358,9 +370,9 @@ changed_symbols = delta_size_info.raw_symbols.WhereDiffStatusIs( models.DIFF_STATUS_UNCHANGED).Inverted() - # Monitor dex method count since the "multidex limit" is a thing. logging.info('Checking dex symbols') - dex_delta_lines, dex_delta = _CreateMethodCountDelta(changed_symbols) + dex_delta_lines, dex_delta = _CreateMethodCountDelta(changed_symbols, + max_methods_increase) size_deltas = {dex_delta} metrics = {(dex_delta, _DEX_SYMBOLS_LOG)} @@ -388,13 +400,14 @@ # Normalized APK Size is the main metric we use to monitor binary size. logging.info('Creating sizes diff') resource_sizes_lines, resource_sizes_delta = (_CreateResourceSizesDelta( - args.before_dir, args.after_dir)) + args.before_dir, args.after_dir, max_size_increase)) size_deltas.add(resource_sizes_delta) metrics.add((resource_sizes_delta, _RESOURCE_SIZES_LOG)) logging.info('Creating base module sizes diff') base_resource_sizes_lines, base_resource_sizes_delta = ( - _CreateBaseModuleResourceSizesDelta(args.before_dir, args.after_dir)) + _CreateBaseModuleResourceSizesDelta(args.before_dir, args.after_dir, + max_size_increase)) size_deltas.add(base_resource_sizes_delta) metrics.add((base_resource_sizes_delta, _BASE_RESOURCE_SIZES_LOG)) @@ -413,7 +426,6 @@ passing_deltas = set(d for d in size_deltas if d.IsAllowable()) failing_deltas = size_deltas - passing_deltas - is_roller = '-autoroll' in args.author failing_checks_text = '\n'.join(d.explanation for d in sorted(failing_deltas)) passing_checks_text = '\n'.join(d.explanation for d in sorted(passing_deltas)) checks_text = """\ @@ -429,13 +441,6 @@ """.format(failing_checks_text, passing_checks_text, _TRYBOT_MD_URL) status_code = int(bool(failing_deltas)) - - # Give rollers a free pass, except for mutable constants. - # Mutable constants are rare, and other regressions are generally noticed in - # size graphs and can be investigated after-the-fact. - if is_roller and mutable_constants_delta not in failing_deltas: - status_code = 0 - see_docs_lines = ['\n', f'For more details: {_TRYBOT_MD_URL}\n'] summary = '<br>' + checks_text.replace('\n', '<br>')
diff --git a/tools/mac/BUILD.gn b/tools/mac/BUILD.gn index 5527752..097e2edf7 100644 --- a/tools/mac/BUILD.gn +++ b/tools/mac/BUILD.gn
@@ -5,12 +5,12 @@ group("mac") { testonly = true deps = [ - ":dsc_extract", + ":dsc_extractor", "power:all", ] } -executable("dsc_extract") { +executable("dsc_extractor") { testonly = true - sources = [ "dsc_extract.cc" ] + sources = [ "dsc_extractor.cc" ] }
diff --git a/tools/mac/dsc_extract.cc b/tools/mac/dsc_extractor.cc similarity index 100% rename from tools/mac/dsc_extract.cc rename to tools/mac/dsc_extractor.cc
diff --git a/tools/make_gtest_filter.py b/tools/make_gtest_filter.py index 1305456..9e8bb4a 100755 --- a/tools/make_gtest_filter.py +++ b/tools/make_gtest_filter.py
@@ -243,6 +243,7 @@ # Note: Test names have the following structures: # * FixtureName.TestName # * InstantiationName/FixtureName.TestName/## + # * FixtureName.TestName/## # Since this script doesn't parse instantiations, we generate filters to # match either regular tests or instantiated tests. if args.wildcard_compress: @@ -251,10 +252,12 @@ elif args.class_only: fixtures = set([t.split('.')[0] for t in tests]) test_filters = [c + '.*' for c in fixtures] + \ - ['*/' + c + '.*/*' for c in fixtures] + ['*/' + c + '.*/*' for c in fixtures] + \ + [c + '.*/*' for c in fixtures] else: test_filters = [c for c in tests] + \ - ['*/' + c + '/*' for c in tests] + ['*/' + c + '/*' for c in tests] + \ + [c + '/*' for c in tests] if args.as_exclusions: test_filters = ['-' + x for x in test_filters]
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 47080392..acd81dc 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -588,6 +588,7 @@ 'codesearch-gen-chromium-android': 'codesearch_gen_chromium_android_bot', 'codesearch-gen-chromium-chromiumos': 'codesearch_gen_chromium_chromiumos_bot', 'codesearch-gen-chromium-fuchsia': 'codesearch_gen_chromium_fuchsia_bot', + 'codesearch-gen-chromium-ios': 'codesearch_gen_chromium_ios_bot', 'codesearch-gen-chromium-lacros': 'codesearch_gen_chromium_lacros_bot', 'codesearch-gen-chromium-linux': 'codesearch_gen_chromium_bot', 'codesearch-gen-chromium-mac': 'codesearch_gen_chromium_mac_bot', @@ -1145,6 +1146,7 @@ 'gen-android-try': 'codesearch_gen_chromium_android_bot', 'gen-chromiumos-try': 'codesearch_gen_chromium_chromiumos_bot', 'gen-fuchsia-try': 'codesearch_gen_chromium_fuchsia_bot', + 'gen-ios-try': 'codesearch_gen_chromium_ios_bot', 'gen-lacros-try': 'codesearch_gen_chromium_lacros_bot', 'gen-linux-try': 'codesearch_gen_chromium_bot', 'gen-mac-try': 'codesearch_gen_chromium_mac_bot', @@ -2444,6 +2446,10 @@ 'codesearch_release', 'fuchsia', ], + 'codesearch_gen_chromium_ios_bot': [ + 'codesearch', 'ios', + ], + # Lacros uses different gn args to build for chromeOS device vs. Linux. For # simplicity, we only generate codesearch x-refs for lacros on Linux. 'codesearch_gen_chromium_lacros_bot': [
diff --git a/tools/mb/mb_config_expectations/chromium.infra.codesearch.json b/tools/mb/mb_config_expectations/chromium.infra.codesearch.json index 0132555..a058e83c 100644 --- a/tools/mb/mb_config_expectations/chromium.infra.codesearch.json +++ b/tools/mb/mb_config_expectations/chromium.infra.codesearch.json
@@ -38,6 +38,19 @@ "use_goma": true } }, + "codesearch-gen-chromium-ios": { + "gn_args": { + "blink_enable_generated_code_formatting": true, + "clang_use_chrome_plugins": false, + "enable_kythe_annotations": true, + "is_clang": true, + "is_component_build": true, + "is_debug": true, + "symbol_level": 1, + "target_os": "ios", + "use_goma": true + } + }, "codesearch-gen-chromium-lacros": { "gn_args": { "blink_enable_generated_code_formatting": true,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.codesearch.json b/tools/mb/mb_config_expectations/tryserver.chromium.codesearch.json index 3a3dda6..2b8c58a 100644 --- a/tools/mb/mb_config_expectations/tryserver.chromium.codesearch.json +++ b/tools/mb/mb_config_expectations/tryserver.chromium.codesearch.json
@@ -38,6 +38,19 @@ "use_goma": true } }, + "gen-ios-try": { + "gn_args": { + "blink_enable_generated_code_formatting": true, + "clang_use_chrome_plugins": false, + "enable_kythe_annotations": true, + "is_clang": true, + "is_component_build": true, + "is_debug": true, + "symbol_level": 1, + "target_os": "ios", + "use_goma": true + } + }, "gen-lacros-try": { "gn_args": { "blink_enable_generated_code_formatting": true,
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 9b2fb30..c4cee98 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -36738,6 +36738,9 @@ </action> <action-suffix separator="_" ordering="suffix"> + <suffix name="AdaptiveButtonInTopToolbarCustomization_AddToBookmarks" + label="For AdaptiveButtonInTopToolbarCustomization add to bookmarks + feature."/> <suffix name="AdaptiveButtonInTopToolbarCustomization_NewTab" label="For AdaptiveButtonInTopToolbarCustomization new tab feature."/> <suffix name="AdaptiveButtonInTopToolbarCustomization_Share"
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 5e6fc16a..6d181c0 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -176,6 +176,18 @@ <int value="2" label="ChromeOS quick settings cast menu"/> </enum> +<enum name="AccessCodeCastDiscoveryTypeAndSource"> + <int value="0" label="Unknown discovery type or source"/> + <int value="1" label="Saved device and Presentation source"/> + <int value="2" label="Saved device and Tab mirror source"/> + <int value="3" label="Saved device and Desktop mirror source"/> + <int value="4" label="Saved device and Remote playback source"/> + <int value="5" label="New device and Presentation source"/> + <int value="6" label="New device and Tab mirror source"/> + <int value="7" label="New device and Desktop mirror source"/> + <int value="8" label="New device and Remote playback source"/> +</enum> + <enum name="AccessCodeCastUiTabSwitcherUsage"> <int value="0" label="Tab switcher UI shown and not used"/> <int value="1" label="Tab switcher UI shown and used to switch tabs"/> @@ -1452,6 +1464,7 @@ <int value="6" label="Price tracking"/> <int value="7" label="Reader mode"/> <int value="8" label="Translate"/> + <int value="9" label="Add to bookmarks"/> </enum> <enum name="AdaptiveToolbarRadioButtonState"> @@ -1464,6 +1477,8 @@ <int value="6" label="Voice"/> <int value="7" label="Translate"/> <int value="8" label="Auto with translate"/> + <int value="9" label="Add to bookmarks"/> + <int value="10" label="Auto with add to bookmarks"/> </enum> <enum name="AdaptiveToolbarSegmentSwitch"> @@ -44879,6 +44894,12 @@ (Lacros only)"/> <int value="2" label="Quit at end: window closed, experience considered 'finished'"/> + <int value="3" + label="Abort task: user runs experience while it's already running. + Experience not considered 'finished'"/> + <int value="4" + label="Abandon flow: user does something to abandon the FRE (open a new + window etc..), experience is considered 'finished'"/> </enum> <enum name="FirstRunLaunchSource"> @@ -57891,7 +57912,10 @@ <int value="-1986814580" label="om"/> <int value="-1920649864" label="an"/> <int value="-1898669966" label="zh-CN"/> - <int value="-1895779836" label="empty string"/> + <int value="-1895779836" label="empty string"> + Reported as page source language when language detection code was not run + (i.e. page closed or navigated away before running). + </int> <int value="-1872667487" label="rm"/> <int value="-1855113037" label="vi"/> <int value="-1835493637" label="ce"/> @@ -60672,6 +60696,7 @@ <int value="-891856063" label="MidiManagerAndroid:enabled"/> <int value="-890224928" label="DownloadBubbleV2:enabled"/> <int value="-889670978" label="AssistantRoutines:disabled"/> + <int value="-888336510" label="NtpSingleRowShortcuts:enabled"/> <int value="-887101831" label="StoreHoursAndroid:disabled"/> <int value="-887094098" label="ForcedColors:enabled"/> <int value="-886912558" label="ChromeHomePromo:enabled"/> @@ -61146,6 +61171,8 @@ <int value="-632030508" label="NativeWindowNavButtons:disabled"/> <int value="-631740127" label="inert-visual-viewport"/> <int value="-631614101" label="CameraSystemWebApp:enabled"/> + <int value="-631136107" + label="PageContentAnnotationsPersistSalientImageMetadata:disabled"/> <int value="-630256330" label="EnableDrDc:enabled"/> <int value="-629084845" label="UseToastManager:disabled"/> <int value="-629041881" label="MuteNotificationsDuringScreenShare:disabled"/> @@ -61745,6 +61772,8 @@ <int value="-290329565" label="CrosVmCupsProxy:disabled"/> <int value="-288316828" label="enable-delegated-renderer"/> <int value="-286603268" label="hide-android-files-in-files-app"/> + <int value="-285499775" + label="AdaptiveButtonInTopToolbarAddToBookmarks:enabled"/> <int value="-284694765" label="JourneysIncludeSyncedVisits:disabled"/> <int value="-284547865" label="UnifiedConsent:enabled"/> <int value="-284470280" label="ShelfPalmRejectionTouchArea:enabled"/> @@ -61777,6 +61806,8 @@ label="MaintainShelfStateWhenEnteringOverview:disabled"/> <int value="-273570157" label="EnableBloom:enabled"/> <int value="-273534119" label="LacrosAuraCapture:enabled"/> + <int value="-272668067" + label="PageContentAnnotationsPersistSalientImageMetadata:enabled"/> <int value="-272544597" label="AccessibilitySelectToSpeakContextMenuOption:enabled"/> <int value="-272266925" label="ForceStartupSigninPromo:enabled"/> @@ -62146,6 +62177,7 @@ <int value="-64839201" label="SyncUSSAutofillWalletData:disabled"/> <int value="-64824628" label="VizHitTestSurfaceLayer:disabled"/> <int value="-64747770" label="IncognitoDownloadsWarning:disabled"/> + <int value="-63207112" label="NtpSingleRowShortcuts:disabled"/> <int value="-59530055" label="ChromeVoxArcSupport:enabled"/> <int value="-59401847" label="ContentSuggestionsLargeThumbnail:disabled"/> <int value="-58338160" label="ChromeShareLongScreenshot:enabled"/> @@ -62339,6 +62371,7 @@ <int value="38904620" label="TabSwitcherLongpressMenu:enabled"/> <int value="39035791" label="AutofillTouchToFillForCreditCardsAndroid:enabled"/> + <int value="39822765" label="ShimlessRMADiagnosticPage:disabled"/> <int value="41881657" label="MessagesForAndroidAdsBlocked:enabled"/> <int value="41990393" label="ContextMenuGoogleLensChip:enabled"/> <int value="42098736" label="TranslateAndroidManualTrigger:disabled"/> @@ -62984,6 +63017,7 @@ <int value="392782890" label="SafeBrowsingTelemetryForApkDownloads:enabled"/> <int value="393569083" label="OmniboxMatchToolbarAndStatusBarColor:enabled"/> <int value="393704200" label="account-consistency"/> + <int value="393869264" label="ShimlessRMADiagnosticPage:enabled"/> <int value="394384982" label="GaiaIdCacheInAccountManagerFacade:enabled"/> <int value="395148768" label="AutofillFillIbanFields:disabled"/> <int value="397275669" label="QuickCommands:disabled"/> @@ -63244,6 +63278,8 @@ <int value="550387510" label="NTPAssetDownloadSuggestions:disabled"/> <int value="550411207" label="enable-webgpu-developer-features"/> <int value="550741462" label="WebAppBorderless:disabled"/> + <int value="552143503" + label="AdaptiveButtonInTopToolbarAddToBookmarks:disabled"/> <int value="552158955" label="NotificationPermissionBottomSheet:enabled"/> <int value="552317551" label="MediaAppHandlesPdf:disabled"/> <int value="552421509" label="AssistMultiWordExpanded:enabled"/> @@ -63874,6 +63910,7 @@ <int value="904159815" label="VideoPlayerAppHidden:disabled"/> <int value="904437796" label="OmniboxBlurWithEscape:disabled"/> <int value="904811479" label="query-tiles-enable-trending"/> + <int value="907051864" label="UseMultiPlaneFormatForHardwareVideo:disabled"/> <int value="907056713" label="DetectFormSubmissionOnFormClear:enabled"/> <int value="908302031" label="OmniboxUIExperimentElideSuggestionUrlAfterHost:enabled"/> @@ -64223,6 +64260,7 @@ <int value="1102035446" label="AutofillUpstreamAuthenticatePreflightCall:enabled"/> <int value="1102780374" label="ClickToCallDetectionV2:disabled"/> + <int value="1104206686" label="UseMultiPlaneFormatForHardwareVideo:enabled"/> <int value="1104948452" label="manual-enhanced-bookmarks-optout"/> <int value="1105182444" label="ChromeCleanupScanCompletedNotification:disabled"/> @@ -92855,16 +92893,6 @@ <int value="8" label="Throttle prevented the prefetch"/> </enum> -<enum name="SearchPrefetchResponseDataReaderStatus"> - <int value="0" label="kCreated"/> - <int value="1" label="kStarted"/> - <int value="2" label="kCompleted"/> - <int value="3" label="kFailedWithErrorCode"/> - <int value="4" label="kDataWritingFailure"/> - <int value="5" label="kCanceledByClient"/> - <int value="6" label="kCanceledByLoader"/> -</enum> - <enum name="SearchPrefetchServingReason"> <int value="0" label="Served a prefetch response"/> <int value="1" label="Search engine not set"/>
diff --git a/tools/metrics/histograms/metadata/autofill/histograms.xml b/tools/metrics/histograms/metadata/autofill/histograms.xml index e2c4d7e..55b89ad6 100644 --- a/tools/metrics/histograms/metadata/autofill/histograms.xml +++ b/tools/metrics/histograms/metadata/autofill/histograms.xml
@@ -2980,7 +2980,7 @@ <histogram name="Autofill.OfferNotificationBubblePromoCodeButtonClicked.{BubbleType}" - enum="BooleanClicked" expires_after="2023-05-01"> + enum="BooleanClicked" expires_after="2024-04-01"> <owner>jsaul@google.com</owner> <owner>siyua@chromium.org</owner> <owner>payments-autofill-team@google.com</owner> @@ -3007,7 +3007,7 @@ </histogram> <histogram name="Autofill.OfferNotificationBubbleSuppressed.{BubbleType}" - enum="BooleanSuppressed" expires_after="2023-05-01"> + enum="BooleanSuppressed" expires_after="2024-04-01"> <owner>jsaul@google.com</owner> <owner>yuezhanggg@chromium.org</owner> <owner>siyua@chromium.org</owner> @@ -3570,7 +3570,7 @@ </histogram> <histogram name="Autofill.SaveCardCardholderNamePrefilled" enum="Boolean" - expires_after="2023-05-01"> + expires_after="2024-04-01"> <owner>jsaul@google.com</owner> <owner>payments-autofill-team@google.com</owner> <summary> @@ -3581,7 +3581,7 @@ </histogram> <histogram name="Autofill.SaveCardCardholderNameWasEdited" enum="Boolean" - expires_after="2023-05-01"> + expires_after="2024-04-01"> <owner>jsaul@google.com</owner> <owner>payments-autofill-team@google.com</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/cryptohome/histograms.xml b/tools/metrics/histograms/metadata/cryptohome/histograms.xml index a19ae9a..11540ac9 100644 --- a/tools/metrics/histograms/metadata/cryptohome/histograms.xml +++ b/tools/metrics/histograms/metadata/cryptohome/histograms.xml
@@ -749,7 +749,7 @@ </histogram> <histogram name="Cryptohome.TimeToAuthSessionRemoveAuthFactorUSS" units="ms" - expires_after="2023-05-01"> + expires_after="2023-11-01"> <owner>thomascedeno@google.com</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -761,7 +761,7 @@ </histogram> <histogram name="Cryptohome.TimeToAuthSessionRemoveAuthFactorVK" units="ms" - expires_after="2023-05-01"> + expires_after="2023-11-01"> <owner>thomascedeno@google.com</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -795,7 +795,7 @@ </histogram> <histogram name="Cryptohome.TimeToCreatePersistentUser" units="ms" - expires_after="2023-05-01"> + expires_after="2023-11-01"> <owner>thomascedeno@google.com</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -1068,7 +1068,7 @@ </histogram> <histogram name="Cryptohome.{AuthSessionFunction}.{AuthBlockType}" units="ms" - expires_after="2023-05-01"> + expires_after="2023-11-01"> <owner>thomascedeno@google.com</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary> @@ -1104,7 +1104,7 @@ </histogram> <histogram name="Cryptohome.{AuthSessionLifetime}.{Type}" units="ms" - expires_after="2023-05-01"> + expires_after="2023-11-01"> <owner>thomascedeno@google.com</owner> <owner>cros-hwsec+uma@chromium.org</owner> <summary>
diff --git a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml index c833452..6bd7fdd 100644 --- a/tools/metrics/histograms/metadata/feature_engagement/histograms.xml +++ b/tools/metrics/histograms/metadata/feature_engagement/histograms.xml
@@ -28,6 +28,8 @@ </variants> <variants name="IPHFeature"> + <variant name="IPH_AdaptiveButtonInTopToolbarCustomization_AddToBookmarks" + summary="the add to bookmarks adaptive button in the top toolbar"/> <variant name="IPH_AdaptiveButtonInTopToolbarCustomization_NewTab" summary="the new tab adaptive button in the top toolbar"/> <variant name="IPH_AdaptiveButtonInTopToolbarCustomization_Share"
diff --git a/tools/metrics/histograms/metadata/media/histograms.xml b/tools/metrics/histograms/metadata/media/histograms.xml index 49e5b4b..7e67422 100644 --- a/tools/metrics/histograms/metadata/media/histograms.xml +++ b/tools/metrics/histograms/metadata/media/histograms.xml
@@ -2407,7 +2407,7 @@ <owner>xhwang@chromium.org</owner> <owner>media-dev@chromium.org</owner> <summary> - Whether a MediaFoundationService process crash is within 2 seconds after + Whether a MediaFoundationService process crash is within 5 seconds after power or display change. Reported when the MediaFoundationService process crashes. </summary> @@ -2420,7 +2420,7 @@ <owner>media-dev@chromium.org</owner> <summary> HRESULTs associated with errors happened in the MediaFoundationService - process within 2 seconds after power or display change. + process within 5 seconds after power or display change. </summary> </histogram> @@ -2435,6 +2435,17 @@ </summary> </histogram> +<histogram name="Media.EME.MediaFoundationService.HardwareContextReset" + enum="BooleanAfterPowerOrDisplayChange" expires_after="2023-05-07"> + <owner>xhwang@chromium.org</owner> + <owner>media-dev@chromium.org</owner> + <summary> + Whether a HardwareContextReset event happened in the MediaFoundationService + process within 5 seconds after power or display change. Reported whenever + such an event happens. + </summary> +</histogram> + <histogram name="Media.EME.MediaFoundationService.IsKeySystemSupported" units="ms" expires_after="2023-08-08"> <owner>xhwang@chromium.org</owner> @@ -5798,7 +5809,7 @@ </histogram> <histogram name="Media.WebMediaPlayerImpl.HLS.HasAccessControl" enum="Boolean" - expires_after="2023-04-01"> + expires_after="2023-08-08"> <owner>cassew@chromium.org</owner> <owner>tguilbert@chromium.org</owner> <owner>media-dev@chromium.org</owner> @@ -5811,7 +5822,7 @@ </histogram> <histogram name="Media.WebMediaPlayerImpl.HLS.IsCorsCrossOrigin" enum="Boolean" - expires_after="2023-04-01"> + expires_after="2023-08-08"> <owner>cassew@chromium.org</owner> <owner>tguilbert@chromium.org</owner> <owner>media-dev@chromium.org</owner> @@ -5837,7 +5848,7 @@ </histogram> <histogram name="Media.WebMediaPlayerImpl.HLS{Variant}.MimeType" - enum="MimeTypeOfHlsManifest" expires_after="2023-04-01"> + enum="MimeTypeOfHlsManifest" expires_after="2023-08-08"> <owner>cassew@chromium.org</owner> <owner>lukasza@chromium.org</owner> <owner>media-dev@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/omnibox/histograms.xml b/tools/metrics/histograms/metadata/omnibox/histograms.xml index 2eb31a55..8d51d1b 100644 --- a/tools/metrics/histograms/metadata/omnibox/histograms.xml +++ b/tools/metrics/histograms/metadata/omnibox/histograms.xml
@@ -1538,18 +1538,6 @@ </token> </histogram> -<histogram name="Omnibox.SearchPreload.ResponseDataReaderFinalStatus.Prerender" - enum="SearchPrefetchResponseDataReaderStatus" expires_after="2023-08-02"> - <owner>lingqi@chromium.org</owner> - <owner>ryansturm@chromium.org</owner> - <owner>chrome-prerendering@google.com</owner> - <summary> - Tracks whether the StreamingSearchPrefetchURLLoader::ResponseReader can - successfully serving to prerender clients. Recorded when a - `StreamingSearchPrefetchURLLoader::ResponseReader` is destroyed. - </summary> -</histogram> - <histogram name="Omnibox.SearchProviderMatches" units="units" expires_after="2022-09-11"> <obsolete>
diff --git a/tools/metrics/histograms/metadata/others/histograms.xml b/tools/metrics/histograms/metadata/others/histograms.xml index 53e37c1f..bcd7505 100644 --- a/tools/metrics/histograms/metadata/others/histograms.xml +++ b/tools/metrics/histograms/metadata/others/histograms.xml
@@ -254,6 +254,17 @@ </summary> </histogram> +<histogram name="AccessCodeCast.Session.RouteDiscoveryTypeAndSource" + enum="AccessCodeCastDiscoveryTypeAndSource" expires_after="2023-08-20"> + <owner>bzielinski@google.com</owner> + <owner>cros-edu-eng@google.com</owner> + <summary> + The discovery type of the associated sink and the cast media source for an + access code route. Recorded when at the start of a local access code route. + Logged only on desktop platforms. + </summary> +</histogram> + <histogram name="AccessCodeCast.Session.RouteDuration" units="ms" expires_after="2023-08-13"> <owner>bzielinski@google.com</owner>
diff --git a/tools/metrics/histograms/metadata/sharing/histograms.xml b/tools/metrics/histograms/metadata/sharing/histograms.xml index 9b71023f..b78a35a6 100644 --- a/tools/metrics/histograms/metadata/sharing/histograms.xml +++ b/tools/metrics/histograms/metadata/sharing/histograms.xml
@@ -182,6 +182,17 @@ </summary> </histogram> +<histogram name="Sharing.PreparePreviewFaviconDuration" units="ms" + expires_after="2023-07-21"> + <owner>wenyufu@chromium.org</owner> + <owner>src/chrome/browser/share/OWNERS</owner> + <summary> + The time to download the favicon as the image preview for sharing an link + using Android share sheet. Recorded when sharing a link with Android share + sheet only. + </summary> +</histogram> + <histogram name="Sharing.RemoteCopyDecodeImageTime" units="ms" expires_after="M97"> <owner>mvanouwerkerk@chromium.org</owner>
diff --git a/tools/metrics/histograms/metadata/startup/histograms.xml b/tools/metrics/histograms/metadata/startup/histograms.xml index afaa578..e6991b8 100644 --- a/tools/metrics/histograms/metadata/startup/histograms.xml +++ b/tools/metrics/histograms/metadata/startup/histograms.xml
@@ -186,11 +186,31 @@ - For WebApps, PWAs or WebApks. + Bugs: + + - This metric does not get recorded when the first navigation commit happens + before post-native initialization. This behaviour is not intentional, see + crbug.com/1273097. TimeToFirstVisibleContent2 addresses this issue. + This histogram is of special interest to the chrome-analysis-team@. Do not change its semantics or retire it without talking to them first. </summary> </histogram> +<histogram name="Startup.Android.Cold.TimeToFirstVisibleContent2" units="ms" + expires_after="2023-09-22"> + <owner>yfriedman@chromium.org</owner> + <owner>pasko@chromium.org</owner> + <owner>fredmello@chromium.org</owner> + <summary> + The time from Chrome tabbed activity creation to the moment the Chrome first + appears ready. + + Currently experimental. Has the same semantics as + Startup.Android.Cold.TimeToFirstVisibleContent, without the known bug. + </summary> +</histogram> + <histogram name="Startup.Android.Cold.TimeToVisibleContent" units="ms" expires_after="2023-08-20"> <owner>ckitagawa@chromium.org</owner>
diff --git a/tools/metrics/structured/structured.xml b/tools/metrics/structured/structured.xml index 32df371..52f8f56 100644 --- a/tools/metrics/structured/structured.xml +++ b/tools/metrics/structured/structured.xml
@@ -671,6 +671,12 @@ Name of the app that was launched. Names are UTF-16 string encoding. </summary> </metric> + <metric name="ResultCategory" type="int"> + <summary> + Enum representing the category of app the result is. This enum should map to + ash::SearchResultType. + </summary> + </metric> </event> <event name="UserLogin">
diff --git a/ui/accessibility/accessibility_features.cc b/ui/accessibility/accessibility_features.cc index 68f8ab57f..e8ef83d 100644 --- a/ui/accessibility/accessibility_features.cc +++ b/ui/accessibility/accessibility_features.cc
@@ -263,15 +263,6 @@ return base::FeatureList::IsEnabled( ::features::kAccessibilityFormControlsMode); } - -BASE_FEATURE(kOptimizeAccessibilityUiThreadWork, - "OptimizeAccessibilityUiThreadWork", - base::FEATURE_ENABLED_BY_DEFAULT); - -bool IsOptimizeAccessibilityUiThreadWorkEnabled() { - return base::FeatureList::IsEnabled( - ::features::kOptimizeAccessibilityUiThreadWork); -} #endif // BUILDFLAG(IS_ANDROID) #if !BUILDFLAG(IS_ANDROID)
diff --git a/ui/accessibility/accessibility_features.h b/ui/accessibility/accessibility_features.h index 4e288c0b..65fddcdf 100644 --- a/ui/accessibility/accessibility_features.h +++ b/ui/accessibility/accessibility_features.h
@@ -207,10 +207,6 @@ // Returns true if the form controls AXMode is enabled. AX_BASE_EXPORT bool IsAccessibilityFormControlsAXModeEnabled(); -AX_BASE_EXPORT BASE_DECLARE_FEATURE(kOptimizeAccessibilityUiThreadWork); - -bool IsOptimizeAccessibilityUiThreadWorkEnabled(); - #endif // BUILDFLAG(IS_ANDROID) #if !BUILDFLAG(IS_ANDROID)
diff --git a/ui/base/interaction/interactive_test.h b/ui/base/interaction/interactive_test.h index b671c724..c6737fb 100644 --- a/ui/base/interaction/interactive_test.h +++ b/ui/base/interaction/interactive_test.h
@@ -396,6 +396,11 @@ return *private_test_impl_; } + // Adds a step or steps to the end of an existing MultiStep. Shorthand for + // making one or more calls to `std::vector::emplace_back`. + static void AddStep(MultiStep& dest, StepBuilder src); + static void AddStep(MultiStep& dest, MultiStep src); + private: // Implementation for RunTestSequenceInContext(). bool RunTestSequenceImpl(ElementContext context, @@ -406,9 +411,6 @@ template <typename T> static void AddStep(InteractionSequence::Builder& builder, T&& step); - static void AddStep(MultiStep& dest, StepBuilder src); - static void AddStep(MultiStep& dest, MultiStep src); - std::unique_ptr<internal::InteractiveTestPrivate> private_test_impl_; };
diff --git a/ui/gl/init/gl_display_initializer.cc b/ui/gl/init/gl_display_initializer.cc index 09ecfaa..fb368d05 100644 --- a/ui/gl/init/gl_display_initializer.cc +++ b/ui/gl/init/gl_display_initializer.cc
@@ -56,16 +56,6 @@ (!command_line->HasSwitch(switches::kUseANGLE) || requested_renderer == kANGLEImplementationDefaultName); - // If we're already requesting an ANGLE implementation, use it instead of the - // default. - // if ((requested_renderer.empty() || - // requested_renderer == kANGLEImplementationDefaultName) && - // gl::GetGLImplementationParts().gl == gl::kGLImplementationEGLANGLE) { - // use_angle_default = false; - // requested_renderer = - // GetGLImplementationANGLEName(gl::GetGLImplementationParts()); - // } - if (supports_angle_null && (requested_renderer == kANGLEImplementationNullName || gl::GetANGLEImplementation() == ANGLEImplementation::kNull)) {
diff --git a/ui/message_center/public/cpp/notification_types.h b/ui/message_center/public/cpp/notification_types.h index d6da1a3c..ec113cb8 100644 --- a/ui/message_center/public/cpp/notification_types.h +++ b/ui/message_center/public/cpp/notification_types.h
@@ -12,7 +12,7 @@ enum NotificationType { NOTIFICATION_TYPE_SIMPLE = 0, DEPRECATED_NOTIFICATION_TYPE_BASE_FORMAT = - 1, // Use NOTIFICATION_TYPE_SIMPLE instead. + 1, // Use `NOTIFICATION_TYPE_SIMPLE` instead. NOTIFICATION_TYPE_IMAGE = 2, NOTIFICATION_TYPE_MULTIPLE = 3, NOTIFICATION_TYPE_PROGRESS = 4, // Notification with progress bar. @@ -25,14 +25,16 @@ enum NotificationPriority { MIN_PRIORITY = -2, LOW_PRIORITY = -1, + // In ChromeOS, if priority < `DEFAULT_PRIORITY`, the notification will be + // silently added to the tray (no pop-up will be shown). DEFAULT_PRIORITY = 0, - // Priorities > |DEFAULT_PRIORITY| have the capability to wake the display up + // Priorities > `DEFAULT_PRIORITY` have the capability to wake the display up // if it was off. HIGH_PRIORITY = 1, MAX_PRIORITY = 2, // Top priority for system-level notifications.. This can't be set from - // kPriorityKey, instead you have to call SetSystemPriority() of + // `kPriorityKey`, instead you have to call `SetSystemPriority()` of // Notification object. SYSTEM_PRIORITY = 3, };
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc index 1a5016b..fd8e632 100644 --- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc +++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -189,11 +189,8 @@ gfx::NativePixmapHandle GbmPixmapWayland::ExportHandle() { gfx::NativePixmapHandle handle; - gfx::BufferFormat format = GetBufferFormat(); - // TODO(dcastagna): Use gbm_bo_get_plane_count once all the formats we use are - // supported by gbm. - const size_t num_planes = gfx::NumberOfPlanesForLinearBufferFormat(format); + const size_t num_planes = gbm_bo_->GetNumPlanes(); std::vector<base::ScopedFD> scoped_fds(num_planes); for (size_t i = 0; i < num_planes; ++i) { scoped_fds[i] = base::ScopedFD(HANDLE_EINTR(dup(GetDmaBufFd(i))));
diff --git a/ui/views/metadata/view_factory.h b/ui/views/metadata/view_factory.h index 466475d3..6c6db5b 100644 --- a/ui/views/metadata/view_factory.h +++ b/ui/views/metadata/view_factory.h
@@ -25,6 +25,7 @@ class BaseViewBuilderT : public internal::ViewBuilderCore { public: using ViewClass_ = typename internal::ViewClassTrait<Builder>::ViewClass_; + using AfterBuildCallback = base::OnceCallback<void(ViewClass_*)>; using ConfigureCallback = base::OnceCallback<void(ViewClass_*)>; BaseViewBuilderT() { view_ = std::make_unique<ViewClass_>(); } explicit BaseViewBuilderT(std::unique_ptr<ViewClass_> view) { @@ -35,6 +36,26 @@ BaseViewBuilderT& operator=(BaseViewBuilderT&&) = default; ~BaseViewBuilderT() override = default; + Builder& AfterBuild(AfterBuildCallback after_build_callback) & { + // Allow multiple after build callbacks by chaining them. + if (after_build_callback_) { + after_build_callback_ = base::BindOnce( + [](AfterBuildCallback previous_callback, + AfterBuildCallback current_callback, ViewClass_* root_view) { + std::move(previous_callback).Run(root_view); + std::move(current_callback).Run(root_view); + }, + std::move(after_build_callback_), std::move(after_build_callback)); + } else { + after_build_callback_ = std::move(after_build_callback); + } + return *static_cast<Builder*>(this); + } + + Builder&& AfterBuild(AfterBuildCallback after_build_callback) && { + return std::move(this->AfterBuild(std::move(after_build_callback))); + } + template <typename ViewPtr> Builder& CopyAddressTo(ViewPtr* view_address) & { *view_address = view_ ? view_.get() : root_view_.get(); @@ -104,6 +125,7 @@ SetProperties(view_.get()); DoCustomConfigure(view_.get()); CreateChildren(view_.get()); + DoAfterBuild(view_.get()); return std::move(view_); } @@ -113,6 +135,7 @@ SetProperties(root_view_); DoCustomConfigure(root_view_); CreateChildren(root_view_); + DoAfterBuild(root_view_); } template <typename T> @@ -188,6 +211,12 @@ return *static_cast<Builder*>(this); } + void DoAfterBuild(ViewClass_* view) { + if (after_build_callback_) { + std::move(after_build_callback_).Run(view); + } + } + void DoCustomConfigure(ViewClass_* view) { if (configure_callback_) std::move(configure_callback_).Run(view); @@ -195,6 +224,12 @@ std::unique_ptr<View> DoBuild() override { return std::move(*this).Build(); } + // Optional callback invoked right after calling `CreateChildren()`. This + // allows additional configuration of the view not easily covered by the + // builder after all addresses have been copied, properties have been set, + // and children have themselves been built and added. + AfterBuildCallback after_build_callback_; + // Optional callback invoked right before calling CreateChildren. This allows // any additional configuration of the view not easily covered by the builder. ConfigureCallback configure_callback_;
diff --git a/ui/views/metadata/view_factory_unittest.cc b/ui/views/metadata/view_factory_unittest.cc index 4ee8dd0..810fa931 100644 --- a/ui/views/metadata/view_factory_unittest.cc +++ b/ui/views/metadata/view_factory_unittest.cc
@@ -8,6 +8,7 @@ #include "base/functional/bind.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/mock_callback.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/accessibility/ax_enums.mojom.h" @@ -238,19 +239,59 @@ EXPECT_EQ(cancel_button, view->children()[1]); } -TEST_F(ViewFactoryTest, TestCustomConfigureChaining) { - int callback_count = 0; - std::unique_ptr<views::View> view = - views::Builder<views::View>() - .CustomConfigure( - base::BindOnce([](int* callback_count, - views::View* view) { ++(*callback_count); }, - &callback_count)) - .CustomConfigure( - base::BindOnce([](int* callback_count, - views::View* view) { ++(*callback_count); }, - &callback_count)) - .Build(); - // Make sure both callbacks have been called. - EXPECT_EQ(callback_count, 2); +TEST_F(ViewFactoryTest, TestOrderOfOperations) { + using ViewCallback = base::OnceCallback<void(views::View*)>; + + views::View* view = nullptr; + base::MockCallback<ViewCallback> custom_configure_callback; + base::MockCallback<ViewCallback> after_build_callback; + + EXPECT_CALL(custom_configure_callback, Run).Times(0); + EXPECT_CALL(after_build_callback, Run).Times(0); + + views::Builder<views::View> builder; + builder.CopyAddressTo(&view) + .SetID(1) + .AddChild(views::Builder<views::View>()) + .CustomConfigure(custom_configure_callback.Get()) + .CustomConfigure(custom_configure_callback.Get()) + .AfterBuild(after_build_callback.Get()) + .AfterBuild(after_build_callback.Get()); + + // Addresses should be copied *before* build but properties shouldn't be set, + // children shouldn't be added, and callbacks shouldn't be run until *after*. + ASSERT_NE(view, nullptr); + EXPECT_EQ(view->GetID(), 0); + EXPECT_EQ(view->children().size(), 0u); + testing::Mock::VerifyAndClearExpectations(&custom_configure_callback); + testing::Mock::VerifyAndClearExpectations(&after_build_callback); + + { + testing::InSequence sequence; + + // Expect that two custom configure callbacks will be run *before* any + // after build callbacks. The order of the custom configure callbacks is + // not guaranteed by the builder. + EXPECT_CALL(custom_configure_callback, Run(testing::Pointer(view))) + .Times(2) + .WillRepeatedly(testing::Invoke([](views::View* view) { + // Properties should be set *before* but children shouldn't be added + // until *after* custom callbacks are run. + EXPECT_EQ(view->GetID(), 1); + EXPECT_EQ(view->children().size(), 0u); + })); + + // Expect that two after build callbacks will be run *after* any custom + // configure callbacks. The order of the after build callbacks is not + // guaranteed by the builder. + EXPECT_CALL(after_build_callback, Run(testing::Pointer(view))) + .Times(2) + .WillRepeatedly(testing::Invoke([](views::View* view) { + // Children should be added *before* after build callbacks are run. + EXPECT_EQ(view->children().size(), 1u); + })); + } + + // Build the view and verify order of operations. + std::ignore = std::move(builder).Build(); }
diff --git a/ui/webui/resources/cr_components/most_visited/most_visited.ts b/ui/webui/resources/cr_components/most_visited/most_visited.ts index 85504d2..5f3bd0e 100644 --- a/ui/webui/resources/cr_components/most_visited/most_visited.ts +++ b/ui/webui/resources/cr_components/most_visited/most_visited.ts
@@ -32,12 +32,6 @@ import {MostVisitedInfo, MostVisitedPageCallbackRouter, MostVisitedPageHandlerRemote, MostVisitedTheme, MostVisitedTile} from './most_visited.mojom-webui.js'; import {MostVisitedWindowProxy} from './window_proxy.js'; -enum ScreenWidth { - NARROW = 0, - MEDIUM = 1, - WIDE = 2, -} - function resetTilePosition(tile: HTMLElement) { tile.style.position = ''; tile.style.left = ''; @@ -98,6 +92,16 @@ theme: Object, /** + * If true, renders MV tiles in a single row up to 10 columns wide. + * If false, renders MV tiles in up to 2 rows up to 5 columns wide. + */ + singleRow: { + type: Boolean, + value: false, + observer: 'onSingleRowChange_', + }, + + /** * When the tile icon background is dark, the icon color is white for * contrast. This can be used to determine the color of the tile hover as * well. @@ -119,12 +123,13 @@ columnCount_: { type: Number, - computed: `computeColumnCount_(tiles_, screenWidth_, maxTiles_)`, + computed: + `computeColumnCount_(singleRow, tiles_, maxVisibleColumnCount_, maxTiles_)`, }, rowCount_: { type: Number, - computed: 'computeRowCount_(columnCount_, tiles_)', + computed: 'computeRowCount_(singleRow, columnCount_, tiles_)', }, customLinksEnabled_: { @@ -198,7 +203,7 @@ showToastButtons_: Boolean, - screenWidth_: Number, + maxVisibleColumnCount_: Number, tiles_: Array, @@ -211,7 +216,8 @@ }; } - private theme: MostVisitedTheme|null; + public theme: MostVisitedTheme|null; + public singleRow: boolean; private useWhiteTileIcon_: boolean; private useTitlePill_: boolean; private columnCount_: number; @@ -230,7 +236,7 @@ private maxVisibleTiles_: number; private showAdd_: boolean; private showToastButtons_: boolean; - private screenWidth_: ScreenWidth; + private maxVisibleColumnCount_: number; private tiles_: MostVisitedTile[]; private toastContent_: string; private visible_: boolean; @@ -244,10 +250,8 @@ private dragOffset_: {x: number, y: number}|null; private tileRects_: DOMRect[] = []; private isRtl_: boolean; + private mediaEventTracker_: EventTracker; private eventTracker_: EventTracker; - private boundOnWidthChange_: () => void; - private mediaListenerWideWidth_: MediaQueryList; - private mediaListenerMediumWidth_: MediaQueryList; private boundOnDocumentKeyDown_: (e: KeyboardEvent) => void; private get tileElements_() { @@ -273,13 +277,17 @@ * of the tile being dragged. */ this.dragOffset_ = null; + + this.mediaEventTracker_ = new EventTracker(); + this.eventTracker_ = new EventTracker(); } override connectedCallback() { super.connectedCallback(); this.isRtl_ = window.getComputedStyle(this)['direction'] === 'rtl'; - this.eventTracker_ = new EventTracker(); + + this.onSingleRowChange_(); this.setMostVisitedInfoListenerId_ = this.callbackRouter_.setMostVisitedInfo.addListener( @@ -305,25 +313,15 @@ override disconnectedCallback() { super.disconnectedCallback(); - assert(this.boundOnWidthChange_); - this.mediaListenerWideWidth_.removeListener(this.boundOnWidthChange_); - this.mediaListenerMediumWidth_.removeListener(this.boundOnWidthChange_); + this.mediaEventTracker_.removeAll(); + this.eventTracker_.removeAll(); this.ownerDocument.removeEventListener( 'keydown', this.boundOnDocumentKeyDown_); - this.eventTracker_.removeAll(); } override ready() { super.ready(); - this.boundOnWidthChange_ = this.updateScreenWidth_.bind(this); - this.mediaListenerWideWidth_ = - this.windowProxy_.matchMedia('(min-width: 672px)'); - this.mediaListenerWideWidth_.addListener(this.boundOnWidthChange_); - this.mediaListenerMediumWidth_ = - this.windowProxy_.matchMedia('(min-width: 560px)'); - this.mediaListenerMediumWidth_.addListener(this.boundOnWidthChange_); - this.updateScreenWidth_(); this.boundOnDocumentKeyDown_ = e => this.onDocumentKeyDown_(e); this.ownerDocument.addEventListener( 'keydown', this.boundOnDocumentKeyDown_); @@ -343,20 +341,15 @@ } private computeColumnCount_(): number { - let maxColumns = 3; - if (this.screenWidth_ === ScreenWidth.WIDE) { - maxColumns = 5; - } else if (this.screenWidth_ === ScreenWidth.MEDIUM) { - maxColumns = 4; - } - const shortcutCount = this.tiles_ ? this.tiles_.length : 0; const canShowAdd = this.maxTiles_ > shortcutCount; const tileCount = Math.min(this.maxTiles_, shortcutCount + (canShowAdd ? 1 : 0)); - const columnCount = tileCount <= maxColumns ? + const columnCount = tileCount <= this.maxVisibleColumnCount_ ? tileCount : - Math.min(maxColumns, Math.ceil(tileCount / 2)); + Math.min( + this.maxVisibleColumnCount_, + Math.ceil(tileCount / (this.singleRow ? 1 : 2))); return columnCount || 3; } @@ -365,6 +358,10 @@ return 0; } + if (this.singleRow) { + return 1; + } + const shortcutCount = this.tiles_ ? this.tiles_.length : 0; return this.columnCount_ <= shortcutCount ? 2 : 1; } @@ -569,6 +566,27 @@ return index >= this.maxVisibleTiles_; } + private onSingleRowChange_() { + if (!this.isConnected) { + return; + } + this.mediaEventTracker_.removeAll(); + const queryLists: MediaQueryList[] = []; + const updateCount = () => { + const index = queryLists.findIndex(listener => listener.matches); + this.maxVisibleColumnCount_ = + 3 + (index > -1 ? queryLists.length - index : 0); + }; + const maxColumnCount = this.singleRow ? 10 : 5; + for (let i = maxColumnCount; i >= 4; i--) { + const query = `(min-width: ${112 * (i + 1)}px)`; + const queryList = this.windowProxy_.matchMedia(query); + this.mediaEventTracker_.add(queryList, 'change', updateCount); + queryLists.push(queryList); + } + updateCount(); + } + private onAdd_() { this.dialogTitle_ = loadTimeData.getString('addLinkTitle'); this.dialogTileTitle_ = ''; @@ -822,16 +840,6 @@ this.tileFocus_(index); } - private updateScreenWidth_() { - if (this.mediaListenerWideWidth_.matches) { - this.screenWidth_ = ScreenWidth.WIDE; - } else if (this.mediaListenerMediumWidth_.matches) { - this.screenWidth_ = ScreenWidth.MEDIUM; - } else { - this.screenWidth_ = ScreenWidth.NARROW; - } - } - private onTilesRendered_() { performance.measure('most-visited-rendered'); assert(this.maxVisibleTiles_);
diff --git a/weblayer/browser/ad_tagging_browsertest.cc b/weblayer/browser/ad_tagging_browsertest.cc index ed989ca..8fd3325 100644 --- a/weblayer/browser/ad_tagging_browsertest.cc +++ b/weblayer/browser/ad_tagging_browsertest.cc
@@ -40,7 +40,7 @@ }; IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, - DISABLED_AdContentSettingAllowed_AdTaggingDisabled) { + AdContentSettingAllowed_AdTaggingDisabled) { HostContentSettingsMapFactory::GetForBrowserContext( web_contents()->GetBrowserContext()) ->SetDefaultContentSetting(ContentSettingsType::ADS,
diff --git a/weblayer/browser/background_sync/background_sync_browsertest.cc b/weblayer/browser/background_sync/background_sync_browsertest.cc index 3ca48fd..64196e43 100644 --- a/weblayer/browser/background_sync/background_sync_browsertest.cc +++ b/weblayer/browser/background_sync/background_sync_browsertest.cc
@@ -188,7 +188,7 @@ EXPECT_FALSE(controller->IsOriginTracked(origin)); } -IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, DISABLED_NormalProfile) { +IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, NormalProfile) { // TODO(crbug.com/1087486, 1091211): Make this use // BackgroundSyncController::ScheduleBrowserWakeup() once we support waking // the browser up. @@ -212,7 +212,7 @@ }; IN_PROC_BROWSER_TEST_F(IncognitoBackgroundSyncBrowserTest, - OffTheRecordProfile) { + DISABLED_OffTheRecordProfile) { base::ScopedAllowBlockingForTesting allow_blocking; // TODO(crbug.com/1087486, 1091211): Make this use
diff --git a/weblayer/browser/clipboard_browsertest.cc b/weblayer/browser/clipboard_browsertest.cc index fd24326..c55450e 100644 --- a/weblayer/browser/clipboard_browsertest.cc +++ b/weblayer/browser/clipboard_browsertest.cc
@@ -71,7 +71,7 @@ std::unique_ptr<content::ScopedPageFocusOverride> scoped_focus_; }; -IN_PROC_BROWSER_TEST_F(ClipboardBrowserTest, DISABLED_ReadTextSuccess) { +IN_PROC_BROWSER_TEST_F(ClipboardBrowserTest, ReadTextSuccess) { prompt_factory()->set_response_type( permissions::PermissionRequestManager::ACCEPT_ALL); ExecuteScriptWithUserGesture(shell()->tab(), "tryClipboardReadText()"); @@ -91,8 +91,7 @@ EXPECT_EQ(0, prompt_factory()->TotalRequestCount()); } -IN_PROC_BROWSER_TEST_F(ClipboardBrowserTest, - DISABLED_ReadTextWithoutPermission) { +IN_PROC_BROWSER_TEST_F(ClipboardBrowserTest, ReadTextWithoutPermission) { prompt_factory()->set_response_type( permissions::PermissionRequestManager::DENY_ALL); ExecuteScriptWithUserGesture(shell()->tab(), "tryClipboardReadText()");
diff --git a/weblayer/browser/download_browsertest.cc b/weblayer/browser/download_browsertest.cc index e708236..669eaf26 100644 --- a/weblayer/browser/download_browsertest.cc +++ b/weblayer/browser/download_browsertest.cc
@@ -197,7 +197,7 @@ EXPECT_EQ(download_dropped_count(), 1); } -IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, DISABLED_Basic) { +IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, Basic) { GURL url(embedded_test_server()->GetURL("/content-disposition.html")); shell()->tab()->GetNavigationController()->Navigate(url); @@ -231,13 +231,7 @@ download_location().DirName()); } -// Test consistently failing on android: crbug.com/1273105 -#if BUILDFLAG(IS_ANDROID) -#define MAYBE_OverrideDownloadDirectory DISABLED_OverrideDownloadDirectory -#else -#define MAYBE_OverrideDownloadDirectory OverrideDownloadDirectory -#endif -IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, MAYBE_OverrideDownloadDirectory) { +IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, OverrideDownloadDirectory) { base::ScopedAllowBlockingForTesting allow_blocking; base::ScopedTempDir download_dir; ASSERT_TRUE(download_dir.CreateUniqueTempDir()); @@ -287,7 +281,7 @@ EXPECT_EQ(download_state(), DownloadError::kCancelled); } -IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, DISABLED_PauseResume) { +IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, PauseResume) { // Add an initial navigation to avoid the tab being deleted if the first // navigation is a download, since we use the tab for convenience in the // lambda. @@ -322,7 +316,7 @@ EXPECT_EQ(download_dropped_count(), 0); } -IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, DISABLED_NetworkError) { +IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, NetworkError) { set_failed_callback(base::BindLambdaForTesting([](Download* download) { CHECK_EQ(download->GetState(), DownloadState::kFailed); }));
diff --git a/weblayer/browser/favicon/favicon_fetcher_browsertest.cc b/weblayer/browser/favicon/favicon_fetcher_browsertest.cc index ce031c0..3e60674 100644 --- a/weblayer/browser/favicon/favicon_fetcher_browsertest.cc +++ b/weblayer/browser/favicon/favicon_fetcher_browsertest.cc
@@ -84,8 +84,7 @@ EXPECT_EQ(2, fetcher_delegate.on_favicon_changed_call_count()); } -IN_PROC_BROWSER_TEST_F(FaviconFetcherBrowserTest, - DISABLED_NavigateToPageWithNoFavicon) { +IN_PROC_BROWSER_TEST_F(FaviconFetcherBrowserTest, NavigateToPageWithNoFavicon) { ASSERT_TRUE(embedded_test_server()->Start()); TestFaviconFetcherDelegate fetcher_delegate; auto fetcher = shell()->tab()->CreateFaviconFetcher(&fetcher_delegate);
diff --git a/weblayer/browser/navigation_browsertest.cc b/weblayer/browser/navigation_browsertest.cc index 2f32bdb..e3d50d1 100644 --- a/weblayer/browser/navigation_browsertest.cc +++ b/weblayer/browser/navigation_browsertest.cc
@@ -944,8 +944,7 @@ // This test verifies the embedder can replace the X-Client-Data header that // is also set by //components/variations. -IN_PROC_BROWSER_TEST_F(NavigationBrowserTest2, - DISABLED_ReplaceXClientDataHeader) { +IN_PROC_BROWSER_TEST_F(NavigationBrowserTest2, ReplaceXClientDataHeader) { std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>(); std::string last_header_value; auto main_task_runner = base::SequencedTaskRunner::GetCurrentDefault();
diff --git a/weblayer/browser/no_state_prefetch/no_state_prefetch_browsertest.cc b/weblayer/browser/no_state_prefetch/no_state_prefetch_browsertest.cc index cc9cdbb..81f91b7 100644 --- a/weblayer/browser/no_state_prefetch/no_state_prefetch_browsertest.cc +++ b/weblayer/browser/no_state_prefetch/no_state_prefetch_browsertest.cc
@@ -131,14 +131,22 @@ // Test that adding a link-rel prerender tag causes a fetch. IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, - DISABLED_LinkRelPrerenderPageFetched) { + LinkRelPrerenderPageFetched) { NavigateAndWaitForCompletion(GURL(https_server_->GetURL("/parent_page.html")), shell()); prerendered_page_fetched_->Run(); } +// Test that only render blocking resources are loaded during NoStatePrefetch. +// TODO(https://crbug.com/1144282): Fix failures on Asan. +#if defined(ADDRESS_SANITIZER) +#define MAYBE_NSPLoadsRenderBlockingResource \ + DISABLED_NSPLoadsRenderBlockingResource +#else +#define MAYBE_NSPLoadsRenderBlockingResource NSPLoadsRenderBlockingResource +#endif IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, - DISABLED_NSPLoadsRenderBlockingResource) { + MAYBE_NSPLoadsRenderBlockingResource) { NavigateAndWaitForCompletion(GURL(https_server_->GetURL("/parent_page.html")), shell()); script_resource_fetched_->Run(); @@ -146,8 +154,16 @@ EXPECT_FALSE(script_executed_); } +// Test that navigating to a no-state-prefetched page executes JS and reuses +// prerendered resources. +// TODO(https://crbug.com/1144282): Fix failures on Asan. +#if defined(ADDRESS_SANITIZER) +#define MAYBE_NavigateToPrerenderedPage DISABLED_NavigateToPrerenderedPage +#else +#define MAYBE_NavigateToPrerenderedPage NavigateToPrerenderedPage +#endif IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, - DISABLED_NavigateToPrerenderedPage) { + MAYBE_NavigateToPrerenderedPage) { NavigateAndWaitForCompletion(GURL(https_server_->GetURL("/parent_page.html")), shell()); script_resource_fetched_->Run(); @@ -189,7 +205,7 @@ // link-rel="prerender" happens even when NoStatePrefetch has been disabled. IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, - DISABLED_LinkRelPrerenderWithNSPDisabled) { + LinkRelPrerenderWithNSPDisabled) { GetProfile()->SetBooleanSetting(SettingType::NETWORK_PREDICTION_ENABLED, false); NavigateAndWaitForCompletion(GURL(https_server_->GetURL("/parent_page.html")), @@ -211,7 +227,7 @@ #if defined(ADDRESS_SANITIZER) #define MAYBE_ExternalPrerender DISABLED_ExternalPrerender #else -#define MAYBE_ExternalPrerender DISABLED_ExternalPrerender +#define MAYBE_ExternalPrerender ExternalPrerender #endif IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, MAYBE_ExternalPrerender) { GetProfile()->GetPrerenderController()->Prerender(
diff --git a/weblayer/browser/popup_blocker_browsertest.cc b/weblayer/browser/popup_blocker_browsertest.cc index 62efe451..56db082 100644 --- a/weblayer/browser/popup_blocker_browsertest.cc +++ b/weblayer/browser/popup_blocker_browsertest.cc
@@ -32,10 +32,7 @@ void SetUpOnMainThread() override { ASSERT_TRUE(embedded_test_server()->Start()); original_tab_ = shell()->tab(); -#if !BUILDFLAG(IS_ANDROID) - // Android does this in Java. original_tab_->SetNewTabDelegate(this); -#endif shell()->browser()->AddObserver(this); NavigateAndWaitForCompletion(embedded_test_server()->GetURL("/echo"), @@ -130,19 +127,18 @@ raw_ptr<Tab> new_tab_ = nullptr; }; -IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, DISABLED_BlocksPopup) { +IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, BlocksPopup) { ExecuteScript(original_tab(), "window.open('https://google.com')", true); EXPECT_EQ(GetBlockedPopupCount(), 1u); } -IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, DISABLED_BlocksMultiplePopups) { +IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, BlocksMultiplePopups) { ExecuteScript(original_tab(), "window.open('https://google.com')", true); ExecuteScript(original_tab(), "window.open('https://google.com')", true); EXPECT_EQ(GetBlockedPopupCount(), 2u); } -IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, - DISABLED_DoesNotBlockUserGesture) { +IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, DoesNotBlockUserGesture) { GURL popup_url = embedded_test_server()->GetURL("/echo?popup"); ExecuteScriptWithUserGesture( original_tab(), @@ -153,7 +149,7 @@ EXPECT_EQ(GetBlockedPopupCount(), 0u); } -IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, DISABLED_OpensBlockedPopup) { +IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, OpensBlockedPopup) { GURL popup_url = embedded_test_server()->GetURL("/echo?popup"); ExecuteScript( original_tab(), @@ -171,7 +167,7 @@ } IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, - DISABLED_AllowsPopupThroughContentSettingException) { + AllowsPopupThroughContentSettingException) { GURL popup_url = embedded_test_server()->GetURL("/echo?popup"); HostContentSettingsMapFactory::GetForBrowserContext( GetWebContents(original_tab())->GetBrowserContext()) @@ -187,7 +183,7 @@ } IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, - DISABLED_AllowsPopupThroughContentSettingDefaultValue) { + AllowsPopupThroughContentSettingDefaultValue) { GURL popup_url = embedded_test_server()->GetURL("/echo?popup"); HostContentSettingsMapFactory::GetForBrowserContext( GetWebContents(original_tab())->GetBrowserContext()) @@ -202,7 +198,7 @@ } IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, - DISABLED_BlockPopupThroughContentSettingException) { + BlockPopupThroughContentSettingException) { GURL popup_url = embedded_test_server()->GetURL("/echo?popup"); HostContentSettingsMapFactory::GetForBrowserContext( GetWebContents(original_tab())->GetBrowserContext()) @@ -220,7 +216,7 @@ } IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest, - DISABLED_BlocksAndOpensPopupFromOpenURL) { + BlocksAndOpensPopupFromOpenURL) { GURL popup_url = embedded_test_server()->GetURL("/echo?popup"); content::OpenURLParams params(popup_url, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
diff --git a/weblayer/browser/profile_browsertest.cc b/weblayer/browser/profile_browsertest.cc index 08e6dfc1..091f53f 100644 --- a/weblayer/browser/profile_browsertest.cc +++ b/weblayer/browser/profile_browsertest.cc
@@ -47,8 +47,7 @@ #endif // !BUILDFLAG(IS_ANDROID) -IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, - DISABLED_GetCachedFaviconForPageUrl) { +IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, GetCachedFaviconForPageUrl) { // Navigation to a page with a favicon. ASSERT_TRUE(embedded_test_server()->Start()); TestFaviconFetcherDelegate fetcher_delegate; @@ -76,8 +75,7 @@ run_loop.Run(); } -IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, - DISABLED_ClearBrowsingDataDeletesFavicons) { +IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, ClearBrowsingDataDeletesFavicons) { // Navigate to a page with a favicon. ASSERT_TRUE(embedded_test_server()->Start()); TestFaviconFetcherDelegate fetcher_delegate;
diff --git a/weblayer/browser/reduce_accept_language_service_browsertest.cc b/weblayer/browser/reduce_accept_language_service_browsertest.cc index 0891cc5..83fe91b 100644 --- a/weblayer/browser/reduce_accept_language_service_browsertest.cc +++ b/weblayer/browser/reduce_accept_language_service_browsertest.cc
@@ -57,8 +57,7 @@ std::unique_ptr<ReduceAcceptLanguageServiceTester> service_tester_; }; -IN_PROC_BROWSER_TEST_F(ReduceAcceptLanguageServiceTest, - DISABLED_GetAcceptLanguageList) { +IN_PROC_BROWSER_TEST_F(ReduceAcceptLanguageServiceTest, GetAcceptLanguageList) { tester()->VerifyFetchAcceptLanguageList({"en", "ja", "it"}); reduce_accept_language::ReduceAcceptLanguageService incognito_service( settings_map(), prefs(), true);
diff --git a/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc b/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc index 3abd90e4..f92d624d 100644 --- a/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc +++ b/weblayer/browser/safe_browsing/safe_browsing_browsertest.cc
@@ -320,18 +320,15 @@ NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_SAFE, false); } -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, - DISABLED_ShowsInterstitial_Malware) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, ShowsInterstitial_Malware) { NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_URL_MALWARE, true); } -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, - DISABLED_ShowsInterstitial_Phishing) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, ShowsInterstitial_Phishing) { NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_URL_PHISHING, true); } -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, - DISABLED_CheckNavigationErrorType) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, CheckNavigationErrorType) { auto threat_types = { safe_browsing::SB_THREAT_TYPE_URL_PHISHING, safe_browsing::SB_THREAT_TYPE_URL_MALWARE, @@ -352,18 +349,16 @@ // Tests below are disabled due to failures on Android. // See crbug.com/1340200. -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, - DISABLED_ShowsInterstitial_Unwanted) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, ShowsInterstitial_Unwanted) { NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_URL_UNWANTED, true); } -IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, - DISABLED_ShowsInterstitial_Billing) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, ShowsInterstitial_Billing) { NavigateWithThreatType(safe_browsing::SB_THREAT_TYPE_BILLING, true); } IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, - DISABLED_ShowsInterstitial_Malware_Subresource) { + ShowsInterstitial_Malware_Subresource) { NavigateWithSubResourceAndThreatType( safe_browsing::SB_THREAT_TYPE_URL_MALWARE, true); } @@ -439,7 +434,7 @@ } IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, - DISABLED_NoAccessTokenFetchInBasicSafeBrowsing) { + NoAccessTokenFetchInBasicSafeBrowsing) { SetSafeBrowsingEnabled(true); GURL a_url(embedded_test_server()->GetURL("a.com", "/simple_page.html")); @@ -448,9 +443,8 @@ EXPECT_FALSE(access_token_fetch_delegate()->has_received_request()); } -IN_PROC_BROWSER_TEST_F( - SafeBrowsingBrowserTest, - DISABLED_NoAccessTokenFetchInRealTimeUrlLookupsUnlessEnabled) { +IN_PROC_BROWSER_TEST_F(SafeBrowsingBrowserTest, + NoAccessTokenFetchInRealTimeUrlLookupsUnlessEnabled) { SetRealTimeURLLookupsEnabled(true); GURL a_url(embedded_test_server()->GetURL("a.com", "/simple_page.html")); @@ -476,7 +470,7 @@ // completes due to Safe Browsing's timing out the access token fetch. IN_PROC_BROWSER_TEST_F( SafeBrowsingBrowserTest, - DISABLED_UnfulfilledAccessTokenFetchTimesOutAndNavigationCompletes) { + UnfulfilledAccessTokenFetchTimesOutAndNavigationCompletes) { SetRealTimeURLLookupsEnabled(true); EnableSafeBrowsingAccessTokenFetches(); access_token_fetch_delegate()->set_should_respond_to_request(false);
diff --git a/weblayer/browser/safe_browsing/weblayer_ping_manager_factory_browsertest.cc b/weblayer/browser/safe_browsing/weblayer_ping_manager_factory_browsertest.cc index 2ac6dd1b..b3f3b58 100644 --- a/weblayer/browser/safe_browsing/weblayer_ping_manager_factory_browsertest.cc +++ b/weblayer/browser/safe_browsing/weblayer_ping_manager_factory_browsertest.cc
@@ -56,8 +56,7 @@ expect_should_fetch); } -IN_PROC_BROWSER_TEST_F(WeblayerPingManagerFactoryTest, - DISABLED_ReportThreatDetails) { +IN_PROC_BROWSER_TEST_F(WeblayerPingManagerFactoryTest, ReportThreatDetails) { auto* ping_manager = WebLayerPingManagerFactory::GetForBrowserContext( GetProfile()->GetBrowserContext()); @@ -87,26 +86,25 @@ ReportThreatDetailsResult::SUCCESS); } IN_PROC_BROWSER_TEST_F(IncognitoModeWeblayerPingManagerFactoryTest, - NoPingManagerForIncognito) { + DISABLED_NoPingManagerForIncognito) { EXPECT_EQ(WebLayerPingManagerFactory::GetForBrowserContext( GetProfile()->GetBrowserContext()), nullptr); } IN_PROC_BROWSER_TEST_F(WeblayerPingManagerFactoryTest, - DISABLED_ShouldFetchAccessTokenForReport_Yes) { + ShouldFetchAccessTokenForReport_Yes) { RunShouldFetchAccessTokenForReportTest(/*is_enhanced_protection=*/true, /*is_signed_in=*/true, /*expect_should_fetch=*/true); } -IN_PROC_BROWSER_TEST_F( - WeblayerPingManagerFactoryTest, - DISABLED_ShouldFetchAccessTokenForReport_NotEnhancedProtection) { +IN_PROC_BROWSER_TEST_F(WeblayerPingManagerFactoryTest, + ShouldFetchAccessTokenForReport_NotEnhancedProtection) { RunShouldFetchAccessTokenForReportTest(/*is_enhanced_protection=*/false, /*is_signed_in=*/true, /*expect_should_fetch=*/false); } IN_PROC_BROWSER_TEST_F(WeblayerPingManagerFactoryTest, - DISABLED_ShouldFetchAccessTokenForReport_NotSignedIn) { + ShouldFetchAccessTokenForReport_NotSignedIn) { RunShouldFetchAccessTokenForReportTest(/*is_enhanced_protection=*/true, /*is_signed_in=*/false, /*expect_should_fetch=*/false);
diff --git a/weblayer/browser/site_isolation_browsertest.cc b/weblayer/browser/site_isolation_browsertest.cc index d444a6b..bf4334c 100644 --- a/weblayer/browser/site_isolation_browsertest.cc +++ b/weblayer/browser/site_isolation_browsertest.cc
@@ -109,16 +109,8 @@ base::test::ScopedFeatureList feature_list_; }; -// Failing on Android, see https://crbug.com/1254509. -#if defined(ANDROID) -#define MAYBE_SiteIsIsolatedAfterEnteringPassword \ - DISABLED_SiteIsIsolatedAfterEnteringPassword -#else -#define MAYBE_SiteIsIsolatedAfterEnteringPassword \ - SiteIsIsolatedAfterEnteringPassword -#endif IN_PROC_BROWSER_TEST_F(SiteIsolationBrowserTest, - MAYBE_SiteIsIsolatedAfterEnteringPassword) { + SiteIsIsolatedAfterEnteringPassword) { GURL url = embedded_test_server()->GetURL("sub.foo.com", "/simple_password_form.html"); NavigateAndWaitForCompletion(url, shell()); @@ -218,8 +210,7 @@ } #endif -IN_PROC_BROWSER_TEST_F(SiteIsolationBrowserTest, - DISABLED_IsolatedSiteIsSavedOnlyOnce) { +IN_PROC_BROWSER_TEST_F(SiteIsolationBrowserTest, IsolatedSiteIsSavedOnlyOnce) { GURL saved_url = embedded_test_server()->GetURL("saved.com", "/simple_page.html"); StartIsolatingSite(saved_url); @@ -232,7 +223,7 @@ // Failing on Android, see https://crbug.com/1254509. #if defined(ANDROID) #define MAYBE_ClearSiteDataHeaderDoesNotClearSavedIsolatedSites \ - DISABLED_ClearSiteDataHeaderDoesNotClearSavedIsolatedSites + ClearSiteDataHeaderDoesNotClearSavedIsolatedSites #else #define MAYBE_ClearSiteDataHeaderDoesNotClearSavedIsolatedSites \ ClearSiteDataHeaderDoesNotClearSavedIsolatedSites @@ -262,9 +253,8 @@ UnorderedElementsAre("https://saved.com")); } -IN_PROC_BROWSER_TEST_F( - SiteIsolationBrowserTest, - DISABLED_ExplicitClearBrowsingDataClearsSavedIsolatedSites) { +IN_PROC_BROWSER_TEST_F(SiteIsolationBrowserTest, + ExplicitClearBrowsingDataClearsSavedIsolatedSites) { GURL saved_url = embedded_test_server()->GetURL("saved.com", "/simple_page.html"); StartIsolatingSite(saved_url);
diff --git a/weblayer/browser/ssl_browsertest.cc b/weblayer/browser/ssl_browsertest.cc index d88ef447..31caa04 100644 --- a/weblayer/browser/ssl_browsertest.cc +++ b/weblayer/browser/ssl_browsertest.cc
@@ -21,6 +21,7 @@ #include "weblayer/public/browser_observer.h" #include "weblayer/public/error_page.h" #include "weblayer/public/error_page_delegate.h" +#include "weblayer/public/new_tab_delegate.h" #include "weblayer/public/tab.h" #include "weblayer/shell/browser/shell.h" #include "weblayer/test/interstitial_utils.h" @@ -33,15 +34,13 @@ #if BUILDFLAG(IS_ANDROID) // Waits for a new tab to be created, and then load |url|. -class NewTabWaiter : public BrowserObserver { +class NewTabWaiter : public NewTabDelegate { public: - NewTabWaiter(Browser* browser, const GURL& url) : url_(url) { - observation_.Observe(browser); - } + explicit NewTabWaiter(const GURL& url) : url_(url) {} - void OnTabAdded(Tab* tab) override { + void OnNewTab(Tab* new_tab, NewTabType type) override { navigation_observer_ = std::make_unique<TestNavigationObserver>( - url_, TestNavigationObserver::NavigationEvent::kStart, tab); + url_, TestNavigationObserver::NavigationEvent::kStart, new_tab); run_loop_.Quit(); } @@ -55,7 +54,6 @@ GURL url_; std::unique_ptr<TestNavigationObserver> navigation_observer_; base::RunLoop run_loop_; - base::ScopedObservation<Browser, BrowserObserver> observation_{this}; }; #endif @@ -228,9 +226,9 @@ // Note: The embedded test server cannot actually load the captive portal // login URL, so simply detect the start of the navigation to the page. - NewTabWaiter waiter(shell()->browser(), - WebLayerSecurityBlockingPageFactory:: + NewTabWaiter waiter(WebLayerSecurityBlockingPageFactory:: GetCaptivePortalLoginPageUrlForTesting()); + shell()->tab()->SetNewTabDelegate(&waiter); ExecuteScript(shell(), "window.certificateErrorPageController.openLogin();", false /*use_separate_isolate*/); waiter.Wait(); @@ -353,8 +351,7 @@ #if BUILDFLAG(IS_ANDROID) // Tests that after reaching a captive portal interstitial, clicking on the // connect link will cause a navigation to the login page. -IN_PROC_BROWSER_TEST_F(SSLBrowserTest, - DISABLED_CaptivePortalConnectToLoginPage) { +IN_PROC_BROWSER_TEST_F(SSLBrowserTest, CaptivePortalConnectToLoginPage) { SSLErrorHandler::SetOSReportsCaptivePortalForTesting(true); NavigateToPageWithMismatchedCertExpectCaptivePortalInterstitial();
diff --git a/weblayer/browser/subresource_filter_browsertest.cc b/weblayer/browser/subresource_filter_browsertest.cc index d2cf240f..b8dce79 100644 --- a/weblayer/browser/subresource_filter_browsertest.cc +++ b/weblayer/browser/subresource_filter_browsertest.cc
@@ -279,7 +279,7 @@ } IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, - DISABLED_ContentSettingsAllowlistGlobal_DoNotActivate) { + ContentSettingsAllowlistGlobal_DoNotActivate) { auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents(); GURL test_url(embedded_test_server()->GetURL(
diff --git a/weblayer/browser/translate_browsertest.cc b/weblayer/browser/translate_browsertest.cc index 51f1875..f140445 100644 --- a/weblayer/browser/translate_browsertest.cc +++ b/weblayer/browser/translate_browsertest.cc
@@ -3,8 +3,12 @@ // found in the LICENSE file. #include "build/build_config.h" +#include "components/infobars/android/infobar_android.h" // nogncheck +#include "components/infobars/content/content_infobar_manager.h" +#include "components/infobars/core/infobar_manager.h" // nogncheck #include "components/translate/content/browser/translate_waiter.h" #include "components/translate/core/browser/language_state.h" +#include "components/translate/core/browser/translate_download_manager.h" #include "components/translate/core/browser/translate_error_details.h" #include "components/translate/core/browser/translate_manager.h" #include "components/translate/core/common/language_detection_details.h" @@ -17,22 +21,15 @@ #include "weblayer/browser/profile_impl.h" #include "weblayer/browser/tab_impl.h" #include "weblayer/browser/translate_client_impl.h" +#include "weblayer/browser/translate_compact_infobar.h" #include "weblayer/public/navigation_controller.h" #include "weblayer/public/tab.h" +#include "weblayer/shell/android/browsertests_apk/translate_test_bridge.h" #include "weblayer/shell/browser/shell.h" #include "weblayer/test/test_navigation_observer.h" #include "weblayer/test/weblayer_browser_test.h" #include "weblayer/test/weblayer_browser_test_utils.h" -#if BUILDFLAG(IS_ANDROID) -#include "components/infobars/android/infobar_android.h" // nogncheck -#include "components/infobars/content/content_infobar_manager.h" -#include "components/infobars/core/infobar_manager.h" // nogncheck -#include "components/translate/core/browser/translate_download_manager.h" -#include "weblayer/browser/translate_compact_infobar.h" -#include "weblayer/shell/android/browsertests_apk/translate_test_bridge.h" -#endif - namespace weblayer { namespace { @@ -103,7 +100,6 @@ } // namespace -#if BUILDFLAG(IS_ANDROID) class TestInfoBarManagerObserver : public infobars::InfoBarManager::Observer { public: TestInfoBarManagerObserver() = default; @@ -130,7 +126,6 @@ base::OnceClosure on_infobar_added_callback_; base::OnceClosure on_infobar_removed_callback_; }; -#endif // if BUILDFLAG(IS_ANDROID) class TranslateBrowserTest : public WebLayerBrowserTest { public: @@ -298,7 +293,7 @@ // Test that the translation infrastructure is set up properly when the user is // in incognito mode. IN_PROC_BROWSER_TEST_F(IncognitoTranslateBrowserTest, - PageTranslationSuccess_IncognitoMode) { + DISABLED_PageTranslationSuccess_IncognitoMode) { ASSERT_TRUE(GetProfile()->GetBrowserContext()->IsOffTheRecord()); SetTranslateScript(kTestValidScript); @@ -326,7 +321,7 @@ } // Test if there was an error during translation. -IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, DISABLED_PageTranslationError) { +IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, PageTranslationError) { SetTranslateScript(kTestValidScript); TranslateClientImpl* translate_client = GetTranslateClient(shell()); @@ -356,7 +351,7 @@ // Test if there was an error during translate library initialization. IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, - DISABLED_PageTranslationInitializationError) { + PageTranslationInitializationError) { SetTranslateScript(kTestScriptInitializationError); TranslateClientImpl* translate_client = GetTranslateClient(shell()); @@ -383,8 +378,7 @@ } // Test the checks translate lib never gets ready and throws timeout. -IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, - DISABLED_PageTranslationTimeoutError) { +IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, PageTranslationTimeoutError) { SetTranslateScript(kTestScriptTimeout); TranslateClientImpl* translate_client = GetTranslateClient(shell()); @@ -411,7 +405,7 @@ } // Test that autotranslation kicks in if configured via prefs. -IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, DISABLED_Autotranslation) { +IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, Autotranslation) { SetTranslateScript(kTestValidScript); TranslateClientImpl* translate_client = GetTranslateClient(shell()); @@ -436,7 +430,6 @@ EXPECT_EQ("zh-CN", translate_client->GetLanguageState().current_language()); } -#if BUILDFLAG(IS_ANDROID) // Test that the translation infobar is presented when visiting a page with a // translation opportunity and removed when navigating away. IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, TranslateInfoBarPresentation) { @@ -481,9 +474,7 @@ EXPECT_EQ(0u, infobar_manager->infobar_count()); infobar_manager->RemoveObserver(&infobar_observer); } -#endif -#if BUILDFLAG(IS_ANDROID) // Test that the translation infobar is not presented when visiting a page with // a translation opportunity but where the page has specified that it should not // be translated. @@ -511,9 +502,7 @@ // were to be shown, this check would fail. EXPECT_EQ(0u, infobar_manager->infobar_count()); } -#endif -#if BUILDFLAG(IS_ANDROID) // Test that the translation can be successfully initiated via infobar. IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, TranslationViaInfoBar) { auto* web_contents = static_cast<TabImpl*>(shell()->tab())->web_contents(); @@ -575,9 +564,7 @@ infobar_manager->RemoveObserver(&infobar_observer); } -#endif -#if BUILDFLAG(IS_ANDROID) // Test that translation occurs when a target language is set. IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, TranslationViaPredefinedTargetLanguage) { @@ -618,9 +605,7 @@ infobar_manager->RemoveObserver(&infobar_observer); } -#endif -#if BUILDFLAG(IS_ANDROID) // Test that the infobar appears on pages in the user's locale iff a target // language is set. IN_PROC_BROWSER_TEST_F( @@ -662,9 +647,7 @@ infobar_manager->RemoveObserver(&infobar_observer); } -#endif -#if BUILDFLAG(IS_ANDROID) // Test that when a predefined target language is set, the infobar does not // appear on pages in that language. IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, @@ -705,9 +688,7 @@ infobar_manager->RemoveObserver(&infobar_observer); } -#endif -#if BUILDFLAG(IS_ANDROID) // Test that the translation infobar stays present when the "never translate // language" item is clicked. Note that this behavior is intentionally different // from that of Chrome, where the infobar is removed in this case and a snackbar @@ -779,7 +760,6 @@ infobar_manager->RemoveObserver(&infobar_observer); } -#if BUILDFLAG(IS_ANDROID) // Test that the infobar shows when a predefined target language is set even if // the source language is in the "never translate" set. IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, @@ -832,7 +812,6 @@ infobar_manager->RemoveObserver(&infobar_observer); } -#endif // Test that the translation infobar stays present when the "never translate // site" item is clicked. Note that this behavior is intentionally different @@ -896,12 +875,10 @@ infobar_manager->RemoveObserver(&infobar_observer); } -#if BUILDFLAG(IS_ANDROID) -// Test that the infobar shows when a predefined target language is set even if -// the site is in the "never translate" set. -IN_PROC_BROWSER_TEST_F( - TranslateBrowserTest, - DISABLED_PredefinedTargetLanguageOverridesSiteBlocklist) { +// Test that the infobar does not show when a predefined target language is set +// and the user selects to never translate the site. +IN_PROC_BROWSER_TEST_F(TranslateBrowserTest, + PredefinedTargetLanguageDoesNotOverrideSiteBlocklist) { auto* tab = static_cast<TabImpl*>(shell()->tab()); auto* web_contents = tab->web_contents(); auto* infobar_manager = @@ -933,37 +910,19 @@ TranslateTestBridge::ClickOverflowMenuItem( infobar, TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_SITE); - // Since a predefined target language is set, the infobar should still be - // shown on new navigations to this site even though the site is blocklisted. ResetLanguageDeterminationWaiter(); - base::RunLoop run_loop2; - infobar_observer.set_on_infobar_added_callback(run_loop2.QuitClosure()); - NavigateAndWaitForCompletion( GURL(embedded_test_server()->GetURL("/french_page2.html")), shell()); language_determination_waiter_->Wait(); EXPECT_EQ("fr", translate_client->GetLanguageState().source_language()); - run_loop2.Run(); - - EXPECT_EQ(1u, infobar_manager->infobar_count()); - - ResetLanguageDeterminationWaiter(); - base::RunLoop run_loop3; - infobar_observer.set_on_infobar_added_callback(run_loop3.QuitClosure()); - - NavigateAndWaitForCompletion( - GURL(embedded_test_server()->GetURL("/german_page.html")), shell()); - language_determination_waiter_->Wait(); - EXPECT_EQ("de", translate_client->GetLanguageState().source_language()); - - run_loop3.Run(); - - EXPECT_EQ(1u, infobar_manager->infobar_count()); + // NOTE: There is no notification to wait for for the event of the infobar not + // showing. However, in practice the infobar is added synchronously, so if it + // were to be shown, this check would fail. + EXPECT_EQ(0u, infobar_manager->infobar_count()); infobar_manager->RemoveObserver(&infobar_observer); } -#endif // Parameterized to run tests on the "never translate language" and "never // translate site" menu items. @@ -1052,6 +1011,4 @@ TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_LANGUAGE, TranslateTestBridge::OverflowMenuItemId::NEVER_TRANSLATE_SITE)); -#endif // BUILDFLAG(IS_ANDROID) - } // namespace weblayer
diff --git a/weblayer/browser/weblayer_variations_http_browsertest.cc b/weblayer/browser/weblayer_variations_http_browsertest.cc index 825de23..0940f6c 100644 --- a/weblayer/browser/weblayer_variations_http_browsertest.cc +++ b/weblayer/browser/weblayer_variations_http_browsertest.cc
@@ -145,7 +145,7 @@ // Verify in an integration test that the variations header (X-Client-Data) is // attached to network requests to Google but stripped on redirects. IN_PROC_BROWSER_TEST_F(WebLayerVariationsHttpBrowserTest, - DISABLED_TestStrippingHeadersFromResourceRequest) { + TestStrippingHeadersFromResourceRequest) { OneShotNavigationObserver observer(shell()); shell()->tab()->GetNavigationController()->Navigate(GetGoogleRedirectUrl1()); observer.WaitForNavigation();
diff --git a/weblayer/public/javatestutil/org/chromium/weblayer/TestWebLayer.java b/weblayer/public/javatestutil/org/chromium/weblayer/TestWebLayer.java index 31b6f7b..ece082db 100644 --- a/weblayer/public/javatestutil/org/chromium/weblayer/TestWebLayer.java +++ b/weblayer/public/javatestutil/org/chromium/weblayer/TestWebLayer.java
@@ -141,13 +141,13 @@ WebLayer.loadAsync(application, webLayer -> { Bundle args = new Bundle(); args.putString(BrowserFragmentArgs.PROFILE_NAME, "browsertest"); - args.putBoolean(BrowserFragmentArgs.IS_INCOGNITO, true); + args.putBoolean(BrowserFragmentArgs.IS_INCOGNITO, false); Browser browser = new Browser(webLayer.createBrowser(application, args)); - browser.initializeState(); WebFragmentEventHandler eventHandler = new WebFragmentEventHandler(browser.connectFragment()); + browser.initializeState(); eventHandler.onAttach(application, null); eventHandler.onCreate(); eventHandler.onStart();
diff --git a/weblayer/shell/android/browsertests_apk/AndroidManifest.xml b/weblayer/shell/android/browsertests_apk/AndroidManifest.xml index 30f0b23..6ca4a95 100644 --- a/weblayer/shell/android/browsertests_apk/AndroidManifest.xml +++ b/weblayer/shell/android/browsertests_apk/AndroidManifest.xml
@@ -12,6 +12,7 @@ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
diff --git a/weblayer/shell/android/support_apk/AndroidManifest.xml b/weblayer/shell/android/support_apk/AndroidManifest.xml index bebb20c..bd4d5ad3 100644 --- a/weblayer/shell/android/support_apk/AndroidManifest.xml +++ b/weblayer/shell/android/support_apk/AndroidManifest.xml
@@ -21,6 +21,7 @@ <uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <application android:label="WebLayer support"> <!-- AR (Augmented Reality) support. -->